跟着官网的教程一起深入学习Lambda表达式:
Using Lambdas Expressions in Your Application - Dev.java
JDK8加了一个新包java.util.function,里面定义了很多函数式接口,主要分为4类:Supplier
Consumer
1.想获取一个新对象使用Supplier
Supplier没有入参,会返回一个对象,而且每次调用都会返回一个新的对象
- @FunctionalInterface
- public interface Supplier
{ -
- T get();
- }
下面是一个简单的Supplier实现如下:
- public static void main(String[] args) {
- Supplier
str = () -> "hello Duke"; - System.out.println(str.get());
- }
再看一个实现示例:
- public static void main(String[] args) {
- Random random = new Random(314L);
- Supplier
supplier = () -> random.nextInt(10); - for (int i = 0; i < 5; i++) {
- System.out.println(supplier.get());
- }
- }
上面的操作会两次装箱和拆箱操作,一个是random.nextInt(10)返回int时会自动装箱为Integer;另一个是调用get后获得随机数后(这里我自己也不是很懂,有人懂的赐教一下),这样的自动装箱拆箱会影响性能。考虑到这个问题,JDK提供了优化的方法供使用。比如提供了专门的IntSupplier
- @FunctionalInterface
- public interface IntSupplier {
-
- int getAsInt();
- }
用IntSupplier修改上面的例子:
- Random random = new Random(314L);
- IntSupplier newRandom = () -> random.nextInt();
-
-
- for (int i = 0; i < 5; i++) {
- int nextRandom = newRandom.getAsInt();
- System.out.println("next random = " + nextRandom);
- }
JDK提供了四个这样的专用Supplier:IntSupplier, BooleanSupplier, LongSupplier, DoubleSupplier.其中的get方法分别为getAsInt(),getAsBoolean(),getAsLong(),getAsDouble()
2.需要使用一个对象用Consumer
Consumer和Supplier相反,它需要入参,但不返回东西,而且它除了抽象方法还有一个default方法
- @FunctionalInterface
- public interface Consumer
{ -
- void accept(T t);
-
- // default methods removed
- }
在Supplier的例子中使用Consumer:
- public static void main(String[] args) {
- Random random = new Random(314L);
- IntSupplier supplier = () -> random.nextInt(10);
- Consumer
consumer = s -> System.out.println(s); -
- for (int i = 0; i < 5; i++) {
- consumer.accept(supplier.getAsInt());
- }
- }
Consumer和Supplier一样,考虑到性能优化,提供了专门的IntConsumer,LongConsumer,DoubleConsumer,因为它们都没有返回值,方法均为accept()。
JDK还提供了一个接收两个参数的BigConsumer
- @FunctionalInterface
- public interface BiConsumer
{ -
- void accept(T t, U u);
-
- // default methods removed
- }
使用BigConsumer重写写获取随机数的例子:
- public static void main(String[] args) {
- BiConsumer
consumer = (r, n) -> { - for (int j = 0; j < n; j++) {
- System.out.println(r.nextInt(10));
- }
- };
-
- consumer.accept(new Random(314L), 5);
- }
BigConsumer也提供了专门的ObjIntConsumer,ObjLongConsumer,ObjDoubleConsumer
3.当需要判断一个对象是否满足某个条件时用Predicate
predicate常常会被用来做过滤
- @FunctionalInterface
- public interface Predicate
{ -
- boolean test(T t);
-
- // default and static methods removed
- }
Predicate的基本类型专用接口有IntPredicate,LongPredicate,DoublePredicate,同时也有支持两个入参的接口BigPredicate
用Predicate对list做过滤:
- public static void main(String[] args) {
- List
list = List.of("one", "two", "three", "four", "five"); - List
strings = new ArrayList<>(list); - Predicate
predicate = s -> s.length()%2==0; -
- strings.removeIf(predicate);
- System.out.println(strings);
- }
输出如下:

注意这里的removeIf()会修改调用列表的内容,所以像List.of()和Arrays.asList()生成的list,调用removeIf()时会运行保存,因为这两种方式生成的列表都是不可变的。
4.从一个类型映射到另一个类型用Function
- @FunctionalInterface
- public interface Function
{ -
- R apply(T t);
-
- // default and static methods removed
- }
例如:
- Function
toLength = s -> s.length(); - String word = ...; // any kind of word will do
- int length = toLength.apply(word);