What Are Functional Interfaces Used For in Java 8

What are functional interfaces used for in Java 8?

@FunctionalInterface annotation is useful for compilation time checking of your code. You cannot have more than one method besides static, default and abstract methods that override methods in Object in your @FunctionalInterface or any other interface used as a functional interface.

But you can use lambdas without this annotation as well as you can override methods without @Override annotation.

From docs

a functional interface has exactly one abstract method. Since default
methods have an implementation, they are not abstract. If an interface
declares an abstract method overriding one of the public methods of
java.lang.Object, that also does not count toward the interface's
abstract method count since any implementation of the interface will
have an implementation from java.lang.Object or elsewhere

This can be used in lambda expression:

public interface Foo {
public void doSomething();
}

This cannot be used in lambda expression:

public interface Foo {
public void doSomething();
public void doSomethingElse();
}

But this will give compilation error:

@FunctionalInterface
public interface Foo {
public void doSomething();
public void doSomethingElse();
}

Invalid '@FunctionalInterface' annotation; Foo is not a functional
interface

Purpose of Functional Interfaces in Java8

Obviously you can skip using these new interfaces and roll your own with better names. There are some considerations though:

  1. You will not be able to use custom interface in some other JDK API unless your custom interface extends one of built-ins.
  2. If you always roll with your own, at some point you will come across a case where you can't think of a good name. For example, I'd argue that CheckPerson isn't really a good name for its purpose, although that's subjective.

Most builtin interfaces also define some other API. For example, Predicate defines or(Predicate), and(Predicate) and negate().

Function defines andThen(Function) and compose(Function), etc.

It's not particularly exciting, until it is: using methods other than abstract ones on functions allows for easier composition, strategy selections and many more, such as (using style suggested in this article):

Before:

class PersonPredicate {
public Predicate<Person> isAdultMale() {
return p ->
p.getAge() > ADULT
&& p.getSex() == SexEnum.MALE;
}
}

Might just become this, which is more reusable in the end:

class PersonPredicate {
public Predicate<Person> isAdultMale() {
return isAdult().and(isMale());
}

publci Predicate<Person> isAdultFemale() {
return isAdult().and(isFemale());
}

public Predicate<Person> isAdult() {
return p -> p.getAge() > ADULT;
}

public Predicate<Person> isMale() {
return isSex(SexEnum.MALE);
}
public Predicate<Person> isFemale() {
return isSex(SexEnum.FEMALE);
}
public Predicate<Person> isSex(SexEnum sex) {
return p -> p.getSex() == sex;
}
}

Functional interfaces introduced in java 8

While all of these interfaces existed prior to Java 8, 2 of them - Runnable and Callable - were annotated as @FunctionalInterface since Java 8. That said, this annotation is informative, and even without it, they can be used as functional interfaces (which means they can be implemented by a lambda expression or a method reference) since Java 8.

The other two are not functional interfaces, since they have multiple abstract methods.

Java8: About Functional Interface

You are using the Lambda syntax to implement the getCar() method of the Rideable interface, where the following anonymous class program is omitted using Lambda's concise syntax:

Rideable rideable = new Rideable() {
@Override
public Car getCar(String name) {
return new Car(name);
}
};

This is Java 7 code. You can achieve the same thing using using Lambda expression:

Rideable rider = name -> new Car(name);

Or as in your example, using method reference:

Rideable rider = Car::new;

As a result, the getCar(String) method of the Rideable object can be used as a new Car(String).

And as an answer to your question, you are creating an instance of Car class that implements the Rideable interface. This is another way you can implement an interface without using implement keyword.

If you are thinking of:

Car auto = Car("MyCar")::new;

or

Car auto = Car::new;
Car vehicle = auto::getCar("MyCar");

or

Car vehicle = Rideable::new::getCar("MyCar");

All these examples are wrong approaches. I gave you this examples because these are common mistakes that can be made when we are speaking about Lambda expressions or method reference.

Functional Interface Implementations and use cases

Why would I have interface with only one abstract method? What would be the use case of having only single abstract method in my interface?

To facilitate the use of lambda expressions , which are nameless functions.
Lambda expressions make code expressive and reduce clutter. It also makes code more readable. This is based my experience working with lambda expressions.

What are the advantages of Java Functional Interfaces?

Your questions could be answered if you read manual about functional interfaces and lambdas.
Just take a look on difference between lambda expression and usual anonymous class creation. Both variables can be used the same way.

    //using anonymous class 
Predicate<String> isStringEmptyObj = new Predicate<String>() {
@Override
public boolean test(String o) {
return o.isEmpty();
}
};
System.out.println(isStringEmptyObj.negate().test("asd"));

//using lambda with reference to existing String object method
Predicate<String> isStringEmpty = String::isEmpty;
System.out.println(isStringEmpty.negate().test("asd"));

Definition of Functional Interface in Java 8

It is true that the Comparator interface has 2 abstract methods. But one of them is equals, which overrides the equals method defined in the Object class, and this method doesn't count.

From @FunctionalInterface:

If an interface declares an abstract method overriding one of the public methods of java.lang.Object, that also does not count toward the interface's abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere.

As such, this makes the Comparator interface a functional interface where the functional method is compare(o1, o2).

The lambda expression (a, b) -> a > b ? -1 : 1 complies with that contract: it declares 2 parameters and return an int.



Related Topics



Leave a reply



Submit