Java 8
新增的lambda
表达式毫无疑问是使人很是激动的,今后咱们能够很是简洁的定义和使用代码块而不是用繁琐的匿名内部类来实现。而接口是lambda
表达式的基础,要理解lambda
表达式就要先理解接口的概念。java
在Java
中接口是对类行为的抽象。彷佛继承也能作到这件事,它们的区别在于Java
中类只能有一个父类,而接口是能够实现多个的。因此接口更倾向于类的一部分抽象,也就是行为的抽象,而不是类自己的抽象。编程
要定义一个接口很简单,使用关键字interface
后面再跟上接口名称就能够了。类能够用implements
关键字来实现接口。安全
public interface A { void test(); }
public static final
public
Java 8
之后还能够声明静态方法和默认方法// Java 8版本 public interface A { //常量 String AUTHOR = "Yuicon"; //抽象方法 void test(); //默认方法 default void testDefault(){} //静态方法 static void testStatic(){} }
若是一个类实现的接口中有签名相同的默认方法,那么就会有冲突的问题。在Java
中解决这个问题有一些明确的规则:闭包
lambda
表达式是一个可传递的代码块,能够在之后执行一次或屡次。之因此会有这么一个特性,是由于原先在Java中传递一个代码块是很是繁琐的一件事情,必需要构建一个对象。好比经常使用的Runnable接口:并发
Runnable runnable = new Runnable() { @Override public void run() { System.out.println("我好麻烦"); } };
lambda
版本就很是简洁:编程语言
Runnable runnable = () -> System.out.println("我很简洁");
是的,lambda
版本只要一行就完成了任务。ide
在我看来lambda
表达式是一种语法糖,它提供了一种简洁、易懂的方式来实现只有一个抽象方法的接口。关键词是只有一个抽象方法的接口,好比这样一个接口:函数
@FunctionalInterface public interface A { void test(); } A a = () -> System.out.println("test"); a.test();
其中@FunctionalInterface
注解是用来标记接口为函数式接口,去掉也不会影响功能,添加了这个注解后编译器会检查接口内是否只有一个抽象方法。ui
lambda
表达式主要有如下要素:this
lambda
表达式的参数和普通方法的参数并没有太大区别,主要的区别点有:
Consumer<String> consumer = s -> System.out.println(s);
lambda
表达式的方法体内只有一条语句的时候,能够不加大括号且无需指定返回值,编译器会自动推导。方法体内有多条语句的时候就须要加大括号并手动指定返回值,不过lambda
表达式是没有本身的做用域的,这点须要注意。
Supplier<String> supplier = () -> { String s = "test"; return s; };
自由变量是指非参数并且不在方法体内定义的变量,咱们来看一个例子:
public static void main(String[] args) { String test = "test"; A a = () -> System.out.println(test); a.test(); }
例子中的变量test
就是一个自由变量,代码块a
引用了外部方法的变量,这就是一个闭包了。lambda
表达式会复制一份自由变量的值,对象的话就是复制一个引用,所以lambda
表达式离开了原做用域也能正常使用自由变量。不过lambda
表达式对自由变量是有要求的,自由变量必须是不可变的,缘由是并发执行时不安全。如下代码是错误的:
for (int i = 0; i < 9; i++) { // error A a = () -> System.out.println(i); }
方法引用是语法糖的语法糖,顾名思义方法引用是引用已有方法的一个特性。它的形式以下:
@FunctionalInterface public interface A { void test(String s); } A a = System.out::println; a.test("test");
之因此说方法引用是语法糖的语法糖是由于A a = System.out::println;
彻底等价于A a = s -> System.out.println(s);
,方法引用有5种状况:
前4种状况和lambda
表达式是彻底等价的,第5种状况比较特殊,第一个参数会成为方法的目标。好比String::compareToIgnoreCase
等同于 (x, y)-> x.compareToIgnoreCase(y)
。
构造器引用是引用对象的构造器,用的是特殊的方法名new
,使用形式为Object::new
,使用方法和方法引用差很少。
JDK
已经提供了经常使用的函数式接口基本上是不须要本身写函数式接口的。
一周一篇是不可能一周一篇的,人懒起来就和咸鱼同样根本不会动弹。还好人是会变通的,上周少了这周补上不就好了!Java
被人诟病繁琐不是一天两天了,在各类新生编程语言的追赶下Java
也要加快本身的演进了,更改发布周期就是一个很好的信号。
参考资料:《Java核心技术 卷1》