Functional Interface

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:

Java Functional Interface
Java Functional Interfaces

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.

 

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.

Java Functional Interface - Impl
Functional Interface Impl

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.

Java Functional Interface - Calculator Running
Calculator Running

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.

Java Functional Interface - Anonymous Implementation
Anonymous Implementation

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:

Java Functional Interface - Launching IDE
Launching IDE

You can select the workspace from the screen which pops up. The attached image shows how it can be selected.

Java Functional Interface - IntelliJ vs Eclipse
Eclipse Workspace

You can see the eclipse workbench on the screen. The attached screenshot shows the Eclipse project screen.

Java Functional Interface - Eclipse Workbench
Eclipse Workbench

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)

Java Functional Interface - Java Hello
Java HelloWorld

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.

Lambda Thread example

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.

Predicate Function

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.

IntegerStream

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.

Integer Stream with Lambda

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.

IntStream range

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.

String Comparison

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.

Double Predicate Example

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.

Long Predicate Example

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:

  1. apply
  2. compose
  3. 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.

Map function

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.

Map function – Anonymous

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.

Compose Function

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.

AndThen example

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.

  • IntFunctionLongFunctionDoubleFunction
  • ToIntFunctionToLongFunctionToDoubleFunction
  • DoubleToIntFunctionDoubleToLongFunctionIntToDoubleFunctionIntToLongFunctionLongToIntFunctionLongToDoubleFunction

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.

IntToDoubleFunction

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.

Lambda with two arguments

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.

Supplier Example

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.

ConsumerExample

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

Download
You can download the full source code of this example here: Java Functional Interface Example

Last updated on Nov. 28th, 2019

Bhagvan Kommadi

Bhagvan Kommadi is the Founder of Architect Corner & has around 20 years’ experience in the industry, ranging from large scale enterprise development to helping incubate software product start-ups. He has done Masters in Industrial Systems Engineering at Georgia Institute of Technology (1997) and Bachelors in Aerospace Engineering from Indian Institute of Technology, Madras (1993). He is member of IFX forum,Oracle JCP and participant in Java Community Process. He founded Quantica Computacao, the first quantum computing startup in India. Markets and Markets have positioned Quantica Computacao in ‘Emerging Companies’ section of Quantum Computing quadrants. Bhagvan has engineered and developed simulators and tools in the area of quantum technology using IBM Q, Microsoft Q# and Google QScript. He has reviewed the Manning book titled : "Machine Learning with TensorFlow”. He is also the author of Packt Publishing book - "Hands-On Data Structures and Algorithms with Go".He is member of IFX forum,Oracle JCP and participant in Java Community Process. He is member of the MIT Technology Review Global Panel.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button