Lambda 表达式

一、什么 Lambda 表达式

​ Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样传递)。使用它可以写出更简洁、更灵活的代码。

​ Lambda 表达式的本质是函数式接口(只有一个抽象函数的接口)的实例。

二、Lambda 表达式使用

2.1 基本语法

接口<泛型> 对象 = (形参列表)-> {函数体}

形参列表:当只有没有形参时,可以用 () 代替;当只有一个形参时,可以省略 ();当接口中指明了泛型时,可以省略参数类型;

函数体:当函数体中只有一条语句时,大括号可以省略;当函数体中只有一条 return 语句时,return 关键字可以省略。

2.2 代码示例

下面代码,第一个是使用接口的匿名对象来实现 run 方法,第二个是使用 lambda 表达式实现的 run 方法。

public class LambdaTest1 {
    @Test
    public void test() {
        Runnable r1 = new Runnable() {
            @Override
            public void run() {
                System.out.println("使用接口的匿名实现类");
            }
        };

        r1.run();
		
        //
        Runnable r2 = () -> System.out.println("使用 Lambda 表达式");
        r2.run();
    }

}
/**运行结果:
使用接口的匿名实现类
使用 Lambda 表达式

分析:
() -> System.out.println() 与 
Runnable r1 = new Runnable() {
     @Override
     public void run() {
         System.out.println("使用接口的匿名实现类");
     }
};
是等价的,证明了Lambda 表达式的本质是函数式接口(只有一个抽象函数的接口)的实例

示例二:

public void test2() {
    Comparator<Integer> comparator1 = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return Integer.compare(o1, o2);
        }
    };
    System.out.println(comparator1.compare(1, 2));

    //两个参数,多条语句的 lambda 表达式
    Comparator<Integer> comparator2 =  (x, y) -> {
        System.out.printf("x = %d, y = %d \n", x, y);
        return Integer.compare(x, y);
    };
    System.out.println(comparator2.compare(10, 15));
    
    //两个参数,只有一个 return 语句的 lambda 表达式
    Comparator<Integer> comparator3 = (x, y) -> Integer.compare(x, y);
    System.out.println(comparator3.compare(10, 15));
}

三、Java 内置四大核心函数式接口

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZGgFKFL3-1586062710333)(C:\Users\dell\AppData\Roaming\Typora\typora-user-images\image-20200403000200251.png)]

3.1 练习使用 Consumer 接口

public void testConsumer() {
    Consumer<String> consumer1 = new Consumer<String>() {
        @Override
        public void accept(String s) {
            System.out.println(s);
        }
    };
    consumer1.accept("使用匿名实现类");

    Consumer<String> consumer2 = s -> System.out.println(s);
    consumer2.accept("使用 Lambda 表达式");

    Consumer<String> consumer3 = System.out::println;
    consumer3.accept("使用方法引用");
}

3.2 练习使用 Supplier 接口

public void testSupplier() {
    Supplier<String> supplier1 = new Supplier<String>() {
        @Override
        public String get() {
            return "使用匿名实现类";
        }
    };
    System.out.println(supplier1.get());

    Supplier<String> supplier2 = () -> "使用 Lambda 表达式";
    System.out.println(supplier2.get());
}

3.3 练习使用 Function 接口

public void testFunction() {
    Function<String, String> function1 = new Function<String, String>() {
        @Override
        public String apply(String s) {
            return (s + ", 接口匿名实现");
        }

    };
    System.out.println(function1.apply("hello"));

    Function<String, String> function2 = s -> s + ", lambda 表达式";
    System.out.println(function2.apply("hello"));
}

3.4 练习使用 Predicate 接口

public void testPredicate() {
    //接口的匿名实现类
    List<Integer> list = Arrays.asList(10, 5, 4, 3, 10, 20, 30);
    Predicate<Integer> predicate1 = new Predicate<Integer>() {
        @Override
        public boolean test(Integer integer) {
            return integer >= 10;
        }
    };
    List<Integer> res1 = filter(list, predicate1);
    System.out.println(res1);

    //lambda 表达式
    Predicate<Integer> predicate2 = integer -> integer >= 10;
    List<Integer> res2 = filter(list, predicate2);
    System.out.println(res2);

}

private List<Integer> filter(List<Integer> list, Predicate<Integer> predicate) {
    List<Integer> res = new ArrayList<>();

    for (Integer i : list) {
        if (predicate.test(i)) res.add(i);
    }

    return res;
}

四、方法引用

​ 方法引用就是简化了的 lambda 表达式:如果 lambda 表达式中使用的形参数列表和 lambda 方法体中的函数使用的参数一样,那么就可以用方法引用来简化。

​ 方法应用的语法:函数式接口 变量名 = 类名/对象 :: 方法名

例:

public void test1() {
    //接口的匿名实现类
    Comparator<Integer> comparator1 = new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o1.compareTo(o2);
        }
    };
    System.out.println(comparator1.compare(2, 3));

     //lambda 表达式 1
    Comparator<Integer> comparator4 = (o1, o2) -> Integer.compare(o1, o2);	//Integer.compare(o1, o2) 中的 o1, o2 与前面的完全相同,所以可以使用方法引用
    System.out.println(comparator2.compare(2, 4));
    //方法引用 1
    Comparator<Integer> comparator5 = Integer::compareTo;
    System.out.println(comparator5.compare(2, 5));
    
    //lambda 表达式 2
    Comparator<Integer> comparator2 = (o1, o2) -> o1.compareTo(o2);//这样的情形也可以使用方法引用,因为和第一种情形是等价的
    System.out.println(comparator2.compare(2, 4));

    //方法引用 2
    Comparator<Integer> comparator3 = Integer::compareTo;
    System.out.println(comparator3.compare(2, 5));
}

例:不能改写成方法引用的情况

public void test2() {
    Consumer<String> consumer1 = s -> System.out.println(s);    
    consumer1.accept("这种情况可以改写成方法引用");  //因为 accept() 中使用的参数与 println() 中使用的参数完全一致

    Consumer<String> consumer2 = s -> System.out.println("不好意思" + s);
    consumer1.accept("这种情况下就不能改写成方法引用");        //因为 accept 中使用的参数和 println() 中使用的参数不一致
}

五、Lambda 表达式的作用

​ 从上面的几个例子看起来 Lambda 表达式除了在创建线程哪个例子里较为使用,其他的例子并不实用,但我们知道 Lambda 的实际作用是用来充当函数式接口的实例的,只要用得到函数式接口的地方,就能用 Lambda 表达式来简化

例:

public void test3() {
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    //一般的 for-each
    for (Integer integer : list) {
        System.out.println(integer);
    }

    //Lambda 表达式简化
    list.forEach(System.out::println);
}

/** foreach 源码,参数是一个 Consumer 的函数式接口
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }
*/

​ 而且,Lambda 在 Stream API(Java 函数式编程的关键) 中会大量用到,因为 Stream API 中的绝大部分函数都有函数式接口类型的形参。

例:

public void test2(){
    //得到一个 employee 的列表
    List<Employee> employees = EmployeeData.getEmployees();	
    // 使用 stream api 来统计列表中薪资大于 5000 的员工个数,直接用一个 filter 就实现了
    long count = employees.stream().filter(e -> e.getSalary() > 5000).count();
}

/** filter 源码,参数是一个 Predicate 的函数式接口
    Stream<T> filter(Predicate<? super T> predicate);
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值