写在前面
前面积极响应读者的需求, 写了两篇 Java 新特性的文章. 有小伙伴留言说: 感觉 Lambda 表达式很强大啊! 一行代码就能够搞定那么多功能! 我想学习下 Lambda 表达式的语法, 可以吗? 我的回答是: 没问题! 这不, Lambda 表达式来了!
匿名类到 Lambda 表达式
我们先来看看从匿名类如何转换到 Lambda 表达式呢?
这里, 我们可以使用两个示例来说明如何从匿名内部类转换为 Lambda 表达式.
匿名内部类到 Lambda 表达式
使用匿名内部类如下所示.
- Runnable r = new Runnable(){
- @Override
- public void run(){
- System.out.println("Hello Lambda");
- }
- }
转化为 Lambda 表达式如下所示.
Runnable r = () -> System.out.println("Hello Lambda");
匿名内部类作为参数传递到 Lambda 表达式作为参数传递
使用匿名内部类作为参数如下所示.
- TreeSet<Integer> ts = new TreeSet<>(new Comparator<Integer>(){
- @Override
- public int compare(Integer o1, Integer o2){
- return Integer.compare(o1, o2);
- }
- });
使用 Lambda 表达式作为参数如下所示.
- TreeSet<Integer> ts = new TreeSet<>(
- (o1, o2) -> Integer.compare(o1, o2);
- );
从直观上看, Lambda 表达式要比常规的语法简洁的多.
Lambda 表达式的语法
Lambda 表达式在 Java 语言中引入了 "->" 操作符, "->" 操作符被称为 Lambda 表达式的操作符或者箭头操作符, 它将 Lambda 表达式分为两部分:
左侧部分指定了 Lambda 表达式需要的所有参数.
Lambda 表达式本质上是对接口的实现, Lambda 表达式的参数列表本质上对应着接口中方法的参数列表.
右侧部分指定了 Lambda 体, 即 Lambda 表达式要执行的功能.
Lambda 体本质上就是接口方法具体实现的功能.
我们可以将 Lambda 表达式的语法总结如下.
1. 语法格式一: 无参, 无返回值, Lambda 体只有一条语句
Runnable r = () -> System.out.println("Hello Lambda");
具体示例如下所示.
- @Test
- public void test1(){
- Runnable r = () -> System.out.println("Hello Lambda");
- new Thread(r).start();
- }
2. 语法格式二: Lambda 表达式需要一个参数, 并且无返回值
Consumer<String> func = (s) -> System.out.println(s);
具体示例如下所示.
- @Test
- public void test2(){
- Consumer<String> consumer = (x) -> System.out.println(x);
- consumer.accept("Hello Lambda");
- }
3. 语法格式三: Lambda 只需要一个参数时, 参数的小括号可以省略
Consumer<String> func = s -> System.out.println(s);
具体示例如下所示.
- @Test
- public void test3(){
- Consumer<String> consumer = x -> System.out.println(x);
- consumer.accept("Hello Lambda");
- }
4. 语法格式四: Lambda 需要两个参数, 并且有返回值
- BinaryOperator<Integer> bo = (a, b) -> {
- System.out.println("函数式接口");
- return a + b;
- };
具体示例如下所示.
- @Test
- public void test4(){
- Comparator<Integer> comparator = (x, y) -> {
- System.out.println("函数式接口");
- return Integer.compare(x, y);
- };
- }
5. 语法格式五: 当 Lambda 体只有一条语句时, return 和大括号可以省略
BinaryOperator<Integer> bo = (a, b) -> a + b;
具体示例如下所示.
- @Test
- public void test5(){
- Comparator<Integer> comparator = (x, y) -> Integer.compare(x, y);
- }
6. 语法格式六: Lambda 表达式的参数列表的数据类型可以省略不写, 因为 JVM 编译器能够通过上下文推断出数据类型, 这就是 "类型推断"
- BinaryOperator<Integer> bo = (Integer a, Integer b) -> {
- return a + b;
- };
等同于
- BinaryOperator<Integer> bo = (a, b) -> {
- return a + b;
- };
上述 Lambda 表达式中的参数类型都是由编译器推断得出的. Lambda 表达式中无需指定类型, 程序依然可以编译, 这是因为 javac 根据程序的上下文, 在后台推断出了参数的类型. Lambda 表达式的类型依赖于上下文环境, 是由编译器推断出来的. 这就是所谓的 "类型推断".
函数式接口
Lambda 表达式需要函数式接口的支持, 所以, 我们有必要来说说什么是函数式接口.
只包含一个抽象方法的接口, 称为函数式接口.
可以通过 Lambda 表达式来创建该接口的对象.(若 Lambda 表达式抛出一个受检异常, 那么该异常需要在目标接口的抽象方法上进行声明).
可以在任意函数式接口上使用 @FunctionalInterface 注解, 这样做可以检查它是否是一个函数式接口, 同时 javadoc 也会包含一条声明, 说明这个接口是一个函数式接口.
我们可以自定义函数式接口, 并使用 Lambda 表达式来实现相应的功能.
例如, 使用函数式接口和 Lambda 表达式实现对字符串的处理功能.
首先, 我们定义一个函数式接口 MyFunc, 如下所示.
- @FunctionalInterface
- public interface MyFunc <T> {
- public T getValue(T t);
- }
接下来, 我们定义一个操作字符串的方法, 其中参数为 MyFunc 接口实例和需要转换的字符串.
- public String handlerString(MyFunc<String> myFunc, String str){
- return myFunc.getValue(str);
- }
接下来, 我们对自定义的函数式接口进行测试, 此时我们传递的函数式接口的参数为 Lambda 表达式, 并且将字符串转化为大写.
- @Test
- public void test6(){
- String str = handlerString((s) -> s.toUpperCase(), "binghe");
- System.out.println(str);
- }
运行 test6 方法, 得出的结果信息如下所示.
BINGHE
我们也可以截取字符串的某一部分, 如下所示.
- @Test
- public void test7(){
- String str = handlerString((s) -> s.substring(0,4), "binghe");
- System.out.println(str);
- }
运行 test7 方法, 得出的结果信息如下所示.
bing
可以看到, 我们可以通过 handlerString(MyFunc<String> myFunc, String str) 方法结合 Lambda 表达式对字符串进行任意操作.
注意: 作为参数传递 Lambda 表达式: 为了将 Lambda 表达式作为参数传递, 接收 Lambda 表达式的参数类型必须是与该 Lambda 表达式兼容的函数式接口的类型 .
写在最后
如果觉得文章对你有点帮助, 请微信搜索并关注「 冰河技术 」微信公众号, 跟冰河学习 Java8 新特性.
最后, 附上 Java8 新特性核心知识图, 祝大家在学习 Java8 新特性时少走弯路.
来源: https://www.cnblogs.com/binghe001/p/12834021.html