12 Java - Interfaces (Functional & Lambda)

What is Functional Interface?

  • If an interface contains only 1 abstract method, that is known as Functional Interface.

  • Alos known as SAM interface (Single Abstract Method).

  • @ FunctionalInterface keyword can be used at top of the interface(But its optional)

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

OR

public interface Bird {
    void canFly(String val);
}
  • @ FunctionalInterface Annotation restrict us and throws compilation error, if we try to add more than 1 abstract method.

  • In Functional Interface, only 1 abstract method is allowed, but we can have other methods like default, static method or Methods inherited from the object class.
@FunctionalInterface
public interface Bird {
    void canFly(String val);

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

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

    String toString(); // Object class method
}
public interface TestInterface {
    String toString();
}

// No need to implement toString because
//Object class already implemented
public class TestClassImplements implements TestInterface{
}

What is Lambda Expression?

  • Lambda expression is a way to implement the Functional Interface.

  • Lambda expression is introduced because of functional interface.

Before going into further into Lambda expression, lets first see:

3 Ways to Implement the Functional Interface

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

Using "implements"

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

Using "anonymous Class"

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

Using "Lambda Expression"

public class Main {
    public static void main(String[] args) {
        Bird eagleObject = (String val) -> {
            System.out.println(val);
        };

        eagleObject.canFly("Cool");
    }
}

Types of Functional Interface

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

Usage

import java.util.function.Consumer;

public class Main {
    public static void main(String[] args) {
        Consumer<Integer> loggingObject = (Integer val) -> {
            if (val > 10){
                System.out.println("logging");
            }
        };
        loggingObject.accept(11);
    }
}

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

Usage

public class Main {
    public static void main(String[] args) {
        Supplier<String> isEvenNumber = () -> "this is the data I am returning";
        System.out.println((isEvenNumber.get()));
    }
}

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);
}
import java.util.function.Function;

public class Main {
    public static void main(String[] args) {
        Function<Integer, String> app = (Integer num) -> {
          String output = num.toString();
          return output;
        };
        System.out.println(app.apply(64));
    }
}

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);
}
import java.util.function.Predicate;

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

Not Possible

Use Case 2

Interface extending Functional Interface

@FunctionalInterface
public interface LivingThing {
    public void canBreathe();
}

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

Use Case 3

Functional Interface extending other Functional Interface

Not possible

@FunctionalInterface
public interface LivingThing {
    public void canBreathe();
}

@FunctionalInterface
public interface Bird extends LivingThing{
    void canFly(String val);
}

Possible

@FunctionalInterface
public interface LivingThing {
    public boolean canBreathe();
}

@FunctionalInterface
public interface Bird extends LivingThing{
    public boolean canBreathe();
}

Usage

public class Main {
    public static void main(String[] args) {
        Bird eagle = () -> true;
        System.out.println(eagle.canBreathe());
    }
}