In this post, we will learn the Java 8 functional interface with examples.
The source code of this tutorial is hosted on my GitHub repository at Java 8 Functional Interfaces Source Code.
Key points about the functional interface:
- An Interface that contains exactly one abstract method is known as a functional interface.
- It can have any number of default, static methods but can contain only one abstract method. It can also declare the methods of the object class.
- Functional Interface is also known as Single Abstract Method Interfaces or SAM Interfaces. It is a new feature in Java 8, which helps to achieve a functional programming approach.
- A functional interface can extend another interface only when it does not have any abstract method.
- The Java API has many one-method interfaces such as Runnable, Callable, Comparator, ActionListener, and others. They can be implemented and instantiated using anonymous class syntax.
Examples of Custom Functional Interface
Create a custom Sayable interface is a functional interface annotated with @FunctionalInterface.
The @FunctionalInterface annotation indicates that an interface is a functional interface and contains exactly one abstract method.
Custom Functional Interface Example
Let's create a Sayable interface annotated with @FunctionalInterface annotation.
@FunctionalInterface
interface Sayable{
void say(String msg); // abstract method
}
Let's demonstrate a custom functional interface via the main() method. We use Lambda expression to implement functional interfaces:
public class FunctionalInterfacesExample {
public static void main(String[] args) {
Sayable sayable = (msg) -> {
System.out.println(msg);
};
sayable.say("Say something ..");
}
}
Java 8 Predefined-Functional Interfaces
Java 8 provides predefined functional interfaces to deal with functional programming by using lambda and method references.
Let's discuss Java Predefined-Functional Interfaces with examples.
Let's first create a Person class, we use this Person class is used to demonstrate Predefined-Functional Interfaces examples.
public class Person {
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Predicate Functional Interface
We need a function for checking a condition. A Predicate is one such function accepting a single argument to evaluate a boolean result.It has a single method test that returns the boolean value.
Predicate interface from JDK 8: Let's look at the internal implementation of the Predicate interface. Predicate interface contains exactly one abstract method test(T t). Note that it also contains default, static methods.
@FunctionalInterface
public interface Predicate<T> {
/**
* Evaluates this predicate on the given argument.
*
* @param t the input argument
* @return {@code true} if the input argument matches the predicate,
* otherwise {@code false}
*/
boolean test(T t);
default Predicate<T> and(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) && other.test(t);
}
default Predicate<T> negate() {
return (t) -> !test(t);
}
default Predicate<T> or(Predicate<? super T> other) {
Objects.requireNonNull(other);
return (t) -> test(t) || other.test(t);
}
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)
? Objects::isNull
: object -> targetRef.equals(object);
}
}
public class PredicateExample {
public static void main(String[] args) {
Predicate < Person > predicate = (person) -> person.getAge() > 28;
boolean result = predicate.test(new Person("ramesh", 29));
System.out.println(result);
}
}
Function Functional Interface
It represents a function that accepts one argument and returns a result.
Function interface from JDK 8: Let's look at the internal implementation of the Function interface. The function interface contains exactly one abstract method apply(T t). Note that it also contains default, static methods.
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
Objects.requireNonNull(before);
return (V v) -> apply(before.apply(v));
}
default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
Objects.requireNonNull(after);
return (T t) -> after.apply(apply(t));
}
static <T> Function<T, T> identity() {
return t -> t;
}
}
Let's create an example to demonstrates the usage of the Function functional interface:
import java.util.function.Function;
public class FunctionExample {
public static void main(String[] args) {
// convert centigrade to fahrenheit
Function < Integer, Double > centigradeToFahrenheitInt = x -> new Double((x * 9 / 5) + 32);
// String to an integer
Function < String, Integer > stringToInt = x -> Integer.valueOf(x);
System.out.println(" String to Int: " + stringToInt.apply("4"));
Function < PersonEntity, PersonDTO > function = (entity) -> {
return new PersonDTO(entity.getName(), entity.getAge());
};
PersonDTO personDTO = function.apply(new PersonEntity("ramesh", 20));
System.out.println(personDTO.getName());
System.out.println(personDTO.getAge());
}
}
class PersonEntity {
private String name;
private int age;
public PersonEntity(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class PersonDTO {
private String name;
private int age;
public PersonDTO(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
Supplier Functional Interface
Represents a supplier of results.
Supplier interface from JDK 8: Let's look at the internal implementation of the Supplier interface. The supplier interface contains exactly one abstract method get(T t). Hence we can apply lambda expression to it.
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
Let's create an example to demonstrates the usage of the Supplier functional interface:
import java.util.function.Supplier;
public class SuppliersExample {
public static void main(String[] args) {
Supplier<Person> supplier = () -> {
return new Person("Ramesh", 30 );
};
Person p = supplier.get();
System.out.println("Person Detail:\n" + p.getName() + ", " + p.getAge());
}
}
Consumer Functional Interface
It represents an operation that accepts a single argument and returns no result.
Consumer interface from JDK 8: Let's look at the internal implementation of the Consumer interface. The consumer interface contains exactly one abstract method accept(T arg0). Hence we can apply lambda expression to it.
@FunctionalInterface
public interface Consumer<T> {
void accept(T arg0);
default Consumer<T> andThen(Consumer<? super T> arg0) {
Objects.requireNonNull(arg0);
return (arg1) -> {
this.accept(arg1);
arg0.accept(arg1);
};
}
}
Let's create an example to demonstrates the usage of the Consumer functional interface:
public class ConsumersExample {
public static void main(String[] args) {
List<Person> listOfPerson = new ArrayList<Person>();
listOfPerson.add(new Person("abc", 27));
listOfPerson.add(new Person("mno", 26));
listOfPerson.add(new Person("pqr", 28));
listOfPerson.add(new Person("xyz", 27));
listOfPerson.forEach((person) -> {
System.out.println(" Person name : " + person.getName());
System.out.println(" Person age : " + person.getAge());
});
// Second example
Consumer<Person> consumer = (person) -> {
System.out.println(person.getName());
System.out.println(person.getAge());
};
consumer.accept(new Person("Ramesh", 30));
}
}
BiFunction Functional Interface
It represents a function that accepts two arguments and returns a result.
To define lambdas with two arguments, we have to use additional interfaces that contain the “Bi” keyword in their names: BiFunction, ToDoubleBiFunction, ToIntBiFunction, and ToLongBiFunction.
BiFunction interface from JDK 8: Let's look at the internal implementation of the BiFunction interface. BiFunction interface contains exactly one abstract method apply(T arg0, U arg1). Hence we can apply lambda expression to it.
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T arg0, U arg1);
default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> arg0) {
Objects.requireNonNull(arg0);
return (arg1, arg2) -> {
return arg0.apply(this.apply(arg1, arg2));
};
}
}
Let's create an example to demonstrates the usage of the BiFunction functional interface:
public class BiFunctionExample {
public static void main(String[] args) {
BiFunction<Person, Person, Integer> biFunction = (p1,p2) -> {
return p1.getAge() + p2.getAge();
};
int totalAge = biFunction.apply(new Person("Ramesh", 10),
new Person("ram", 10));
System.out.println(totalAge);
}
}
BiConsumer Functional Interface
It represents an operation that accepts two input arguments and returns no result.
BiConsumer interface from JDK 8: Let's look at the internal implementation of BiConsumer interface. BiConsumer interface contains exactly one abstract method accept(T arg0, U arg1). Hence we can apply lambda expression to it.
@FunctionalInterface
public interface BiConsumer<T, U> {
void accept(T arg0, U arg1);
default BiConsumer<T, U> andThen(BiConsumer<? super T, ? super U> arg0) {
Objects.requireNonNull(arg0);
return (arg1, arg2) -> {
this.accept(arg1, arg2);
arg0.accept(arg1, arg2);
};
}
}
Let's create an example to demonstrates the usage of the BiConsumer functional interface:
public class BiConsumersExample { public static void main(String[] args) { BiConsumer<Person, Person> biConsumer = (p1, p2) -> { System.out.println(" print first persion"); System.out.println(p1.getName()); System.out.println(" print second persion"); System.out.println(p2.getName()); }; biConsumer.accept(new Person("Ramesh", 10), new Person("ram", 10)); } }
BiPredicate Functional Interface
This interface represents a predicate that takes two arguments.
This is how the interface is defined:
@FunctionalInterface
public interface BiPredicate<T, U> {
boolean test(T t, U u);
// Default methods are defined also
}
package com.javaguides.java.functionalinterfaces;
import java.util.function.BiPredicate;
public class BiPredicateDemo {
public static void main(String[] args) {
// anonymous class implements BiPredicate interface
BiPredicate < String, String > predicateObject = new BiPredicate < String, String > () {
@Override
public boolean test(String s1, String s2) {
return s1.equals(s2);
}
};
System.out.println(predicateObject.test("Ramesh", "Ramesh"));
// Lambda expression implementation
BiPredicate < String, String > biPredicate = (s1, s2) -> s1.equals(s2);
System.out.println(biPredicate.test("ramesh", "ramesh"));
System.out.println(biPredicate.test("java guides", "Java Guides"));
}
}
Output:
true
true
false
Summary
- A functional interface is an interface that has exactly one abstract method.
- Since default methods have an implementation, they are not abstract so a functional interface can have any number of them.
- If an interface declares an abstract method with the signature of one of the methods of java.lang.Object, it doesn't count toward the functional interface method count.
- A functional interface is valid when it inherits a method that is equivalent but not identical to another.
- An empty interface is not considered a functional interface.
- A functional interface is valid even if the @FunctionalInterface annotation would be omitted.
- Functional interfaces are the basis of lambda expressions.
Source Code on GitHub
The source code of this article is available on GitHub Repository.4. Related Java 8 Top Posts
- Java 8 Lambda Expressions
- Java 8 Functional Interfaces
- Java 8 Method References
- Java 8 Stream API
- Java 8 Optional Class
- Java 8 Collectors Class
- Java 8 StringJoiner Class
- Java 8 Static and Default Methods in Interface
- Guide to Java 8 forEach Method
- Handle NullPointerException using Java 8 Optional Class
- How to Use Java 8 Stream API in Java Projects
- Migrating Source Code to Java 8
Comments
Post a Comment
Leave Comment