Lambda是一个匿名函数,我们可以把Lambda表达式理解为一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码、作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升。
**操作符“->”**称为箭头操作符或Lambda操作符,夹头操作符将Lambda表达式拆分成两部分:
左侧:Lambda表达式的参数列表。右侧:Lambda表达式所需执行的功能,即Lambda体。语法格式一:无参数,无返回值。 () -> System.out.println(“Hello Lambda!”);
@Test public void test1(){ //匿名内部类 Runnable r = new Runnable() { @Override public void run() { System.out.println("Hello World!"); } }; r.run(); System.out.println("=================="); //使用Lambda表达式 Runnable r1 = () -> System.out.println("Hello Lambda"); r1.run(); /** * 打印结果 * Hello World! * ================== * Hello Lambda */ }语法格式二:有一个参数,并且无返回值。 (x) -> System.out.println(x); 如只有一个参数,小括号可以省略不写。 x -> System.out.println(x);
@Test public void test2(){ Consumer<String> con = (x) -> System.out.println(x); con.accept("Hello Lambda!"); /** * 将Hello Lambda!传递到(x)中,然后打印X * 打印结果 * Hello Lambda! */ } }语法格式三:有两个以上的参数,有返回值,并且Lambda体有多条语句。 Comparator com = (x,y) -> { System.out.println(“函数式接口”); return Integer.compare(x,y); };
@Test public void test3(){ Comparator<Integer> com = (x,y) -> { System.out.println("函数式接口"); return Integer.compare(x,y); }; Integer max = com.compare(77,7); System.out.println(max); /** * 打印结果 * 函数式接口 * 1 * * 2个数相等差就是0,大于用1表示,小于用-1表示 */ }语法格式四:若Lambda体重只有一条语句,return 和大括号都可以省略不写。 Comparator com = (x,y) -> Integer.compare(x,y);
@Test public void test4(){ Comparator<Integer> com = (x,y) -> Integer.compare(x,y); Integer result = com.compare(44,4); System.out.println(result); /** * 打印结果 * 1 */ }语法格式五:Lambda表达式的参数列表的数据类型可以省略不写,因为JVM编译器同上下文推断出数据类型,即“类型推断”。 Comparator com = (Integer x , Integer y) -> Integer.compare(x,y) 等价于 Comparator com = (x , y) -> Integer.compare(x,y)
**函数式接口:**接口中只有一个抽象方法的接口,称为函数式接口。可以使用注解 @FunctionalInterface 修饰,可以检查是否是函数式接口。
例如:对一个数进行运算
/** * 定义函数式接口 */ @FunctionalInterface public interface MyFun { public Integer getValue(Integer num); } @Test public void test6(){ Integer num = operation(100, (x) -> x * x); System.out.println(num); System.out.println("================"); Integer count = operation(100, (x) -> x + 500); System.out.println(count); /** * 打印结果 * 10000 * ================ * 600 */ } public Integer operation(Integer num, MyFun mf){ return mf.getValue(num); } }练习一: 调用Conllections.sort()方法,通过定制排序比较两个Employee(先按年龄比,年龄相同按姓名比),使用Lambda作为参数传递。 实体类
public class Employee { public Employee(){} public Employee(String name, int age, double salary) { this.name = name; this.age = age; this.salary = salary; } private String name; private int age; private double salary; //get 和set。。。。 //toString方法测试类
public class TestLambda { List<Employee> employees = Arrays.asList( new Employee("张三",22,6333.333), new Employee("李四",33,8444.444), new Employee("王五",64,3555.555), new Employee("陈六",45,6666.666), new Employee("田七",33,4500.666) ); @Test public void test1(){ Collections.sort(employees,(emp1,emp2) -> { if (emp1.getAge() == emp2.getAge()){ return emp1.getName().compareTo(emp2.getName()); }else { return Integer.compare(emp1.getAge(),emp2.getAge()); } }); for (Employee employee : employees) { System.out.println(employee); } /** * 打印结果 * Employee{name='张三', age=22, salary=6333.333} * Employee{name='李四', age=33, salary=8444.444} * Employee{name='田七', age=33, salary=4500.666} * Employee{name='陈六', age=45, salary=6666.666} * Employee{name='王五', age=64, salary=3555.555} */ } }练习二:
声明函数式接口,接口中声明抽象方法,public String getValue(String str);声明类TestLambda,类中编写方法使用接口作为参数,将一个字符串转换成大写,并作为方法的返回值;再将一个字符串的第2个和第4个索引位置进行截取子串。函数式接口
@FunctionalInterface public interface MyFunction { public String getValue(String str); }测试类
public class TestLambda { @Test public void test(){ String trimStr = strHandle("\t\t 哈哈哈哈哈", (str) -> str.trim()); System.out.println(trimStr); String upper = strHandle("Hello World!", (str) -> str.toUpperCase()); System.out.println(upper); String newStr = strHandle("Hello World!", (str) -> str.substring(6, 11)); System.out.println(newStr); /** * 打印结果 * 哈哈哈哈哈 * HELLO WORLD! * World */ } //用于处理字符串 public String strHandle(String str,MyFunction mf){ return mf.getValue(str); } }练习三:
声明一个带两个泛型的函数式接口,泛型类型是<T,R> T 为参数,R为返回值;接口中声明对应抽象方法;在TestLambda类中声明方法,使用接口作为参数,计算两个long 型参数的和;再计算两个long型参数的乘积。函数式接口
@FunctionalInterface public interface MyFunction1<T,R> { public R getValue(T t1,T t2); }测试类
public class TestLambda1 { @Test public void test1(){ op(100L,200L,(l1,l2) -> l1+l2); op(100L,200L,(l1,l2) ->l1 * l2); /** * 打印结果 * 300 * 20000 */ } //对两个Long型数据进行处理 public void op(Long l1,Long l2,MyFunction1<Long,Long> mf){ System.out.println(mf.getValue(l1,l2)); } }若Lambda体重的内容有方法已经实现了,我们可以使用“方法引用”(可以理解为方法引用是Lambda表达式的另外一种表现形式)。 主要有三种语法格式:
对象::实例方法名类::静态方法名类::实例方法名注意:
Lambda体中调用方法的参数列表与返回值类型,要与函数式接口中抽象方法的函数列表和返回值类型保存一致。若Lambda参数列表中的第一参数是实例方法的调用者,而第二参数是实例方法的参数时,可以使用ClassName::method。 public class TestMethodRef { //对象::实例方法名 @Test public void test1(){ PrintStream ps = System.out; Consumer<String> con =(x) -> ps.println(x); //等价于 PrintStream ps1 = System.out; Consumer<String> con1 = ps1::println; //等价于 Consumer<String> con2 = System.out::println; con.accept("hello world!"); /** * 打印结果 * hello world! */ } @Test public void test2(){ Employee emp = new Employee(); Supplier<String> sup = () -> emp.getName(); String str = sup.get(); System.out.println(str); //等价于 Supplier<String> sup1 = emp::getName; String str1 = sup1.get(); System.out.println(str1); } //类::静态方法名 @Test public void test3(){ Comparator<Integer> com = (x,y) -> Integer.compare(x,y); //等价于 Comparator<Integer> com1 = Integer::compare; int result = com1.compare(11,55); System.out.println(result); /** * 打印结果 * -1 */ } //类::实例方法名 @Test public void test4(){} BiPredicate<String,String> bp = (x,y) -> x.equals(y); //等价于 BiPredicate<String,String> bp1 = String::equals; }格式:ClassName::new 注意: 需要调用的构造器的参数列表要与函数式接口中抽象方法的参数列表保持一致!
public class TestConstructorRef { //构造器引用 @Test public void test() { Supplier<Employee> sup = () -> new Employee(); //构造器引用方式 Supplier<Employee> sup2 = Employee::new; Employee emp = sup2.get(); System.out.println(emp); /** * 打印结果 * Employee{name='null', age=0, salary=0.0} */ } @Test public void test1(){ Function<Integer,Employee> fun = (x) -> new Employee(x); //等价于 Function<Integer,Employee> fun1 = Employee::new; Employee emp = fun1.apply(111); System.out.println(emp); /** * 在Employee类中添加构造器 * public Employee(int age) { * this.age = age; * } * 打印结果 * Employee{name='null', age=111, salary=0.0} */ } }格式:Type[]::new
public class TestArrayRef { //数组引用 @Test public void test(){ Function<Integer,String[]> fun = (x) -> new String[x]; //等价于 Function<Integer,String[]> fun1 = String[]::new; String[] strs = fun1.apply(5); System.out.println(strs.length); /** * 打印结果 * 5 */ } }