1、什么时候该用lambda表达式?
Java中所有的参数都以类的形式进行传递,不能直接传递一个代码块,比如,在调用sort方法时,我们需要程序如何比较数组中的元素,因此sort需要提供一个实现了Comparator接口的类,该实现类只需要实现一个compare方法,但如果仅仅只是为了实现一个方法而创建一个全新的类,未免有些臃肿和麻烦,因此,提供了 lambda表达式。
说白了,lambda表达式就是专门为这些只需要实现一个方法的接口(函数式接口,@FunctionalInterface)做简化的,你只需要给出方法中的代码,至于类的名字、如何创建、何时创建,都不需要关心。
综上,当你调用了一个方法,它的参数是一个函数式接口,此时就可以用lambda表达式。
2、lambda的语法
这是最标准的格式,表达式不需要也不能指定返回类型(因为没必要,接口方法已经定义好了,编译器会自己去查):
(int a, int b) -> { System.out.println("a, b"); retrun Math.max(a, b); }
同理,可以省略参数类型:
(a, b) -> { System.out.println("a, b"); retrun Math.max(a, b); }
当接口方法不需要参数时,需要使用(),如果代码块只有一句也可以不写{}:
() -> System.out.println("test");
当且仅当只有一个参数时,可以省略(),如果只有一句return代码,必须省略return,否则需要使用{}:
a -> a+1;
a -> {return a + 1;}
3、stream流
许多集合类都支持流处理,调用Arrays.stream()获取流。stream通常与lambda一起使用。
流处理方法中大多需要传入一个函数式接口,此时可以使用lambda表达式实现。
4、常见的流处理方法
流处理方法可以分为两类:中间处理方法 和 最后处理方法。
中间处理方法:
filter:参数是Predicate接口,接口方法是 boolean test(int/double/... value),传入一个参数(数组中的元素),判断是否过滤该元素,true表示该元素通过。
sorted:老生常谈了,不需要参数,热知识:sort默认从小到大排序,在Comparator中,(a, b) -> {} 如果返回负数表示a比b小(return a-b)。
distinct:去除重复元素,无参。
limit:传入一个long参数,表示保留前几个元素。
skip:传入一个long参数,跳过前几个元素,配合limit实现分页。
map:传入一个UnaryOperator接口,接口方法包含一个T类型参数(与数组元素类型一致),返回值类型也为T,即,在保持元素类型不变的情况下对元素做变换操作。比如(a) -> a*2-1
最后处理方法:
forEach:传入一个Consumer接口,接口方法包含一个T类型参数,返回值void。
toArray:不解释。
min:返回最小元素,类型为OptionalT(可能为empty或T,使用getAsT()返回T类型)
max:返回最大元素。
count:元素个数。
reduce:对所有元素进行求“和”运算,返回OptionalT类型,传入一个BinaryOperator接口,接口方法接收两个T参数,返回T类型,表示两个元素的运算结果。比如reduce( (x,y) -> x*2 + y),此时reduce返回结果为 ((x1*2 + x2)*2 + x3)*2 + ...(但实际运行不会按顺序来)。如果传入T::sum表示所有元素求和。
sum:相当于reduce(T::sum)。
anyMatch:传入一个Predicate接口,如果有任何元素执行test接口方法为true,则该方法返回true。
allMatch:与上面类似。
findFirst:无参,返回第一个元素,类型为OptionalT。
findAny:无参,返回任何一个元素。
collect:比较复杂,参数需要三个接口,主要是将结果存放到容器中,使用例子:collect(Collectors.toList())、collect(Collectors.toSet())、collect(Collectors.toMap)。