java 函数式接口相关内容及例子
什么是函数式接口呢,简单的来说就是一个接口,其中只有一个没有被实现的方法,即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。
这里我们可以看出,在构造方法匹配的时候,可以根据参数自动匹配到合适的构造方法