Java-lambda表达式入门
Lambda表达式,也可称为闭包,是JDK8的新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中),可以使代码变的更加简洁紧凑。Lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。
名字起源是以前还没有计算机时,逻辑学家Alonzo Church想要形式化的表示能有效计算的数学函数,使用了希腊字母lambda( λ \lambda λ)来标记参数,从那以后,带参数变量的表达式就被称为lambda表达式。
lambda表达式本质是一个匿名函数,比如以下函数
1
2
3
|
public int add( int x, int y) { return x + y; } |
可以转换为:
1
|
( int x, int y) -> x + y; |
语法
语法格式如下
1
2
3
|
(parameters) -> expression 或 (parameters) ->{ statements; } |
其中()用来描述参数列表,{}用来描述方法体,->是lambda运算符,读作goes to。
可以包含显示的return语句,如:
1
2
3
4
5
6
|
(String sirst,String second)-> { if (first.length()<second.length()) return - 1 ; else if (first.length()>second.length()) return 1 ; else return 0 ; } |
可以没有参数,但()不可缺省:
()->{for(int i=0;i<10;i++)System.out.print(i);}
如果可以推导出参数类型,则可以忽略其类型:
Comparator<String>cmp=(first,second)->first.length()-second.length();
特别注意不能只在某些分支返回一个值,这是不合法的,如:
(int x)->{if(x>=0)return 1;}
常用示例:
1
2
3
4
5
6
7
8
9
10
|
ArrayList<Integer>list= new ArrayList<>(); Collections.addAll(list, 1 , 2 , 3 , 4 , 5 ); //遍历 list.forEach(e->{System.out.println(e);}); //删除指定值 list.removeIf(e->e== 3 ); //排序 list.sort((o1,o2)->o2-o1); //遍历(双冒号操作符) list.forEach(System.out::println); |
函数式接口
Java中又很多封装代码块的接口,如ActionListener
、Comparator
等,lambda表达式与这些接口时兼容的。
对于只有一个抽象方法的接口,需要这种接口的对象时,就可以提供一个lambda表达式,这种接口称为函数式接口。
比如Arrays.sort()
方法,它的第二个参数需要一个Comparator
实例,而Comparator
就是只有一个方法的接口,所以可以使用lambda表达式替代,可以把lambda表达式看作一个函数,而不是一个对象,如:
1
2
|
Arrays.sort(arrays, (first,second)->first.length()-second.length()); |
lambda表达式还可以转换为接口,比如实现Runnable接口:
1
2
3
|
new Thread(() -> System.out.println( "记得一键三连" )).start(); Runnable r = () -> System.out.println( "(。・∀・)ノ" ); r.run(); |
再如之前提到的removeIf()
方法,它的参数就是一个Predicate
接口(位于java.util.function包),这个接口专门用来传递lambda表达式,如删除一个数组列表所有null值:
1
|
list.removeIf(e->e== null ) |
方法引用
当在Lambda表达式中直接调用了一个方法时可以使用,其写法为目标引用::方法名称。
有时候,可能已经有现成的方法可以完成你想要传递到其他代码的某个动作,如遍历打印集合:
1
|
list.forEach(e->{System.out.println(e);}); |
我们可以直接把现成的println方法传递给它:
1
|
list.forEach(System.out::println); |
它们是等价的,是一个方法引用的写法。
再如对字符串排序而不考虑大小写,可以直接传递以下方法表达式:
1
|
Arrays.sort(strings,String::compareToIgnoreCase); |
也就是说使用双冒号操作符::来分离方法名与对象或类名:
- object::instanceMethod
- Class::staticMethod
- Class::instanceMethod
对于前两种情况,方法引用等价于提供方法参数的lambda表达式,如,Math::Pow等价于(x,y)->Math.pos(x,y)。
对于第三种情况,第一个参数会成为方法的目标,如String::compareToIgnoreCase等同于(x,y)->x.compareToIgnoreCase(y)。
也可以在方法中引用this参数,如this::equals等价于x->this.equals(x),同样的,使用super也是允许的。