Java8新特性-lambda表达式
在刚毕业的时候,就听公司里面的大神说过lambda的事情,大神说Java语言怎么怎么的弱,需要靠框架才能完成需要解决的问题,当时想想也是这么回事。Java8推出了lambda表达式,相对于其他语言,比如python,Lisp,JavaScript等等这些语言确实落后了不少。
1.究竟什么是Lambda表达式?
Lambda表达式的概念来自于Lambda演算,下面是一个java lambda的简单例子,(int x)-> { return x+1;}
简单来看lambda像一个没有名字的方法,具有一个方法应该有的部分
- 参数列表: int x
- 方法body: return x+1
和方法相比lambda好像缺少了一个返回值类型、异常抛出和名字。
2. Lambda的用法
语法:
(parameters) -> expression
(parameters) -> statement
(parameters) -> { statements; }
举例:
() -> Math.PI * 2.0
(int i) -> i * 2
(String s) -> s.length()
(int i0, int i1) -> i0 + i1
(int x, int y) -> { return x + y; }
1. 省略类型
(int x, int y) -> { return x + y; };
(x, y) -> { return x + y; };
2. 1个参数可以省略括号
(String text) -> { System.out.println(text); };
(text) -> { System.out.println(text); };
text -> { System.out.println(text); };
3. 函数体多行时需要大括号
(int i) -> {
int prod = 1;
for(int n = 0; n < 5; n++) prod *= i;
return prod;
};
4. 函数体只有一行的话可以省略大括号
text -> System.out.println(text);
5. 只有一行代码而且有返回值的可以省略return
(x, y) -> { return x -y; };
(x, y) -> x -y;
6. 没有参数没有返回值的空函数
() -> {};
7. 用于Lambda的变量不可变
int portNumber = 1337;
Runnable r = () -> System.out.println(portNumber); // OK
// 编译错误
// Local variable portNumber defined in an enclosing scope must be final or effectively final
int portNumber = 1337;
Runnable r = () -> System.out.println(portNumber); // NG
portNumber = 1338;
// 通过数组实现
final int[] wrappedNumber = new int[] { 1337 };
Runnable r = () -> System.out.println(wrappedNumber[0]); // OK
wrappedNumber[0] = 1338;
8. 其他
- 一个λ表达式可以有多个目标类型(函数接口),只要函数匹配成功即可。但需注意一个λ表达式必须至少有一个目标类型。
- 一个λ表达式可以被当做Object使用,需要赋值给一个函数接口,然后再赋值给一个Object。
运行机制
Java 7引入了invokedynamic指令,它是一个JVM指令,允许动态语言在run-time时动态绑定。Java 8的Lambda表达式并不是匿名类的语法糖,它不会在编译的时候生成类似于匿名类的xxx$1.class,而是在运行的时候使用invokeDynamic指令。对于一条Lambda表达式在class里边会包含一个invokedynamic命令和一个静态方法。运行时会使用LambdaMetafactory#metafactory做成一个Lambda$1的内部类再调用该函数式接口的实例。在运行时生成class,就是避免class太多影响加载速度,像Stream那样的到处是Lambda。