Skip to content

4.28 Self 9

Functional Interface

A functional interface in Java is an interface that contains only one abstract method.

Functional interfaces can have multiple default or static methods and methods from other classes, but only one abstract method.

Note even if we didn't declare access modifiers before void, it will set public abstract​ as default

public interface Bird A {
    void canFly(String val); 
}

Also it's better that we add @FunctionalInterface​ annotation, because it will throws a error if we add one more abstract class

If we don't add this, it can contain two abstract classes but this method will no longer be Functional Interface

Example

@FunctionalInterface
public interface Bird {

    void canFly(String val); // Abstract method

    default void getHeight() {
        // default method implementation
    }

    static void canEat() {
        // my static method implementation
    }

    String toString(); // Object class method
}

Different ways to implements functional interface

1. Using implements keyword

@FunctionalInterface
public interface Bird {

    void canFly(String val);
}
---
public class Eagle implements Bird {

    @Override
    public void canFly(String val) {
        System.out.println("Eagle Bird Implementation");
    }
}

Then we can do this

Bird eagleObject = new Eaglg();
eagleObject.canFly("vertical");

2. Using anonymous class

Anonymous class

“You cannot have instances of Interfaces or Abstract classes”, this is true.

But you can have an Anonymous class implementing an Interface or Abstract class.

Anonymous class is a class without a given name.

Why would you want one?

When an abstract class or interface requires few methods and you don’t want to introduce new classes that will only be used once.

@FunctionalInterface
public interface Bird {

    void canFly(String val);
}
---

public class Main {

    public static void main(String args[]) {

        Bird eagleObject = new Bird() {
            @Override
            public void canFly(String val) {
                System.out.println("Eagle Bird Implementation");
            }
        };
        eagleObject.canFly("vertical");

    }
}

In this way, we can do the same thing

3. Using Lambda expression

Lambda expression is a way to implement the Functional Interface. Before going into further into Lambda expression, lets first see:

We use this because it can reduce the complexity of above 2.

Format: (list-arguments) -> {body}

@FunctionalInterface
public interface Bird {

    void canFly(String val);
}
---

public class Main {

    public static void main(String args[]) {

        Bird eagleObject = (String value) -> {
            System.out.println("Eagle Bird Implementation");
        };

        eagleObject.canFly("vertical");

    }

}

Types of functional interface

1. Consumer

Consumer

  • Represent an operation, that accept a single input parameter and returns no result.
  • Present in package: java.util.function;
@FunctionalInterface
public interface Consumer<T> {

    void accept(T t);
}
---
public class Main {

    public static void main(String args[]) {

        Consumer<Integer> loggingObject = (Integer val) -> {
            if (val > 10) {
                System.out.println("Logging");
            }
        };

        loggingObject.accept(11);

    }

}

2. Supplier

Supplier

  • Represent the supplier of the result. Accepts no Input parameter but produce a result
  • Present in package: java.util.function;
@FunctionalInterface
public interface Supplier<T> {

    T get();
}
---
public class Main {

    public static void main(String args[]) {

        Supplier<String> isEvenNumber = () -> "this is the data i am returning";

        System.out.println(isEvenNumber.get());

    }

}

3. Function

  • Represent function, that accepts one argument process it and produce a result.
  • Present in package: java.util.function;
@FunctionalInterface
public interface Function<T, R> {

    R apply(T t);
}
---
public class Main {

    public static void main(String args[]) {

        Function<Integer, String> integerToString =
            (Integer num) -> {
                String output = num.toString();
                return output;
            };

        System.out.println(integerToString.apply(64));
    }
}

4. Predicate

  • Represent function, that accept one argument and return the boolean.
  • Present in package: java.util.function;
@FunctionalInterface
public interface Predicate<T> {

    boolean test(T t);
}
---
public class Main {

    public static void main(String args[]) {

        Predicate<Integer> isEven = (Integer val) -> {
            if (val % 2 == 0) {
                return true;
            } else {
                return false;
            }
        };

        System.out.println(isEven.test(19));
    }
}

Handle use case when Functional Interface extends from other Interface

Use Case 1: Functional Interface extending Non Functional Interface

public interface LivingThing {

    public void canBreathe();
}

@FunctionalInterface
public interface Bird extends LivingThing {

    void canFly(String val);
}

This is wrong because LivingThing​ has one abstract method and Bird​ extends it, then Bird​ will have 2 abstract method.


Here is the correct use

public interface LivingThing {

    default public boolean canBreathe() {
        return true;
    }
}

@FunctionalInterface
public interface Bird extends LivingThing {

    void canFly(String val);
}

Use Case 2: Interface extends Functional Interface

@FunctionalInterface
public interface LivingThing {

    public boolean canBreathe();
}

public interface Bird extends LivingThing {

    void canFly(String val);
}

This is correct because Bird​ didn't have annotation keyword, then it's allowed and also it is not a Functional interface\

Use Case 3: Functional Interface extending other Functional Interface

Wrong way:

@FunctionalInterface
public interface LivingThing {

    public boolean canBreathe();
}

@FunctionalInterface
public interface Bird extends LivingThing {

    void canFly(String val);
}

Correct way: This is because these two abstract method are same(signature same), then they are considered as one abstract method

@FunctionalInterface
public interface LivingThing {

    public boolean canBreathe();
}

@FunctionalInterface
public interface Bird extends LivingThing {

    boolean canBreathe();
}

---

public class Main {

    public static void main(String args[]) {

        Bird eagle = () -> true;

        System.out.println(eagle.canBreathe());
    }
}