# 前言 **能够使用Lambda的依据是必须有相应的函数接口**(函数接口,是指内部只有一个抽象方法的接口)。 这一点跟Java是强类型语言吻合,_也就是说你并不能在代码的任何地方任性的写Lambda表达式_。实际上Lambda的类型就是对应函数接口的类型。Lambda表达式另一个**依据是类型推断机制(重点)**,在上下文信息足够的情况下,**编译器可以推断出参数表的类型,而不需要显式指名**。 读者福利:[Java核心学习笔记](https://mp.weixin.qq.com/s/AgJ9iymCiM63a9E20mlA6Q)+2021最新[大厂面试真题](https://mp.weixin.qq.com/s/VZ7wormwowlSPnA_XAnZaw)共享! # 一、演化过程 ## A.基础类的准备 ```javascript package com.os.model; import java.util.Objects; public class Employee { private int id; private String name; private int age; private double salary; //省略生成的getteer和setter方法,构造方法、toString方法、hashCode、equals方法 } 复制代码 ``` ## B.筛选数据 我们根据不同的筛选条件需要设置不同的方法,增加了很多的代码量。 ```javascript package com.os.test; import com.os.model.Employee; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Demo01 { private static List
emps = Arrays.asList( new Employee(101, "悟空", 18, 9999.99), new Employee(102, "八戒", 59, 6666.66), new Employee(103, "唐僧", 28, 3333.33), new Employee(104, "沙僧", 8, 7777.77), new Employee(105, "白龙马", 38, 5555.55) ); public static void main(String[] args) { System.out.println("===>1.筛选年龄"); List
list = filterEmployeeAge(emps); for (Employee employee : list) { System.out.println(employee); } System.out.println("===>2.筛选工资"); list = filterEmployeeSalary(emps); for (Employee employee : list) { System.out.println(employee); } } /** * 需求:获取公司中年龄小于 35 的员工信息 * @param employeeList * @return */ public static List
filterEmployeeAge(List
employeeList){ List
list = new ArrayList<>(); for (Employee emp : employeeList) { if(emp.getAge() <= 35){ list.add(emp); } } return list; } /** * 需求:获取公司中工资大于 5000 的员工信息 * @param employeeList * @return */ public static List
filterEmployeeSalary(List
employeeList){ List
list = new ArrayList<>(); for (Employee emp : employeeList) { if(emp.getSalary() >= 5000){ list.add(emp); } } return list; } } 复制代码 ``` ## C.代码进化:策略设计模式 ### **(1)定义筛选条件的泛型接口** ```javascript package com.os.service; /** * 针对于数据的筛选条件的接口 */ public interface ObjectDataPredicate
{ boolean test(T t); } 复制代码 ``` ### **(2)实现类去实现不同的筛选方式** 按照年龄进行筛选实现类 ```javascript package com.os.service; import com.os.model.Employee; public class FilterEmployeeForAge implements ObjectDataPredicate
{ @Override public boolean test(Employee employee) { return employee.getAge() <= 35; } } 复制代码 ``` 按照工资进行筛选实现类 ```javascript package com.os.service; import com.os.model.Employee; public class FilterEmployeeForSalary implements ObjectDataPredicate
{ @Override public boolean test(Employee employee) { return employee.getSalary() >= 5000; } } 复制代码 ``` ### **(3)策略模式的实现代码** ```javascript public static List
filterEmployee(List
emps, ObjectDataPredicate
objectDataPredicate){ List
list = new ArrayList<>(); for (Employee employee : emps) { if(objectDataPredicate.test(employee)){ list.add(employee); } } return list; } 复制代码 ``` 完整代码如下 ```javascript package com.os.test; import com.os.model.Employee; import com.os.service.FilterEmployeeForAge; import com.os.service.FilterEmployeeForSalary; import com.os.service.ObjectDataPredicate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Demo02 { private static List
emps = Arrays.asList( new Employee(101, "悟空", 18, 9999.99), new Employee(102, "八戒", 59, 6666.66), new Employee(103, "唐僧", 28, 3333.33), new Employee(104, "沙僧", 8, 7777.77), new Employee(105, "白龙马", 38, 5555.55) ); public static void main(String[] args) { List
list = filterEmployee(emps, new FilterEmployeeForAge());//接口回调 for (Employee employee : list) { System.out.println(employee); } System.out.println("------------------------------------------"); List
list2 = filterEmployee(emps, new FilterEmployeeForSalary());//接口回调 for (Employee employee : list2) { System.out.println(employee); } } public static List
filterEmployee(List
emps, ObjectDataPredicate
objectDataPredicate){ List
list = new ArrayList<>(); for (Employee employee : emps) { if(objectDataPredicate.test(employee)){ list.add(employee); } } return list; } } 复制代码 ``` > 这种代码的实现类太多了 > ## D.代码进化:匿名内部类 ```javascript package com.os.test; import com.os.model.Employee; import com.os.service.FilterEmployeeForAge; import com.os.service.FilterEmployeeForSalary; import com.os.service.ObjectDataPredicate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Demo03 { private static List
emps = Arrays.asList( new Employee(101, "悟空", 18, 9999.99), new Employee(102, "八戒", 59, 6666.66), new Employee(103, "唐僧", 28, 3333.33), new Employee(104, "沙僧", 8, 7777.77), new Employee(105, "白龙马", 38, 5555.55) ); public static void main(String[] args) { List
list = filterEmployee(emps, new ObjectDataPredicate
() { @Override public boolean test(Employee employee) { return employee.getId() <= 103; } });//接口回调 for (Employee employee : list) { System.out.println(employee); } } public static List
filterEmployee(List
emps, ObjectDataPredicate
objectDataPredicate){ List
list = new ArrayList<>(); for (Employee employee : emps) { if(objectDataPredicate.test(employee)){ list.add(employee); } } return list; } } 复制代码 ``` > 通过内部类,我们能发现整个代码中核心的部分就是一句话`employee.getId() <= 103` > ## E.代码进化:Lambda 表达式 ```javascript package com.os.test; import com.os.model.Employee; import com.os.service.ObjectDataPredicate; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Demo04 { private static List
emps = Arrays.asList( new Employee(101, "悟空", 18, 9999.99), new Employee(102, "八戒", 59, 6666.66), new Employee(103, "唐僧", 28, 3333.33), new Employee(104, "沙僧", 8, 7777.77), new Employee(105, "白龙马", 38, 5555.55) ); public static void main(String[] args) { /* List
list = filterEmployee(emps, new ObjectDataPredicate
() { @Override public boolean test(Employee employee) { return employee.getId() <= 103; } });//接口回调 */ List
list = filterEmployee(emps, (e) -> e.getAge() <= 35); for (Employee employee : list) { System.out.println(employee); } System.out.println("------------------------------------------"); List
list2 = filterEmployee(emps, (e) -> e.getSalary() >= 5000); for (Employee employee : list2) { System.out.println(employee); } } public static List
filterEmployee(List
emps, ObjectDataPredicate
objectDataPredicate){ List
list = new ArrayList<>(); for (Employee employee : emps) { if(objectDataPredicate.test(employee)){ list.add(employee); } } return list; } } 复制代码 ``` > Lambda 是一个匿名函数,我们可以把Lambda 表达式理解为是**一段可以传递的代码(将代码像数据一样进行传递)**。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。 > # 二、Lambda基础语法 Lambda 表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为`->`,该操作符被称为Lambda 操作符或剪头操作符。它将Lambda 分为两个部分: - 左侧:指定了Lambda 表达式需要的所有参数(对应接口中形参) - 右侧:指定了Lambda 体,即Lambda 表达式要执行的功能。(方法体,可以推断返回值类型) ## A.格式1:无参数,无返回值 ```javascript package com.os.print.service; @FunctionalInterface//定义接口函数 public interface Printer01 { void print(); } 复制代码 ``` ```javascript package com.os.print.service; public class Demo01 { public static void main(String[] args) { //之前我们可以使用你们实现类 Printer01 out = new Printer01() { @Override public void print() { System.out.println("匿名实现类"); System.out.println("====>"+Math.random()); } }; out.print(); //使用Lambda表达式 out = ()-> System.out.println("方法体只有一行,可以省略大括号"); out.print(); out = ()->{ System.out.println("方法体有很多,需要使用大括号搞定"); System.out.println("====>"+Math.random()); }; out.print(); } } 复制代码 ``` ## B.格式2:有一个参数,无返回值 ```javascript package com.os.print.service; @FunctionalInterface//定义接口函数 public interface Printer02
{ void print(T t); } 复制代码 ``` ```javascript public class Demo02 { public static void main(String[] args) { //通过泛型推断参数e的类型 Printer02
out01 = (e)-> System.out.println(e); out01.print(new Employee(999,"悟空",19,25000)); Printer02
out2 = (e)-> System.out.println(e); out2.print(999); Printer02
out3 = (e)-> System.out.println(e); out3.print("西游记"); } } 复制代码 ``` ## C.格式3:若只有一个参数,小括号可以省略不写 ```javascript package com.os.print.service; import com.os.model.Employee; public class Demo02 { public static void main(String[] args) { //通过泛型推断参数e的类型 Printer02
out01 = e-> System.out.println(e); out01.print(new Employee(999,"悟空",19,25000)); Printer02
out2 = e-> System.out.println(e); out2.print(999); Printer02
out3 = e-> System.out.println(e); out3.print("西游记"); } } 复制代码 ``` ## D.格式4:有两个以上的参数,有返回值,并且 Lambda 体中有多条语句 使用系统有的函数接口测试如下: ```javascript package com.os.print.service; import com.os.model.Employee; import java.util.Comparator; public class Demo03 { public static void main(String[] args) { /* public interface Comparator
{ } * */ Comparator
comparator = (x,y)->{ System.out.println("接口函数方法"); return Integer.compare(x,y); }; } } 复制代码 ``` ### 自定义函数接口方法: ```javascript package com.os.print.service; @FunctionalInterface//定义接口函数 public interface Printer03
{ T print(T t1,T t2); } 复制代码 ``` ```javascript package com.os.print.service; import com.os.model.Employee; import java.util.Comparator; public class Demo03 { public static void main(String[] args) { Printer03
out01 = (s1,s2)->{ String str = s1.concat(s2); return str.toUpperCase(); }; System.out.println(out01.print("abc","efg")); } } 复制代码 ``` ### 自定义函数接口方法两个参数: ```javascript package com.os.print.service; @FunctionalInterface//定义接口函数 public interface Printer04
{ R print(T t1, R t2); } 复制代码 ``` ```javascript package com.os.print.service; import com.os.model.Employee; public class Demo04 { public static void main(String[] args) { Printer04
out = (name,e)->{ e.setName(name); return e; }; Employee employee = out.print("西游记",new Employee()); System.out.println(employee); } } 复制代码 ``` ## E.格式5:若 Lambda 体中只有一条语句, return 和 大括号都可以省略不写 ```javascript package com.os.print.service; import com.os.model.Employee; import java.util.Comparator; public class Demo04 { public static void main(String[] args) { Comparator
comparator = (x, y)->Integer.compare(x,y); System.out.println(comparator.compare(1,2)); Printer04
out = (name,e)->e; Employee employee = out.print("西游记",new Employee()); System.out.println(employee); } } 复制代码 ``` ## F.格式5:Lambda 表达式的参数列表的数据类型可以省略不写,因为JVM编译器通过上下文推断出,数据类型,即“类型推断” ```javascript (Integer x, Integer y) -> Integer.compare(x, y); //一般不会使用这种写法 复制代码 ``` 上述Lambda 表达式中的参数类型都是由编译器推断得出的。Lambda 表达式中无需指定类型,程序依然可以编译,这是因为javac根据程序的上下文,在后台推断出了参数的类型。Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的“类型推断” > lambda语法的总结如下: > - **上联:左右遇一括号省** - **下联:左侧推断类型省** - **横批:能省则省** # 三、函数式接口 - 只包含一个抽象方法的接口,称为函数式接口。 - 你可以通过Lambda 表达式来创建该接口的对象。 - (若Lambda 表达式抛出一个受检异常,那么该异常需要在目标接口的抽象方法上进行声明)。 - 在任意函数式接口上设置`@FunctionalInterface`注解,这样做可以检查它是否是一个函数式接口,同时javadoc也会包含一条声明,说明这个接口是一个函数式接口。 上述的示例中,我们已经定义过函数式接口,但是我们不可能每次都要自己定义函数式接口,太麻烦!所以,Java内置了函数式接口在`java.util.function`包下 ## A.Predicate
断言型接口 ```javascript @FunctionalInterface public interface Predicate
{ boolean test(T t); } 复制代码 ``` ```javascript package com.os.print.service; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Predicate; public class Demo05 { public static void main(String[] args) { List
list = Arrays.asList("Hello", "pangsir", "Lambda", "www", "ok"); List
strList = filterStr(list, (s) -> s.length() > 3); for (String str : strList) { System.out.println(str); } } //需求:将满足条件的字符串,放入集合中 public static List
filterStr(List
list, Predicate
pre){ List
strList = new ArrayList<>(); for (String str : list) { if(pre.test(str)){ strList.add(str); } } return strList; } } 复制代码 ``` ## B.Function
函数型接口 ```javascript @FunctionalInterface public interface Function
{ R apply(T t); } 复制代码 ``` ```javascript package com.os.print.service; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.function.Function; import java.util.function.Predicate; public class Demo06 { public static void main(String[] args) { String newStr = strHandler("\t\t\t 西游记齐天大圣孙悟空 ", (str) -> str.trim()); System.out.println(newStr); String subStr = strHandler("西游记齐天大圣孙悟空", (str) -> str.substring(2, 5)); System.out.println(subStr); } //需求:用于处理字符串 public static String strHandler(String str, Function
fun){ return fun.apply(str); } } 复制代码 ``` ## C.Supplier
供给型接口 ```javascript @FunctionalInterface public interface Supplier
{ T get(); } 复制代码 ``` ```javascript package com.os.print.service; import java.util.ArrayList; import java.util.List; import java.util.function.Supplier; public class Demo07 { public static void main(String[] args) { List
numList = getNumList(10, () -> (int)(Math.random() * 100)); for (Integer num : numList) { System.out.println(num); } } //需求:产生指定个数的整数,并放入集合中 public static List
getNumList(int num, Supplier
sup){ List
list = new ArrayList<>(); for (int i = 0; i < num; i++) { Integer n = sup.get(); list.add(n); } return list; } } 复制代码 ``` ## D.Consumer
消费型接口 ```javascript @FunctionalInterface public interface Consumer
{ void accept(T t); } 复制代码 ``` ```javascript package com.os.print.service; import java.util.function.Consumer; public class Demo08 { public static void main(String[] args) { happy(10000, (m) -> System.out.println("购物消费:" + m + "元")); } public static void happy(double money, Consumer
con){ con.accept(money); } } 复制代码 ``` ### java.util.function包下有很多有用的函数式接口 | 函数式接口 | 参数类型 | 返回类型 | 用途 | |:----|:----|:----|:----| | Consumer
消费型接口 | T | void | 对类型为T的对象应用操作,包含方法:void accept(T t) | | Supplier
供给型接口 | 无 | T | 返回类型为T的对象,包含方法:T get(); | | Function
函数型接口 | T | R | 对类型为T的对象应用操作。结果R类型的对象。方法:R apply(T t); | | Predicate
断定型接口 | T | boolean | 确定类型为T的对象是否满足某约束,boolean 值。含方法boolean test(T t); | | BiFunction
| T,U | R | 对类型为T,U参数应用操作,返回R类型的结果。包含方法为:R apply(T t,U u); | | UnaryOperator
| T | T | 对类型为T的对象进行一元运算,并返回T类型的结果。包含方法为T apply(Tt); | | BinaryOperator
| T,T | T | 对类型为T的对象进行二元运算,并返回T类型的结果。包含方法为T apply(Tt1,Tt2); | | BiConsumer
| T,U | void | 对类型为T,U参数应用操作。包含方法为void accept(T t,U u) | | ToIntFunction
ToLongFunction
ToDoubleFunction
| T | intlongdouble | 分别计算int、long、double、值的函数 | | IntFunction
LongFunction
DoubleFunction
| intlongdouble | R | 参数分别为int、long、double类型的函数 | # 四、方法引用 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用! 方法引用:使用操作符“::” 将方法名和对象或类的名字分隔开来。 - 对象::实例方法 - 类::静态方法 - 类::实例方法 > 注意: > - ①
方法引用所引用的方法的参数列表与返回值类型,需要与函数式接口中抽象方法的参数列表和返回值类型保持一致! 复制代码 - ② 若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName 复制代码 ## A.对象的引用 :: 实例方法名 ```javascript package com.os.print.service; import com.os.model.Employee; import java.util.function.Supplier; public class Demo09 { public static void main(String[] args) { Employee emp = new Employee(101, "张三", 18, 9999.99); Supplier
sup = () -> emp.getName(); System.out.println(sup.get()); System.out.println("----------------------------------"); Supplier
sup2 = emp::getName; System.out.println(sup2.get()); } } 复制代码 ``` ## B.类 :: 静态方法名 ```javascript package com.os.print.service; import java.util.function.BiFunction; import java.util.function.Supplier; public class Demo10 { public static void main(String[] args) { BiFunction
fun = (x, y) -> Math.max(x, y); System.out.println(fun.apply(1.5, 22.2)); System.out.println("--------------------------------------------------"); BiFunction
fun2 = Math::max; System.out.println(fun2.apply(1.2, 1.5)); } } 复制代码 ``` ## C.类 :: 实例方法名 ```javascript package com.os.print.service; import com.os.model.Employee; import java.util.function.BiFunction; import java.util.function.BiPredicate; import java.util.function.Function; public class Demo11 { public static void main(String[] args) { BiPredicate
bp = (x, y) -> x.equals(y); System.out.println(bp.test("abcde", "abcde")); System.out.println("-----------------------------------------"); BiPredicate
bp2 = String::equals; System.out.println(bp2.test("abc", "abc")); System.out.println("-----------------------------------------"); Function
fun = (e) -> e.getName(); System.out.println(fun.apply(new Employee())); System.out.println("-----------------------------------------"); Function
fun2 = Employee::getName; System.out.println(fun2.apply(new Employee())); } } 复制代码 ``` > 若Lambda 的参数列表的第一个参数,是实例方法的调用者,第二个参数(或无参)是实例方法的参数时,格式: ClassName::MethodName > ## D.构造方法引用 ClassName::new 格式:`ClassName::new` 与函数式接口相结合,自动与函数式接口中方法兼容。 可以把构造器引用赋值给定义的方法,与构造器参数列表要与接口中抽象方法的参数列表一致! ```javascript package com.os.print.service; import com.os.model.Employee; import java.util.function.BiFunction; import java.util.function.BiPredicate; import java.util.function.Function; public class Demo12 { public static void main(String[] args) { Function
fun = Employee::new; System.out.println(fun.apply("悟空")); BiFunction
fun2 = Employee::new; System.out.println(fun2.apply("八戒",18)); } } 复制代码 ``` ## E.数组引用 ```javascript package com.os.print.service; import com.os.model.Employee; import java.util.function.BiFunction; import java.util.function.Function; public class Demo13 { public static void main(String[] args) { Function
fun = (e) -> new String[e]; String[] strs = fun.apply(10); System.out.println(strs.length); System.out.println("--------------------------"); Function
fun2 = Employee[] :: new; Employee[] emps = fun2.apply(20); System.out.println(emps.length); } } 关注公众号:麒麟改bug 共享2021金三银四Java面试题总结集锦! ```
微信关注我们
原文链接:https://blog.51cto.com/u_14994509/2899028
转载内容版权归作者及来源网站所有!
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
相关文章
发表评论
资源下载
更多资源优质分享Android(本站安卓app)
近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。
Mario,低调大师唯一一个Java游戏作品
马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。
Java Development Kit(Java开发工具)
JDK是 Java 语言的软件开发工具包,主要用于移动设备、嵌入式设备上的java应用程序。JDK是整个java开发的核心,它包含了JAVA的运行环境(JVM+Java系统类库)和JAVA工具。
Sublime Text 一个代码编辑器
Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。