新特性1-函数式接口

什么是函数式接口呢,简单的来说就是一个接口,其中只有一个没有被实现的方法,即SAM(Single Abstract Method)类型接口。这样的接口在过去的时候,需要用类去实现其中的抽象方法,或者类似于监听器那样,用匿名内部类的方式去实现。现在可以通过lambda表达式的形式来实现相关功能,方式十分简便。接下来我们来写一个典型的SAM

 1 @FunctionalInterface
 2 public interface TestFunctionInterface {
 3 
 4     void method();
 5     
 6     public static void main(String[] args) {
 7         TestFunctionInterface test = ()->System.out.println("test method");
 8         test.method();
 9     }
10 }

现在我们看这个interface和以前的相比有几个不同之处,第一个是里面有了有了static方法,第二个是多了一个@FunctionalInterface。我们首先说第一个,在java8以后,接口中可以定义方法,但是方法必须被static,或者default修饰,而且这样的方法不影响函数式接口的契约,可以定义一个或者多个,这里需要注意的是这里的default关键字不再是控制包访问控制权限,在其他包中仍然可以访问default关键字修饰的方法。第二个是@FunctionalInterface注解,这个注解表达了这个接口是一个函数式接口,强制要求了该接口中只能由一个未实现的抽象方法,不过在此处去掉这个注解,也不会报错。在jdk1.8中,将所有函数式接口的类都加上了@FunctionalInterface注解

不过在看源码的过程中我看到了这样一个类Comparator,很熟悉的一个类,我只截取了有疑惑的部分

1 @FunctionalInterface
2 public interface Comparator<T> {
3     
4     int compare(T o1, T o2);
5     
6     boolean equals(Object o);
7     
8 }

这里明明有两个未实现的方法,但是加上@FunctionalInterface仍然不报错,还可以用lambda表达式来正确的定义compare方法。这里就又涉及到另一条规则,就是对于Object类中已经实现的方法比如还有hashCode()等这样的方法,写在interface中的时候,不会被当做abstract接口来看待,因为所有的类都继承了Object类

综上对于函数式接口总结起来大概就是三句话:

  1、函数式接口中,原则上讲只应该有一个需要被实现的方法

  2、如果接口中存在已经完成定义的static和default方法,不影响函数式接口的判断

  3、接口中可以存在Object类已经定义的方法

对于函数式接口的定义,还有两点需要补充:

第一种是通过其他类的静态方法来定义

 1 @FunctionalInterface
 2 public interface TestFunctionInterface {
 3 
 4     Object method(String value);
 5     
 6     public static void main(String[] args) {
 7         TestFunctionInterface test = Integer::valueOf;
 8         Object o = test.method("123");
 9         System.out.println(o instanceof Integer);
10     }
11 }

输出结果是true。学过C++的同学会不会觉得Integer::valueOf有一点点亲切,以前在某个.cpp中去实现一个类的.h文件会大量用到class::method这种形式,后来写java很久没有用到过了。

第二种是通过构造方法来定义,我们来写一个简单的工厂模型:

 1 public class Test {
 2     
 3     public String property;
 4 
 5     public Test(String property) {
 6         this.property = property;
 7     }
 8     
 9     public Test(String a, String b) {
10         this.property = "double";
11     }
12     
13     public static void main(String[] args) {
14         ProduceTest<Test> t = Test::new;
15         Test test = t.create("single");
16         System.out.println(test.property);
17     }
18 }
19 
20 interface ProduceTest<t extends Test> {
21     t create(String property);
22 }

输出结果为single。

这里我们可以看出,在构造方法匹配的时候,可以根据参数自动匹配到合适的构造方法

posted on 2018-03-19 16:33  徐彬彬要好好学习  阅读(631)  评论(0编辑  收藏  举报