Java8
往函数式编程迈入了一大步;引入了函数式接口的概念;并使用 lambda
表达式在语法上大大简化函数式接口写法;
帖上一段简单的示例代码:
Runnbale run = () -> System.out.println("Hello Jack!");
new Thread(run).start();
lambda
可以粗暴看作为匿名类的实现,提供了轻量级的语法上的实现,但远不止如此,比喻还有改变 this
的指向;
在使用 lambda
的时候有几个要注意的地方:
声明:函数式接口是指只有一个函数的接口,可以使用
@FunctionalInterface
注解来进行显示声明,这样编译器会验证接口是否满足函数接口的要求;也可以不使用@FunctionalInterface
来显示声明,接口满足只有一个函数的要求即可,不包含有default
默认实现的函数;类型推导:使用
lambda
的时候,简化的语法形式对指向类型变得泛化无法明确,对后续程序执行变得不安全,编译器自动根据使用上下文所期待的类型(即目标类型)来进行推导出来的具体函数式接口;例如我写了两个lambda
表达式;
Callable<String> callable = () -> "hello";
PrivilegedAction<String> a = () -> "world";
第一个就是 Callbale
的实例,第二个是PrivilegedAction
的实例;
但是要注意是:
Object o = () -> { System.out.println("hello"); };
这样的代码是非法的,编译无法通过,因为后面的lambda
表达式无法根据目标类型推荐出是哪个函数接口,如像下面做一个强制转换,才能编译通过;
Object o = (Runnable) () -> { System.out.println("hello"); };
- 语法作用域:
this
不再如内部类那向指向内部类自己,而是当前类的执行环境对象,并没有引用新的作用域,这样使得lamada
表达式在形式上更加直接,与上下文代码保持一致;如下代码示例:
public class Hello {
Runnable runnable = () -> { System.out.println(this); };
public String toString() {
return "I am 'Hello'";
}
public static void main(String[] args) {
new Hello().runnable.run();
}
}
执行结果:
"I am 'Hello'"
外部的变量和值
:在Java1.8
之前,匿名内部类要访问外部的成员变量,需要将外部的成员变量使用final
进行修饰,即从语法上强制要求内部类不能对外部的变量进行赋新值;Java1.8
的lambda
从语法上放开了这个限制,即不用加final
修饰变量,lambda
表达式(或者匿名内部类中)都可以自由的访问变量的值,但试图对外部的变更进行赋值仍然是不被允许的,因为这是引起『race condition』,在多线程情况下会引起程序出现不可预测的错误。