书接上文,上一篇对 Java 8 数据结构中设计到的接口类型做了一个大致的分类,由于 Java 8 数据结构的源码中大量使用了 Java 8 的新特性,所以在阅读源码之前,先来了解一下这些特性。
Java 8 新特性
在分析行为接口类的源码之前,需要对 Java 8 的新特性有一个简单的了解,下面将通过解读官方定义与一些例子来简单介绍一下这些特性
1、函数式接口
@Documented
@Retention(value=RUNTIME)
@Target(value=TYPE)
public @interface FunctionalInterface
An informative annotation type used to indicate that an interface type declaration is intended to be a functional interface as defined by the Java Language Specification. Conceptually, a functional interface has exactly one abstract method. Since default methods have an implementation, they are not abstract. If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface’s abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere.
Note that instances of functional interfaces can be created with lambda expressions, method references, or constructor references. Oracle 官网对函数式接口的定义。
由定义可知:
- @FunctionalInterface 是一个函数式接口注解类,标注这个注解的接口将被定义为函数式接口
- 一个函数接口只能有一个抽象方法
- 默认接口方法有实现,所以不算在抽象方法中
- 如果一个接口定义了与 java.lang.Object 中的方法参数列表1 相同的方法,也不算在抽象方法中,因为该方法在 Object 中被实现了
- 函数式接口可以被 Lambda 表达式,方法引用或者构造引用创建。
函数式接口定义与使用方式:
public class FunctionalInterfaceDemo {
/**这里是使用 Lambda 表达式的方式创建函数式接口的具体实现**/
public static void main(String[] args) {
/**由于抽象函数只有一个方法,所以使用 Lambda 表达式调用时不用声明**/
FunctionalInter i = () -> System.out.println("This is a demo");
}
}
@FunctionalInterface
interface FunctionalInter {
void anyName();
}
2、默认方法
The section Interfaces describes an example that involves manufacturers of computer-controlled cars who publish industry-standard interfaces that describe which methods can be invoked to operate their cars. What if those computer-controlled car manufacturers add new functionality, such as flight, to their cars? These manufacturers would need to specify new methods to enable other companies (such as electronic guidance instrument manufacturers) to adapt their software to flying cars. Where would these car manufacturers declare these new flight-related methods? If they add them to their original interfaces, then programmers who have implemented those interfaces would have to rewrite their implementations. If they add them as static methods, then programmers would regard them as utility methods, not as essential, core methods. Oracle 官网对默认方法的定义
由定义可知:
官网是由了一个非常巧妙的例子,以汽车厂商(接口提供方)与电子导航厂商(接口实现方)为例,当未来的汽车有了飞行功能的时候,如果这个方法被汽车厂商定义在接口中,那么电子导航厂商就不得不实现这个接口,这是不符合 OOP 思想的。而如果将方法定义成接口的静态方法(Java 8 中的另一个新特性)那么开发人与啊会认为这些方法是工具方法,不是重要的,核心的方法。
默认方法的定义与使用方式:
public class DefaultMethodDemo implements DefaultMethodInterface {
public static void main(String[] args) {
DefaultMethodInterface demo = new DefaultMethodDemo();
demo.demo();
}
}
interface DefaultMethodInterface {
default void demo() {
System.out.println("This is a demo");
}
}
3、Lambda 表达式
One issue with anonymous classes is that if the implementation of your anonymous class is very simple, such as an interface that contains only one method, then the syntax of anonymous classes may seem unwieldy and unclear. In these cases, you’re usually trying to pass functionality as an argument to another method, such as what action should be taken when someone clicks a button. Lambda expressions enable you to do this, to treat functionality as method argument, or code as data. Oracle 官网对 Lambda 表达式的定义
由定义可知:
匿名类的问题之一是如果匿名类非常简单,比如一个接口只有一个方法(这里与函数式接口对应),那么这个匿名类的语法会显得非常笨重且难以理解。在这种情况下,使用 Lambda 表达式允许我们像传递方法参数那样传递功能,或者是实现代码。
Lambda 的使用方式:
public class LambdaExpressionDemo {
/**这里依然是使用函数式接口配合使用**/
public static void main(String[] args) {
AddFunctionalInter demoInterface = i -> i + 5;
demoInterface.add(6);
}
}
@FunctionalInterface
interface AddFunctionalInter {
Integer add(Integer num);
}
4、方法引用
You use lambda expressions to create anonymous methods. Sometimes, however, a lambda expression does nothing but call an existing method. In those cases, it’s often clearer to refer to the existing method by name. Method references enable you to do this; they are compact, easy-to-read lambda expressions for methods that already have a name. Oracle 官网对方法引用的定义
当使用 Lambda 表达式创建匿名方法时。有时候一个 Lambda 表达式只是调用一个已经存在的方法而不做其它事。在这种情况下,方法引用允许我们通过方法名的访问这些方法,这种调用已经存在的方法的方式使代码看上去更紧凑,更具阅读性。
方法引用的定义与使用方式:
public class MethodReferenceDemo {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3);
/**这里由于调用的是静态方法,所以直接用 类名::方法名 调用,如果是非静态方法,需要使用 对象::方法名的方式**/
list.forEach(MethodReferenceDemo::print);
}
private static void print(Integer num) {
System.out.println(num);
}
}
5、构造引用
构造引用是方法引用的一种形式,调用方式如下
public class ConstructorReferenceDemo {
/**注意使用构造引用时,函数式接口的参数必须与构造器参数相同,返回类型必须与构造器类型相同**/
public ConstructorReferenceDemo(String str) {
System.out.println(str);
}
public static void main(String[] args) {
ConstructorReferenceInterface demoInterface = ConstructorReferenceDemo::new; //这里并没有进入构造方法中,使用带参数的构造器比较容易看清楚
demoInterface.demo("This is a demo"); //这里才进入了构造方法
}
}
@FunctionalInterface
interface ConstructorReferenceInterface {
ConstructorReferenceDemo demo(String str);
}
了解了以上这些 Java 8 的新特性,阅读 Java 8 数据结构源码就不会一头雾水了。下一篇将介绍 Java 8 数据结构中的行为接口2。