什么是 Lambda表达式?
对于 Java 中的 lambda 表达式,我们可以把它简单的理解为一个函数。
比如,我们需要这样一个函数,它需要把两个数字相加,将结果返回 则可以这样定义
1 | int add(int a, int b); |
但是我们知道,Java中函数是没有办法单独定义存在的,所以我们需要一个接口才能声明这个函数功能
1 | interface Function { |
当我们需要实现这个方法的时候,一种方法就是定义一个新的类来实现这个接口
1 | class Calc implements Function { |
除此之外,还有一种方法就是使用匿名类
1 | Function addFunc = new Function() { |
而在 Java8 中,我们又有了一种更简单的写法,这也就是lambda表达式
1 | Function addFunc1 = (a, b) -> a + b; |
当然,既然是为了表达一个函数所创建的接口,所以定义的接口中就必须只能有一个方法。对于这类接口,它还有一个特殊的名字: 函数式接口,我们可以在对应的接口上面添加@FunctionalInterface
注解来表明它的身份。
如何使用?
上一节我们可以知道,lambda就是函数式接口的实现,所以要想使用lambda表示式,我们必须先定义一个函数式接口,这样任何需要函数式接口的地方,我们都可以传递lambda表达式进去。我们也可以自己定义方法,接受lambda表达式参数
JDK中已经定义了很多常用的函数式接口,比如Comparator
接口
1 |
|
这样我们在排序的时候,接受 Comparator接口的地方就可以传递lambda表达式了,非常方便
1 | List<String> list = ...; |
基本常用的函数式接口,JDK已经都帮我们内置好了,不需要自己定义,大致有以下几类
常用函数式接口
Predicate
谓词 - 用来对数据进行判断,返回true或false
1 |
|
Function
用于转换数据,将前一个参数的类型转为后面的类型
1 |
|
Supplier
生产者,用来生产数据,无参数,返回一个对象
1 |
|
Consumer
消费者,就是用来消费数据,接受一个数据,无返回值
1 |
|
Lambda表达式复合使用
函数式接口的功能都比较单一,有时候无法满足我们的需求,这时候就需要将多个lambda表达式组合到一起使用来完成功能
比较器复合
1 | // 对于用户类,有两个比较器 |
上面只是为了方便理解,实际比较时,可以使用 Comparator.comparing()
方法
如按照年龄排序: Comparator<User> newAgeComparator = Comparator.comparing(User::getAge);
谓词复合
谓词接口有三个方法,negate
, and
,or
来分别表示 非、与、或
1 | // 获取年龄大于18岁的用户 |
注意:如果and
和or
在一起使用,则会按照书写顺序来定优先级
函数复合
Function
接口提供了两个方法andThen
和compose
用来组合函数
andThen用在执行完当然函数,将结果用户参数中的下一个函数
而 compose顺序则相反,是执行完参数中的函数,将结果用于当前调用函数
1 | Function<Integer, Integer> f = x -> x + 1; |
附:Java8其他
流的扁平化-flatMap
flatMap方法让你把一个流中的每个值都换成另一个流,然后把所有的流连接起来成为一个流
1 | // 获取所有的各不相同的字符 |
1 | // 生成所有数对,如:[(1,3), (1,3), (1,4), (2,3), (2,4), (3,3), (3,4)] |
查找和匹配
这里需要额外注意,在集合(流)为空的时候,allMatch和noneMatch会返回true, 但是anyMatch会返回false
至少一个匹配
boolean b = words.stream().anyMatch("hello"::equals);
匹配全部元素
1 | boolean b1 = words.stream().allMatch("hello"::equals); |
查找元素
1 | Optional<String> h1 = words.stream().filter("hello"::equals).findAny(); |
收集器接口
1 | /** |
具体例子可参考
Collectors.toList
实现
参考资料:《Java8 实战》