java8 函数式接口(FunctionalInterface) [二]

话接上章,这篇介绍函数式接口的以下两点:

  • 声明异常
  • 泛型及继承关系

声明异常
函数式接口的抽象方法可以声明 可检查异常(checked exception)。

    @FunctionalInterface
    public static interface Functional {
        void action() throw Exception;
    }

在调用方法中捕获异常或继续抛出。

public class FunctionalTest{
    public static void main(String... args){
        Functional func = ()->{
            throw new Exception();
        };
    }
    try{
        func.action();
    }catch(Exception e){
        e.printStackTrace();
    }
}

上面的代码可以编译运行的。
但是如果函数式接口中没有声明这个异常,而lambda表达式中抛出这个异常,就会编译失败。

    @FunctionalInterface
    public static interface NoExceptionFunctional {
        void action();
    }
//wile be compile error
public class NoExceptionFunctionalTest{
    public static void main(String... args){
        Functional func = ()->{
            throw new Exception();
        };
    }
    try{
        func.action();
    }catch(Exception e){
        e.printStackTrace();
    }
}

原因是lambda表达式要求的目标类型和NoExceptionFunctional接口不同(有篇文章中对java方法签名的内容让我理解可能是方法签名不同,但是没有找到更多的资料去证明这篇文章是否正确。点击查看)。 NoExceptionFunctional接口的action()函数没有声明异常。

如果函数式接口中声明的异常,而lambda表达式中不抛出异常,也是可以的。

    @FunctionalInterface
    public static interface HasExceptionFunctional {
        void action();
    }
//wile be compile error
public class HasExceptionFunctionalTest{
    public static void main(String... args){
        Functional func = ()->{
            throw new Exception();
        };
    }
    try{
        func.action();
    }catch(Exception e){
        e.printStackTrace();
    }
}

上面的代码是可以运行的。

泛型及继承关系
上一篇有介绍了函数式接口的继承,但是没有结合泛形一起去介绍, 因为上篇主要是让读者对函数式接口的定义以及如何定义有一个了解,所以复杂的放到这篇文章介绍了。

接口可以继承接口。 如果父接口是一个函数接口, 那么子接口也可能是一个函数式接口。 判断标准依据下面的条件:

对于接口I, 假定M是接口成员里的所有抽象方法的继承(包括继承于父接口的方法), 除去具有和Object的public的实例方法签名的方法, 那么我们可以依据下面的条件判断一个接口是否是函数式接口, 这样可以更精确的定义函数式接口。
如果存在一个一个方法m, 满足:

  • m的签名(subsignature)是M中每一个方法签名的子签名(signature)
  • m的返回值类型是M中的每一个方法的返回值类型的替代类型(return-type-substitutable)
    那么I就是一个函数式接口。

上面的内容是引用参考资料中的,里面介绍了函数式接口在继承多个接口时,会根据的方法签名进行判断, 但是我在测试时发现,判断依据并不仅仅只包含方法的签名。
下面将测试的例子列出来

1、 两个函数式接品方法完全一样

@FunctionalInterface
public interface I {
    int m(Iterable<String> arg); 
}

@FunctionalInterface
public interface M {
    int m(Iterable<String> arg); 
}

@FunctionalInterface
public interface IM extends I, M{

}

接口IM继承了I,M接口的m方法,由于这两个方法的签名相同,返回值也一样,所以IM有唯一的一个抽象方法int m(Iterable arg);,可以作为函数式接口。

2、 有一个方法中不加泛形

@FunctionalInterface
public interface I {
    List m(Iterable<String> arg); 
}

@FunctionalInterface
public interface M {
    List<String> m(Iterable arg); 
}

@FunctionalInterface
public interface IM extends I, M{

}

方法签名M.m 既满足签名是I.m,并且返回值也满足return-type-substitutable。所以IM是函数式接口,函数类型为Iterable m(Iterable arg)。

3、形参中给定不同泛形

    // compile error
    @FunctionalInterface
    public interface I {
        List m(Iterable<String> arg);
    }

    @FunctionalInterface
    public interface M {
        List m(Iterable<Integer> arg);
    }

    @FunctionalInterface
    public interface IM extends I, M {

    }

编译出错,Multiple non-overriding abstract mehods found in interface IM

4、返回值中给定不同的泛形

    // compile error
    @FunctionalInterface
    public interface I {
        List<String> m(Iterable arg);
    }

    @FunctionalInterface
    public interface M {
        List<Object> m(Iterable arg);
    }

    @FunctionalInterface
    public interface IM extends I, M {

    }

编译出错,Multiple non-overriding abstract mehods found in interface IM

5、 其中一个返回类形中指定有继承关第的类型

    @FunctionalInterface
    public interface I {
        List<String> m(Iterable arg);
    }

    @FunctionalInterface
    public interface M {
        Object m(Iterable arg);
    }

    @FunctionalInterface
    public interface IM extends I, M {

    }

编译通过,使用的是List m(Iterable arg);

6、其中一个返回类形中指定没有继承关第的类型

    // compile error
    @FunctionalInterface
    public interface I {
        List<String> m(Iterable arg);
    }

    @FunctionalInterface
    public interface M {
        String m(Iterable arg);
    }

    @FunctionalInterface
    public interface IM extends I, M {

    }

编译不通过,’m(iterable)’ in ‘M’ clashes with ‘m(Iterable)’ in ‘I’ ; methods have unrelated return types

7、 一个不传入泛形

// has error
@FunctionalInterface
public interface Car {
    void m(String arg);
}

@FunctionalInterface
public interface Animal<T> {
    void m(T arg);
}

@FunctionalInterface
public interface IM extends Car, Animal<String> {

}

编译通过,但无法执行:Ambiguous method call: both ‘Car.m(String)’ and ‘Animal.m(String)’ match

8、

@FunctionalInterface
interface X {
    void m() throws IOException;
}

@FunctionalInterface
interface Y {
    void m() throws EOFException;
}

@FunctionalInterface
interface Z {
    void m() throws ClassNotFoundException;
}

@FunctionalInterface
interface XY extends X, Y {
}

@FunctionalInterface
interface XYZ extends X, Y, Z {
}

编译通过。
XYZ可以正常运行,但不能抛异常。
XY调用m()方法报错:Unhandled exception:java.io.EOEFxception

总结
综合如上,对于函数式接口的继承,它的判断依据有很多种,而这里测试,仅仅只是部分,所以在编写继承的函数式接口时,需要进行更多的测试。

参考资料
http://colobu.com/2014/10/28/secrets-of-java-8-functional-interface/
http://iteratrlearning.com/java/generics/2016/05/12/intersection-types-java-generics.html

猜你喜欢

转载自blog.csdn.net/mr_rain/article/details/73729745
今日推荐