Being an object-oriented programming language, we can say that everything present in Java revolves around Objects, except for some of the primitive data types and primitive methods.
Table of Contents
There are also no independent functions available in Java and if you want to use a function, it can only be used when called by an object.
To cater to that, Java functional interfaces were introduced in Java 8. It is an interface that contains only one abstract method.
Before that, we had to create anonymous inner class objects or implement these interfaces. In this article, we will be discussing the working of a Java functional interface and different types of built-in Functional interfaces.
First introduced in Java 8, A functional interface is a special interface in Java that contains only one abstract method.
Along with an unimplemented (abstract) method, a java functional interface can also have multiple default and static methods with their implementations.
The use of the ‘abstract’ keyword is also optional in Java functional interface because, by default, the method defined inside the interface is only abstract.
The introduction of Java functional interfaces provided developers with a great approach to fundamental programming in Java and allowed them to develop more readable, clean, and straightforward Java codes.
See this very basic example of a Java functional interface:
@FunctionalInterface public interface FunctionalInterface01 { public void execute(); }
This interface qualifies as a Java functional interface because it only contains one method, execute and this method has no implementation, making it an abstract method.
Usually, a Java functional interface does not contain implementations of the methods it has declared, but there can be implementations in default or static methods in the interface.
See this another example of a Java functional interface, that contains the implementations of some of its methods:
@FunctionalInterface public interface FunctionalInterface02{ public void execute(); public default void outputData(String str) { System.out.println(str); } public static void outputData(String str, PrintWriter writer) throws IOException { writer.write(str); } }
The above interface still qualifies as a Java functional interface, since it contains a single non-implemented method.
As shown in the both of above examples, @FunctionalInterface annotation is used to ensure that the functional interface must not have more than one abstract method.
In case, if you attempt to add more than one abstract method in the Java functional interface, the compiler will output the “Unexpected @FunctionalInterface annotation” warning message.
However, it is an optional annotation and your code will work just fine without it but it is still a good practice to mention it.
A Java functional interface can also be implemented using a Java Lambda Expression. See this code snippet below that demonstrates the implementation of a Java functional interface MyFunctionalInterface03 using a Lambda expression.
See this code below:
@FunctionalInterface Import Math; interface SqrRoot { int calc(int num); } class DemoClass { public static void main(String args[]) { int n = 81; // This is the lambda expression to define the calculate method SqrRoot sr = (int num) -> Math.sqrt(num); float ans = sr.calc(n); System.out.println(ans); } }
A Java lambda expression is used here to implement a single method from a Java interface. To get to know what method is implemented by the lambda expression, the interface must be a Java functional interface, containing only a single abstract method.
Many Java interfaces have been converted into a Built-in Java functional interface since the introduction of functional interfaces. These reusable built-in interfaces offer some commonly used features of Java codes. There is a list of such built-in interfaces but they can be easily classified into the following types based on their functionality.
First on our list is The Java Consumer interface. It represents a method that takes a value as an argument but does not return any value, consuming the value thus the name, consumer. A Java Consumer implementation is only suitable when you have to just output a message on screen, or have to write it in a file.
Here is a code demonstration of the implementation of the Java Consumer interface:
Consumer<Integer> consumer = (num) -> System.out.println(num);
This Java Consumer implementation here prints the value (num) passed as parameter to it.
The Java Predicate interface represents a single method that takes a single value as a parameter and returns a Boolean value (TRUE or FALSE).
This is how the Predicate functional interface is defined:
public interface Predicate<T> { boolean test(T t); }
Predicate functional interface also offers some extensions such as IntPredicate, DoublePredicate, and LongPredicate. These types of predicate functional interfaces accept the respective primitive data types or values as arguments. The Bi-Predicate is also an extension that takes two arguments instead of one and returns the Boolean value.
The predicate Functional Interface can also be implemented using a class like this:
public class nullCheck implements Predicate { @Override public boolean test(Object obj) { return obj != null; } }
The Java Predicate interface can also be implemented using a Lambda expression. See this example of implementing the Predicate interface using a Java lambda expression. It does the same task as done above using a class.
See code below:
Predicate predicate = (val) -> val != null;
The Java UnaryOperator interface is a functional interface that represents an operation that takes a single parameter and returns a parameter of the same type.
Here is an example of a Java UnaryOperator implementation:
UnaryOperator<Person> unaryOperator = (person) -> { person.name = "New Name"; return person; };
The UnaryOperator interface can be used to represent an operation that takes a specific object as a parameter, modifies that object, and returns it.
The Java BinaryOperator interface is another functional interface that represents an operation that takes two parameters and returns a single value. Both parameters and the return type must be of the same type.
The Java BinaryOperator interface is quite useful when implementing functions for arithmetic operations such as sum, subtract, divide, multiply etc.
Here is an example implementation of the BinaryOperator interface:
BinaryOperator<MyValue> binaryOperator = (value1, value2) -> { value1.add(value2); return value1; };
The Java Function interface (java.util.function.Function) is considered the most important functional interfaces in Java. It contains a function that takes a single parameter and returns a value. It can be used for numerous applications in Java.
This is how the Function interface is defined:
public interface Function<T,R> { public <R> apply(T parameter); }
You can find different versions of Function interfaces because a primitive data type cannot imply a general type argument, so these function interfaces become quite useful.
All these different versions of the function interfaces are commonly used with primitive data types like int and double.
One such different versions are Bi-Function which takes two parameters contrary to a function interface that only accepts one argument.
See the syntax of the Bi-Function:
@FunctionalInterface public interface BiFunction<T, U, R> { R apply(T t, U u); }
Here, T and U are the inputs, and R is the returning value.
The Function interface can also be implemented using a Java lambda expression.
Function<Long, Long> mult2 = (num) -> num * 2; Long result = mult2.apply((long) 3); System.out.println("Output = " + result);
The Function interface implementation is also inlined here in the declaration of the mult2 variable instead of being in a separate class. This can make your code a bit shorter.
The above discussed two java functional interfaces can also be used with the Function interfaces. The UnaryOperator and BinaryOperator Interface can be used to extend the Function the Bi-Function interfaces, respectively.
See the syntax for extension with Unary Operator and Binary Operator below:
@FunctionalInterface public interface UnaryOperator<T> extends Function<T, U> { … }
@FunctionalInterface public interface BinaryOperator<T> extends BiFunction<T, U, R> { … }
The Supplier interface is the last Java functional interface on the list. It represents a method that passes no value as a parameter but returns a single value. It can also be considered a factory interface with very basic features.
See this demo implementation of the Java Supplier interface:
Supplier<Integer> supplier = () -> new Integer((int) (Math.random()*2);
This Java Supplier implementation returns a new Integer instance with a random even number.
We have discussed how a Java functional interface works and how to use it in your code. We also covered various types of built-in functions that are available in java.util.function Package.
Also Read: What Causes java.lang.reflect.InvocationTargetException?
The use of Java Lambda expressions and @FunctionalInterface Annotation in Java was also briefly covered. This was all about Java functional interface but you can also explore some built-in interfaces available and their working.
Shaharyar Lalani is a developer with a strong interest in business analysis, project management, and UX design. He writes and teaches extensively on themes current in the world of web and app development, especially in Java technology.
Create a free profile and find your next great opportunity.
Sign up and find a perfect match for your team.
Xperti vets skilled professionals with its unique talent-matching process.
Connect and engage with technology enthusiasts.
© Xperti.io All Rights Reserved
Privacy
Terms of use