什么是Lambda表达式
这里首先要提到一个概念:函数式接口
- Java中只有一个抽象方法的接口,用来表示lambda表达式的类型,JAVA8中新增了许多函数式接口。比如断言接口Predicate,表示函数的Function等。
简单的说,如果你接触过C++,C#之类的编程语言,也许会听说过函数式编程、函数引用之类的概念,他们与lambda表达式功能类似,通俗的说就是,现在你可以更简单的在JAVA中把方法当做一个参数传递给另一个方法,或者可以不用再写那么复杂的匿名内部类(可读性差,稍复杂)去实现一些必要的接口。
有这样一个例子我觉得很好,
现在有一个List<Integer> numbers
,我们要达到三种结果,获得所有integer的和,获得集合中所有偶数的和,获得所有奇数的和。
- 没有lambda时,你可能最先想到的就是写三个如下方法
public int sumAllSth (List<Integer> numbers){
int total = 0;
for(int n:numbers){
if(//这个数是奇数或偶数){
total += number;
}
}
return total;
}
但是当你需要再次加入一个获取所有质数的和时,你就要找到这个类,再次添加方法了。这样明显有大量的代码冗余,也不利于维护。
- 当然你也可以使用设计模式——策略模式来完成这个任务
public int sumAllSth (List<Integer> numbers){
int total = 0;
for(int n:numbers){
if(strategy.test(number)){//返回true或false
total += number;
}
}
return total;
}
多余的代码不写了… 策略模式可以在影响主程序段环境(Context)的情况下,通过多个实现了抽象策略(Strategy)的抽象策略类(ConcreteStrategy),是的这些策略可以被替换。但是代码量也变大了。
- Lambda表示式
public int sumAll(List<Integer> numbers, Predicate<Integer> p) {
int total = 0;
for (int number : numbers) {
if (p.test(number)) {
total += number;
}
}
return total;
}
//part 1:
System.out.println( sumAll(numbers, n -> n % 2 == 0) );
//part 2:
System.out.println( sumAll(numbers, new Predicate<Integer>() {
@Override
public boolean test(Integer integer) {
return integer%2==0;
}
}));
对于part1部分,就是我们的lambda表达式,暂时忽略那些横线箭头,表达式能达到的作用就是part2部分。
正如part2,当你准备使用类似Predicate的函数式接口,有一个test方法用来断言,返回是true或者false,当需要灵活变动if()中的条件时,Predecate可以经过test()多次传递达到可变条件的效果。也就是要实现一个匿名内部类时,6行代码里的核心其实只有return integer%2=0
这一段,而lambda表达式在这里就简练很多,并且性能也会提升。
- Lambda表达式语法:
(params) -> expression
(params) -> statement
(params) -> { statements }
主要包括
- 圆括号中的参数
- ->
- 花括号中的表达式
基本规则
- 参数与表达式可为0,也可有多个多行
- 当参数/表达式为1时,可以省略圆括号/花括号
- 参数类型可以指定,可以省略(省略时编译器会根据上下文去判断)
- 当表达式只有一条时,返回值就是表达式的返回值
再介绍一个使用场景:下面是JAVA8中对于迭代器interface Iterator新增的的函数式接口:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
下面就出现了比起for(:)更加简便的写法,说起来,其实他们都是java的语法糖:
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7);
//lambda
numbers.forEach( value -> System.out.print(value) );
//方法引用
numbers.forEach(System.out::print);