Java Functional Interface Example
In this post, we present a detailed article about Functional Interfaces in Java 8. Java functional interface has only one abstract method. The interface will have only one behavior.
Java 8 has lambda expressions. Lambda expression is used for functional interface instance. A java functional interface has many default methods. Runnable, Callable, ActionListener, Comparable, and FileFilter are good examples of Java functional interfaces.
You can also check this tutorial in the following video:
1. Introduction
Java was always Object-oriented language until Java 8 came up with functional interfaces. Functional programming is about breaking the complex functionality into smaller functions.
Table Of Contents
“Divide each difficulty into as many parts as is feasible and necessary to resolve it. ”
René Descartes
The quote above is in line with the java functional interface which helps in handling complex functionality in Java.
In an interface, the methods can have implementations. These methods are marked default. In an interface, you can have multiple default methods. A functional interface will have one abstract method. The interface can be annotated with Functional Interface annotation.
FunctionalInterfaceImpl
@java.lang.FunctionalInterface interface greeting{ public void greet(String message); int hashCode(); String toString(); boolean equals(Object obj); } public class FunctionalInterfaceImpl implements greeting{ public void greet(String message){ System.out.println("The Greeting is "+message); } public static void main(String[] args) { FunctionalInterfaceImpl finterface = new FunctionalInterfaceImpl(); finterface.greet("Good Morning"); } }}
Note that the interface has a single abstract method. The output of the executed command is shown below.
2. Java Functional Interface
In java, you would have used many interfaces that are functional or represent a behavior. For example, you would have used the Runnable
interface which is similar to java functional interface. The Runnable
interface has one method run which is an abstract method. The code below shows the implementation of Runnable
.
Calculator
/** * Calculator Class */ public class Calculator implements Runnable{ /** * Default Constructor */ public Calculator() { // TODO Auto-generated constructor stub } /** * run method */ public void run() { System.out.println("Running"); } /** * main method * @param args */ public static void main(String[] args) { Calculator calculator = new Calculator(); Thread thread = new Thread(calculator); thread.start(); } }
As shown in the code above, Thread
class is instantiated and Calculator
class instance is passed to the thread. Thread start method invokes the run method which is the function of the interface Runnable
. The output of the executed command is shown below.
Runnable
interface can be created as an anonymous class implemented. Thread
‘s instance can be created using the anonymous class as shown in the code below:
Anonymous Class Example
/** * Anonymous Example */ /** * @author bhagvan.kommadi * */ public class AnonymousExample { /** * Default Constructor */ public AnonymousExample() { } /** * main method * @param args */ public static void main(String[] args) { new Thread(new Runnable() { public void run() { System.out.println("Running"); } }).start(); } }
The output of the executed command in eclipse (Run as Java Application) is shown below.
Next sections talk about what is required for execution of the code in this tutorial.
2.1 Prerequisites
Java 8 is required on the Linux, Windows or Mac operating system. Eclipse Oxygen can be used for this example.
2.2 Download
You can download Java 8 from the Oracle web site . Eclipse Oxygen can be downloaded from the eclipse web site.
2.3 Setup
2.3.1 Java Setup
Below is the setup commands required for the Java Environment.
Setup
JAVA_HOME="/desktop/jdk1.8.0_73" export JAVA_HOME PATH=$JAVA_HOME/bin:$PATH export PATH
2.4 IDE
2.4.1 Eclipse Oxygen Setup
The ‘eclipse-java-oxygen-2-macosx-cocoa-x86_64.tar’ can be downloaded from the eclipse website. The tar file is opened by double click. The tar file is unzipped by using the archive utility. After unzipping, you will find the eclipse icon in the folder. You can move the eclipse icon from the folder to applications by dragging the icon.
2.4.2 Launching IDE
Eclipse has features related to language support, customization, and extension. You can click on the eclipse icon to launch eclipse. The eclipse screen pops up as shown in the screenshot below:
You can select the workspace from the screen which pops up. The attached image shows how it can be selected.
You can see the eclipse workbench on the screen. The attached screenshot shows the Eclipse project screen.
Java Hello World
class prints the greetings. The screenshot below is added to show the class and execution on the eclipse. (Run as Java Application is the command to execute the code)
3. Lambda Implementation
After seeing Functional interfaces in java, the next topic will be to see how lambda expressions simplify the code. Below is the example which shows the thread executing the runnable method run and starting the thread.
Lambda Example
/** * Lambda Thread */ public class LambdaThread { /** * Default Constructor */ public LambdaThread() { } /** * main method * @param args */ public static void main(String[] args) { new Thread(() -> System.out.println("running")).start(); } }
The above code in the main method creates an anonymous class implementing run method and starts the thread. The output of the executed command (Run as Java Application) is shown below.
4. Java Functional Interface Examples
java.util.function
package has the predefined functional interfaces. They can be categorized into the following categories:
- Predicates
- Functions
- Consumers
- Suppliers
4.1 Predicate
The java.util.function.Predicate
functional interface has an abstract method test. The method has the signature boolean test(T t)
. It is used to “test” an element if it satisfies certain predicate/criteria written inside the implementation of the method. The java.util.Stream.filter(Predicate predicate)
takes a Predicate
instance, as visible. We would use this for our demonstration.
4.1.1 Predicate Function
Mathematically, a predicate is a function that takes the input as a generic collection and returns the boolean value. The code below shows how predicated is used to filter a collection using Streams and a Predicate
function to pick from the list string which starts with a capital letter D.
ListStream
import java.util.stream.Collectors; import java.util.*; public class ListStream { /** * */ public ListStream() { // TODO Auto-generated constructor stub } /** * main method * @param args */ public static void main(String[] args) { List listStream = Arrays.asList("David", "Thomas", "Bill", "Eric", "Ford"); listStream.stream() .filter(list -> list.startsWith("D")) .collect(Collectors.toList()).forEach(System.out::println); } }
The output of the executed command (Run as Java Application) is shown below.
4.1.2 IntPredicate Function
Let us say, we have the business criteria/predicate, that we want to select all of the odd numbers between 1 to 5. With this predicate set, we can employ Predicate
as follows. Firstly we will see the anonymous implementation:
Integer Stream
/** * IntegerStream class */ import java.util.function.Predicate; import java.util.function.IntPredicate; import java.util.stream.IntStream; public class IntegerStream { public IntegerStream() { } public static void main(String[] args) { IntStream integerStream = IntStream.of(1,2,3,4,5); integerStream.filter(new IntPredicate() { @Override public boolean test(int value) { if(value%2 == 0) return false; return true; } }).forEach(System.out::println); } }
The output of the executed command (Run as Java Application) is shown below.
And now we would refactor the same behavior with lambdas. The sample code is shown below after refactoring the IntegerStream
class with the usage of lambdas.
Integer Stream Lambda
/** * IntegerStream Lambda Example */ import java.util.function.Predicate; import java.util.function.IntPredicate; import java.util.stream.IntStream; public class IntegerStreamLambda { /** * Default Constructor */ public IntegerStreamLambda() { } /** * main method * @param args */ public static void main(String[] args) { IntStream integerStream = IntStream.of(1,2,3,4,5); integerStream.filter(val -> { if (val % 2 == 0) return false; return true; }).forEach(System.out::println); } }
The output of the executed command (Run as Java Application) is shown below.
IntStream can be defined with range function. It is shown in the code below:
IntStream range
IntStream.range(1, 6);
Integer Stream class defined above can be simplified with filter method on IntStream as shown in the code below:
IntStream range
IntStream.range(1, 6).filter(i -> i % 2 != 0);
The above code finds the odd numbers in the stream of integers from 1 to 5. The IntegerStream
class can be refactored as below:
IntStream range
import java.util.stream.IntStream; public class IntegerStreamSimple { /** * main method * @param args */ public static void main(String[] args) { IntStream.range(1, 6).filter(i -> i % 2 != 0).forEach(System.out::println); } }
The output of the executed command (Run as Java Application) is shown below.
4.1.3 BiPredicate
java.util.function.BiPredicate
is the interface which has an abstract method test
. This method takes two arguments and returns a boolean result. Below is the code which checks if the strings are not equal.
BiPredicate
/** * BiPredicate Implementation */ import java.util.function.BiPredicate; public class BiPredicateImpl { /** * main method * @param args */ public static void main(String[] args) { BiPredicate biPredicate = (str1, str2) -> (!str1.equals(str2)); System.out.println(biPredicate.test("Check", "Check")); System.out.println(biPredicate.test("Check", "Check1")); } }
The output of the executed command (Run as Java Application) is shown below.
4.1.4 Double Predicate
java.util.function.DoublePredicate
is a predicate that takes double value as input and returns boolean. The code below shows the double predicate function which checks if a double value is greater than 2.
Double Predicate
import java.util.function.DoublePredicate; public class DoublePredicateImpl { public static void main(String[] args) { DoublePredicate doublePredicate = (d) -> d > 2; System.out.println(doublePredicate.test(2.56)); System.out.println(doublePredicate.test(1.56)); } }
The output of the executed command (Run as Java Application) is shown below.
4.1.5 LongPredicate
java.util.function.LongPredicate
is a predicate that takes long value as input and returns boolean. The code below shows the long predicate function which checks if a long value is greater than 4.
Long Predicate
import java.util.function.LongPredicate; public class LongPredicateImpl { public static void main(String[] args) { LongPredicate longPredicate = (l) -> l>4; System.out.println(longPredicate.test(Long.MAX_VALUE)); System.out.println(longPredicate.test(Long.MIN_VALUE)); } }
The output of the executed command (Run as Java Application) is shown below.
4.2 Function
The java.util.function.Function
interface is a functional interface that “maps” the input argument into some other generic type R. The interface has the following methods:
apply
compose
andThen
4.2.1 apply method
If the given input argument is of generic type T, apply (T t)
method creates a result of generic type R. The example below shows how the input string is changed to an integer within the map function. The code below shows how the string list is transformed to a list of integers using the map function.
Map Function
import java.util.*; public class IntegerListMapFunction { public static void main(String[] args) { List stringList = Arrays.asList("4","5","6"); stringList.stream() .map(integer -> Integer.parseInt(integer)) .forEach(stringInteger -> System.out.println("String changed to integer: "+stringInteger)); } }
The output of the executed command (Run as Java Application) is shown below.
The code below helps to understand how the map function is handled internally by creating an anonymous Function with a method apply
. The method apply parses the string as an integer.
Map Function – Anonymous
import java.util.*; import java.util.function.*; public class IntegerListMapAnonymousFunction { public static void main(String[] args) { List stringList = Arrays.asList("4","5","6"); stringList.stream() .map(new Function () { @Override public Integer apply(Object string) { return Integer.parseInt(String.valueOf(string)); } }).forEach(stringInteger -> System.out.println("parsed integer: "+stringInteger)); } }
The output of the executed command (Run as Java Application) is shown below.
4.2.2 compose method
If the given input argument is of java.util.function.Function
type, compose (Function)
method creates a result which is a function. The code below shows how an integer is changed to a percentage format.
Compose Method
import java.util.function.*; public class ComposeFunction { public static void main(String[] args) { Function intToString = Object::toString; Function perc = str -> str + "%"; Function addPercentage = perc.compose(intToString); System.out.println(addPercentage.apply(6)); } }
The output of the executed command (Run as Java Application) is shown below.
The method and constructor references can be used to specify the function. In the code above, Function intToString = Object::toString; Object toString method is specified. The other examples are listed below:
- System::getProperty
- System.out::println
- “checkString”::length
- List<String>::new
- double[]::new
- ………..
4.2.3 andThen method
If the given input argument is of java.util.function.Function
type, andThen (Function)
method creates a result which is a function. The code below shows how a product is then added to an integer.
And Then method
import java.util.function.*; public class AndThenFunction { public static void main(String[] args) { Function product = (value) -> value * 4; Function sum = (value) -> value + 5; Function productThenSum = product.andThen(sum); Integer result = productThenSum.apply(6); System.out.println(result); } }
The output of the executed command (Run as Java Application) is shown below.
4.3 Primitive Function Specializations
To handle primitives and the combinations of primitive transformations, the functions below are part of the java.util.function package.
IntFunction
,LongFunction
,DoubleFunction
ToIntFunction
,ToLongFunction
,ToDoubleFunction
DoubleToIntFunction
,DoubleToLongFunction
,IntToDoubleFunction
,IntToLongFunction
,LongToIntFunction
,LongToDoubleFunction
You can have your own transformation functions. for example, you can write your own shortToDouble function. Let us look at an example for IntToDoubleFunction
below:
IntToDouble Function
import java.util.function.IntToDoubleFunction; public class IntegerToDoubleTransform { public static void main(String[] args) { IntToDoubleFunction intToDoubFunction = (val) -> { return Math.cos(val);}; System.out.println( intToDoubFunction.applyAsDouble(1)); } }
The output of the executed command (Run as Java Application) is shown below.
As shown in the above, each of the primitive combinations can be created and executed by using the applyAs (the appropriate type).
4.4 Lambdas with 2 arguments
java.util.function.BiFunction
is a function that takes two arguments and returns a result. It is a function with two-arity specialization. “Bi” keyword is used to handle transformations like int, double and long. The functions which are used with “Bi” keyword are listed below:
BiFunction
ToDoubleBiFunction
ToIntBiFunction
ToLongBiFunction
The return type of a BiFunction
is a generified type. The other Functions (ToDoubleBi, ToIntBi,…) returns a primitive typed value. BiFunction has two methods apply and andThen.
The code below shows how lambda expressions are implemented. Sum and product of two integers are executed as lambda expressions representing BiFunction.
Lambda Expressions with two arguments
public class LambdaWithTwoExample { interface FuncExpr { int execute(int x, int y); } private int executor(int x, int y, FuncExpr fexpr) { return fexpr.execute(x, y); } public static void main(String[] args) { FuncExpr sum = (int x1, int x2) -> x1 + x2; FuncExpr product = (int x1, int x2) -> x1 * x2; LambdaWithTwoExample example = new LambdaWithTwoExample(); System.out.println("Sum is " + example.executor(9, 4, sum)); System.out.println("Product is " + example.executor(7,3, product)); } }
The output of the executed command (Run as Java Application) is shown below.
4.5 Supplier
The java.util.function.Supplier
interface is another functional interface which does not take input. It is used for lazy calculation of values. For example, you have a function that finds the random value. It will not get the value itself but this value’s supplier. The code below shows the supplier representation using lambda.
Supplier Example
import java.util.function.Supplier; public class SupplierExample { public static void main(String[] args) { Supplier randomValue = () -> Math.random(); System.out.println(randomValue.get()); } }
The output of the executed command (Run as Java Application) is shown below.
4.6 Consumer
The java.util.function.Consumer
takes a generified input and returns nothing. It is a function that represents the side effects. For example, you want to wish a group of people by welcoming them. Lambda function takes the person’s name and welcomes each person. The code below shows the consumer functional interface used for representing the lambda function.
Consumer Example
import java.util.function.Consumer; public class ConsumerExample { public static void main(String[] args) { Consumer consumer = (str) -> System.out.println(str.toUpperCase()); consumer.accept("abcdefghij"); } }
The output of the executed command (Run as Java Application) is shown below.
5. Conclusion
Functional Interfaces are the first-class citizens representing functionality in the object-oriented world of Java. They represent single functionality which they encapsulate. They make it easy to pass functionality or behavior instead of objects in method calls.
6. Download the Source Code
You can download the full source code of this example here: Java Functional Interface Example
Last updated on Nov. 28th, 2019