Java里的lambda表达式

Posted anivia

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java里的lambda表达式相关的知识,希望对你有一定的参考价值。

在上一篇文章《Java里的函数式接口》介绍了关于函数式接口的内容,那么本文基于函数式接口来继续学习lambda表达式。

  • 语法结构
Runnable runnable = () -> System.out.println("Runnable Instance");

这种使用箭头符号->分开参数列表和方法体的语法就是lambda表达式。在Java 里没有和lambda 表达式对应的类定义或者代码库,lambda表达式总是在定义后赋值给某个函数式接口类型变量。

一个 lambda表达式的参数列表声明和方法实现必须和所赋值的函数式接口函数中的抽象方法匹配。关于lambda表达式和函数式接口之间的关系还有以下注意点:

  1. 参数列表的括号必不可少,即使没有参数声明。
  2. 参数列表的参数声明顺序要和函数式接口的抽象方法一致,而且可以省略参数的类型声明。
  3. 方法体若只有一行代码,则可以省略方法体声明的中括号,如果方法体有返回值,则也可以省略return关键字。若加上了中括号,那么return关键字必须补上。
  4. 方法体若不止一行代码,中括号不可以省略,返回值的return关键字也不可以省略。
  • 使用变量

在lambda表达式里可以使用上下文中的变量,但是和匿名类中使用上下文变量一样的限制,要求变量必须是final的。

然而在Java8里,也可以不明确的加上final,只需要该变量是一种“形式final”即可。例如以下代码会通过编译并正常运行:

        String message = "Message";
        Runnable runnable = () -> System.out.println(message);
        new Thread(runnable).start();

message变量并没有加上关键字final,但是很明显它被初始化之后没有对它进行任何操作,所以“显然”它肯定是“不可变”的,所以可以在lambda 表达式里使用。但是以下代码就不能通过编译:

        String message = "Message";
        message = "Message2";
        Runnable runnable = () -> System.out.println(message);
        new Thread(runnable).start();

在message初始化之后,又进行了一次赋值操作,明显不符合一个final变量只能赋值一次的约束,所以lambda表达式里不能使用。

关于在Java8里引入的这种新特性,到底是什么实现的呢?我们可以编译代码之后查看class文件,就会发现上述代码变成了以下样子:

final String message = "Message";
        Runnable runnable = () -> {
            System.out.println(message);
        };
        (new Thread(runnable)).start();

编译器自动给message加上了final关键字。

  • 总结

lambda表达式不单独存在和使用,它总是从上下文中推导参数类型和自己的类型,可以把lambda表达式赋值给符合条件的函数式接口类型变量,也可以把它传递给接受符合条件的函数式接口类型的方法里。通过lambda表达式,我们可以真的做到将代码块作为变量一样使用。

以上是关于Java里的lambda表达式的主要内容,如果未能解决你的问题,请参考以下文章

java8的lambda表达式及方法引用

JAVA由一个将JSONArray转成Map的需求引发的lambda语法的学习

Java8 Lambda表达式介绍

lambda表达式在解决java后台分组排序时的应用

IntelliJ:求值lambda表达式在调试时引发编译错误

死磕Lambda表达式:更简洁的Lambda