java8 functional interface (FunctionalInterface) [two]

Continuing from the previous chapter, this article introduces the following two points of functional interfaces:

  • declare exception
  • Generics and Inheritance

Declaring Exceptions
Abstract methods of functional interfaces can declare checked exceptions.

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

Catch the exception in the calling method or keep throwing.

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

The above code compiles and runs.
But if the exception is not declared in the functional interface, and the exception is thrown in the lambda expression, the compilation will fail.

    @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();
    }
}

The reason is that the target type required by the lambda expression is different from the NoExceptionFunctional interface (the content of the java method signature in an article made me understand that the method signature may be different, but I did not find more information to prove whether this article is correct. Click to view ). The action() function of the NoExceptionFunctional interface does not declare an exception.

It's okay if the exception declared in the functional interface does not throw in the lambda expression.

    @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();
    }
}

The above code works.

Generics and Inheritance
The previous article introduced the inheritance of functional interfaces, but did not introduce them together with generics, because the last article mainly gave readers an understanding of the definition of functional interfaces and how to define them. introduced to this article.

Interfaces can inherit interfaces. If the parent interface is a functional interface, then the child interface may also be a functional interface. Judgment criteria are based on the following conditions:

For interface I, assuming that M is the inheritance of all abstract methods in the interface members (including the methods inherited from the parent interface), excluding the methods with the public instance method signature of Object, then we can judge whether an interface is based on the following conditions is a functional interface, which allows a more precise definition of a functional interface.
If there is a method m that satisfies:

  • The signature of m (subsignature) is the sub-signature (signature) of each method signature in M
  • The return type of m is the return-type-substitutable of each method in M.
    Then I is a functional interface.

The above content is quoted from the reference materials, which describes that when a functional interface inherits multiple interfaces, it will be judged according to the method signature, but I found during the test that the judgment basis does not only include the method signature.
The test examples are listed below

1. The two functional connection methods are exactly the same

@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{

}

The interface IM inherits the m method of the I and M interfaces. Since these two methods have the same signature and the same return value, IM has a unique abstract method int m(Iterable arg);, which can be used as a functional interface.

2. There is a method without generics

@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{

}

The method signature Mm satisfies that the signature is Im and the return value also satisfies return-type-substitutable. So IM is a functional interface, and the function type is Iterable m(Iterable arg).

3. Different generics are given in the formal parameters

    // 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 {

    }

Compile error, Multiple non-overriding abstract mehods found in interface IM

4. Different generics are given in the return value

    // 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 {

    }

Compile error, Multiple non-overriding abstract mehods found in interface IM

5. One of the return types specifies the type of inheritance relation

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

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

    @FunctionalInterface
    public interface IM extends I, M {

    }

Compiled, using List m(Iterable arg);

6. One of the return types specifies a type without inheritance

    // 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, a generic that does not pass in

// 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> {

}

Compiled, but failed to execute: 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 {
}

Compiled.
XYZ works fine, but cannot throw exceptions.
XY calls the m() method to report an error: Unhandled exception: java.io.EOEFxception

Summary
In summary , there are many judgments for the inheritance of functional interfaces, and the tests here are only partial, so more tests are needed when writing inherited functional interfaces.

References
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

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326488153&siteId=291194637