🎓 Top 15 Udemy Courses (80-90% Discount): My Udemy Courses - Ramesh Fadatare — All my Udemy courses are real-time and project oriented courses.
▶️ Subscribe to My YouTube Channel (178K+ subscribers): Java Guides on YouTube
▶️ For AI, ChatGPT, Web, Tech, and Generative AI, subscribe to another channel: Ramesh Fadatare on YouTube
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