Blog

  •  

     

    This blog post is the second in the series of Diving Deep into the Lambda Expressions. Here we will discuss about Funtional Interfaces.By now, you already know what a Funtional Interface is. However, let’s dive deep into it.

     

    A functional interface, you already know, has one abstract method. It can be a target for a Lambda Expression or Method Reference. The use of the word abstract is significant. Prior to Java 8, all the methods in interfaces were considered abstract by default – there wasn’t any need to mention it.

     

     

     

     
    @FunctionalInterface
    
    public interface PalindromeChecker {
    
    boolean isPalindrome(String s);
    
    }
    

     

    You can leave the access modifier as well as the abstract keyword. Generally, to denote the functional interfaces, we use @FuntionalInterface annotation. Java 8 provides this annotation in the java.lang package that can be applied to the interfaces as shown above.

     

    Annotation is not mandatory, however it serves two purposes

     

    1. It generates an error when more than 1 abstract method declarations are present.
    2. Another benefit is that it helps in generating a statement to notify that interface is functional in Javadocs.

     

    Functional Interface can have:

     

    1. Only one abstract method (as described above)
    2. default method with proper implementation
    3. a static method with implementation

     

    as shown below :

     

     
    public interface MyInterface {
    int myMethod();
    // int mySecondMethod();
    default String sayHello() {
    return "Hello World";
    }
    static void myStaticMethod() {
    System.out.println("Printing from a static method");
    }
    }
    

     

    If we uncomment the line in the above method for my second method, with this annotation, it will throw an error saying that “multiple non-overriding abstract methods found”.If another interface extends this interface, and include another abstract method, that new interface can’t be used as a target for functional interfaces Lambda Expressions or method references.

     

    Below interface will be a valid one but it’s not a functional interface.

     

    public interface MyChildInterface extends MyInterface{
    int another();
    }
    

     

    Below declaration will give the compilation error because of the @FunctionalInterface annotation:

     

    @FunctionalInterface
    
    public interface MyChildInterface extends MyInterface{
    int another();
    }
    

     

    Please note that below declaration won’t give any error:

     

    @FunctionalInterface
    public interface MyChildInterface extends MyInterface{
    boolean equals(Object o);
    }
    

     

    This means we can declare methods in Object as abstract in an interface, but that doesn’t make them abstract. Usually, the reason for doing it so to add documentation that explains the contract of the interface. Rules for functional interfaces say that method from Object doesn't count against the single method limit, so our above interface, MyChildInterface is still a funtional interface.

     

    Same goes for the Comparator interface in java.util, as shown below :

     

     

     

     

    Default Methods in interfaces

     

    The traditional reason why java never supported multiple inheritances is the so-called diamond problem. Java’s approach was to prohibit multiple inheritance completely, and interfaces were introduced as a workaround for when a class has an “is a kind of” relationship with more than one type. Since, interfaces had only abstract methods, there were no implementations to conflict. The problem is, if you can never implement a method in an interface, you wind up with some awkward designs. For ex: Among the methods in the java.util.Collection interface, for ex:

    • boolean isEmpty()
    • int size()

    isEmpty() method can be implemented in terms of size also.

     

    Since Collection is an interface, you can’t do this in an interface itself. Instead, the standard library includes an abstract class, AbstractCollection, which includes, among other code, exactly the implementation of isEmpty. Two scenarios are possible here:

     

    1. If you don’t have a Super Class and you want to create your own implementation class, you can extend AbstractCollection and you get the isEmpty method for free.
    2. If you already have a Super Class, you have to implement the Collection interface instead and remember to provide your own implementations of isEmpty as well as size.

     

    Now, this imposes some restrictions on developers to be bounded by the rules.

     

    To avoid this, Java 8 introduced the ability to add default implementations to the interface methods. All that you have to do is to add a “default” keyword and provide an implementation.

     

    @FunctionalInterface
    public interface MyChildInterface extends MyInterface{
    boolean equals(Object o);
    }
    default void printThis(String s) {
        System.out.println(s);
    }
    }
    

     

     

     

    Many of the existing interfaces in Java have been enhanced with default methods to introduce the backward compatibility. Normally, when a new method is introduced in the interfaces, all the existing implementation will have to be modified to add the implementation of newly added methods. However, with this addition of default methods functionality, it is possible. No need to change the existing implementations. :)

     

    java.util.Collection now contains the following default methods:

     

    • default boolean removeIf(Predicate<? Super E> filter)
    • default Stream<E> stream()
    • default Stream<E> parallelStream()
    • default Spliterator<E> spliterator

     

    Note: If a class implements more than one interface with the same default method declarations (with same or different implementations), Our class will have to implement the method in the class itself.

     

     

     

    Static Methods

     

    To create the static method in interfaces, add static keyword ahead of the method declaration and provide the default implementation.To access it, classes don't need to implement an interface to use its static method. One example of such a method (static) is the comparing() method in the java.util.Comparator interface, along with its primitive variants:

    • comparing
    • comparing long
    • comparingDouble

     

    Comparator interface also has static methods naturalOrder and reverseOrder. Static methods in interfaces remove the need to create separate utility classes, though that option is still available.

     

    You can always check the Java Doc for more info on various Functional Interfaces. In the next blog, we will explore java.util.function package for all the functional interfaces that are provided by JDK for general purposes.

     

     

Tags: