Lambda表达式(也称为闭包)是Java 8中最大和最使人期待的语言改变。它容许咱们将函数当成参数传递给某个方法,或者把代码自己看成数据处理:函数式开发者很是熟悉这些概念。不少JVM平台上的语言(Groovy、Scala等)从诞生之日就支持Lambda表达式,可是Java开发者没有选择,只能使用匿名内部类代替Lambda表达式。php
Lambda的设计耗费了不少时间和很大的社区力量,最终找到一种折中的实现方案,能够实现简洁而紧凑的语言结构。最简单的Lambda表达式可由逗号分隔的参数列表、->符号和语句块组成,例如:css
Arrays.asList( "a", "b", "d" ).forEach( e -> System.out.println( e ) );
二、接口的默认方法和静态方法
Java 8使用两个新概念扩展了接口的含义:默认方法和静态方法。默认方法使得接口有点相似traits,不过要实现的目标不同。默认方法使得开发者能够在 不破坏二进制兼容性的前提下,往现存接口中添加新的方法,即不强制那些实现了该接口的类也同时实现这个新加的方法。html
默认方法和抽象方法之间的区别在于抽象方法须要实现,而默认方法不须要。接口提供的默认方法会被接口的实现类继承或者覆写,例子代码以下:java
private interface Defaulable { // Interfaces now allow default methods, the implementer may or // may not implement (override) them. default String notRequired() { return "Default implementation"; } } private static class DefaultableImpl implements Defaulable { } private static class OverridableImpl implements Defaulable { @Override public String notRequired() { return "Overridden implementation"; } }
Defaulable接口使用关键字default定义了一个默认方法notRequired()。DefaultableImpl类实现了这个接口,同时默认继承了这个接口中的默认方法;OverridableImpl类也实现了这个接口,但覆写了该接口的默认方法,并提供了一个不一样的实现。express
Java 8带来的另外一个有趣的特性是在接口中能够定义静态方法,例子代码以下:闭包
private interface DefaulableFactory { // Interfaces now allow static methods static Defaulable create( Supplier< Defaulable > supplier ) { return supplier.get(); } }
下面的代码片断整合了默认方法和静态方法的使用场景:ide
public static void main( String[] args ) { Defaulable defaulable = DefaulableFactory.create( DefaultableImpl::new ); System.out.println( defaulable.notRequired() ); defaulable = DefaulableFactory.create( OverridableImpl::new ); System.out.println( defaulable.notRequired() ); }
这段代码的输出结果以下:函数
Default implementation Overridden implementation
因为JVM上的默认方法的实如今字节码层面提供了支持,所以效率很是高。默认方法容许在不打破现有继承体系的基础上改进接口。该特性在官方库中的应用是:给java.util.Collection接口添加新方法,如stream()、parallelStream()、forEach()和removeIf()等等。ui
尽管默认方法有这么多好处,但在实际开发中应该谨慎使用:在复杂的继承体系中,默认方法可能引发歧义和编译错误。this
方法引用使得开发者能够直接引用现存的方法、Java类的构造方法或者实例对象。方法引用和Lambda表达式配合使用,使得java类的构造方法看起来紧凑而简洁,没有不少复杂的模板代码。
西门的例子中,Car类是不一样方法引用的例子,能够帮助读者区分四种类型的方法引用。
public static class Car { public static Car create( final Supplier< Car > supplier ) { return supplier.get(); } public static void collide( final Car car ) { System.out.println( "Collided " + car.toString() ); } public void follow( final Car another ) { System.out.println( "Following the " + another.toString() ); } public void repair() { System.out.println( "Repaired " + this.toString() ); } }
第一种方法引用的类型是构造器引用,语法是Class::new,或者更通常的形式:Class<T>::new。注意:这个构造器没有参数。
final Car car = Car.create( Car::new ); final List< Car > cars = Arrays.asList( car );
第二种方法引用的类型是静态方法引用,语法是Class::static_method。注意:这个方法接受一个Car类型的参数。
cars.forEach( Car::collide );
第三种方法引用的类型是某个类的成员方法的引用,语法是Class::method,注意,这个方法没有定义入参:
cars.forEach( Car::repair );
第四种方法引用的类型是某个实例对象的成员方法的引用,语法是instance::method。注意:这个方法接受一个Car类型的参数:
final Car police = Car.create( Car::new ); cars.forEach( police::follow );
运行上述例子,能够在控制台看到以下输出(Car实例可能不一样):
Collided com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d Repaired com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d Following the com.javacodegeeks.java8.method.references.MethodReferences$Car@7a81197d