How to use Java 8 Function and BiFunction Interface?

With all the other enhancements in Java 8 a new package java.util.function is also added to the Java library. In this post, we will discuss how to use the Function and BiFunction interface with examples. Both the interface are functional interface.

Function Interface Syntax

@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;
    }
}

Salient Points of Function interface

  • It has been defined with the generic types T & R, where T is the type of the input and R is the output type.
  • Method apply() is the functional method (only abstract method in a functional interface). It takes an input t of type T and returns an output of type R.
  • It has two default method.
  • The first default method compose()  Returns a composed function that first applies the function to its input, and then applies this function to the result. If the evaluation of either function throws an exception, it is relayed to the caller of the composed function. In simple words, a composed function that first applies the before function and then applies its own function to the result of before.
  • The second default method is andThen() is inverse of the compose function. It is a composed function that first applies its own function to the input and then applies the after function to the result.
  • Function interface has one static method identity() which returns a function that always returns its input argument.

BiFunction Interface

@FunctionalInterface
public interface BiFunction<T, U, R> {
    R apply(T t, U u);

    default <V> BiFunction<T, U, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t, U u) -> after.apply(apply(t, u));
    }
}

Salient Points of BiFunction interface

  • It has been defined with the generic types T, U & R, where T and U are the types of the first and second input and R is the output type.
  • Method apply() is the functional method that applies this function to the given input T and U and returns the output of Type R.
  • The default method andThen() is a composed function that first applies its own function to the input and then applies the after function to result.

Example

In this example, we will use a class Product to demonstrate the Function interface.

class Product{
	private int id;
	private String name;
	private String desc;
	
	public Product(int id, String name, String desc) {
		super();
		this.id = id;
		this.name = name;
		this.desc = desc;
	}

	@Override
	public String toString() {
		return "Product [id=" + id + ", name=" + name + ", desc=" + desc + "]";
	}

	public int getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	public String getDesc() {
		return desc;
	}

	public void setName(String name) {
		this.name = name;
	}
	
} 

Function Interface apply method

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

public class FunctionDemo {
	static List<Product> products = new ArrayList<>();	
	
	static Function<Product, String> getProductNameFunction = Product::getName;
		
	public static void main(String[] args) {
		prepareData();
		List<String> productNames = new ArrayList<>(); 
		products.forEach(p ->{
			productNames.add(getProductNameFunction.apply(p));
		});
		System.out.println("productNames => "+productNames);		
	}

	static void prepareData() {
		for(int i =1 ; i<= 10; i++) {
			products.add(new Product(i, "product name "+i, "product desc "+i));
		}
	}
}

In the above code snippet, we have created a list of Products and a Function getProductNameFunction which will convert the list of Products into a list of String containing product names.

Function Interface compose method

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.function.Function;

public class FunctionDemo {
	static List<Product> products = new ArrayList<>();	
	
	static Function<Product, String> getProductNameFunction = Product::getName;
	
	static Function<Product, Product> composeBeforeFunction = (Product p)->{
		String name = p.getName().replace(" ", " "+new Random().nextInt());
		p.setName(name);
		return p;
	};
		
	public static void main(String[] args) {
		prepareData();
		
		List<String> productNames = new ArrayList<>(); 
		products.forEach(p ->{
			productNames.add(getProductNameFunction.compose(composeBeforeFunction).apply(p));
		});
		System.out.println("productNames => "+productNames);		
	}

	static void prepareData() {
		for(int i =1 ; i<= 10; i++) {
			products.add(new Product(i, "product "+i, "product desc "+i));
		}
	}
}

Here we have created a list of products and a new Function composeBeforeFunction and we also use getProductNameFunction from apply example. Here when we run this code snippet as per the description of compose() method composeBeforeFunction will apply and it will add a random string to the product name and then the getProductNameFunction will be applied which will return a list of the product name.

Function Interface andThen method

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

public class FunctionDemo {
	static List<Product> products = new ArrayList<>();	
	
	static Function<Product, String> getProductNameFunction = Product::getName;
	
	static Function<String, String> andThenFunction = (String s)-> s.substring(s.length()-1,s.length());
	
	public static void main(String[] args) {
		prepareData();
		
		List<String> productNames = new ArrayList<>(); 
		
		products.forEach(p ->
			productNames.add(getProductNameFunction.andThen(andThenFunction).apply(p))
		);
		
		System.out.println("productNames => "+productNames);		
	}

	static void prepareData() {
		for(int i =1 ; i<= 10; i++) {
			products.add(new Product(i, "product "+i, "product desc "+i));
		}
	}
}

In this example, we have created a list of products and a new Function andThenFunction also we have used getProductNameFunction from apply example. Here when we run this code snippet as per the description of andThen() method getProductNameFunction will apply first and then the andThenFunction will be applied which will return a list of String only having the last char of the product name.

Function Interface identity method

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class FunctionDemo {
	static List<Product> products = new ArrayList<>();	
	
	public static void main(String[] args) {
		prepareData();
		
		Map<Integer, Product> productmap = products.stream()
				.collect(Collectors.toMap(Product::getId, Function.identity()));
		
		System.out.println("productmap => "+productmap);		
	}

	static void prepareData() {
		for(int i =1 ; i<= 10; i++) {
			products.add(new Product(i, "product "+i, "product desc "+i));
		}
	}
}

In this example, we have converted the list of products into a Map of using the identity() method.

If we haven’t used the identity() method to create a Map we have to use the other way like below.

Map<Integer, Product> productmapWithForeach = new HashMap<>();
		
products.forEach(product -> productmapWithForeach.put(product.getId(),
 product));

BiFunction apply method

public class FunctionDemo {	
		
	public static void main(String[] args) {
				
		 BiFunction<Integer, Integer, Integer> addFunction = (t, u) -> t + u;
		 
		 int sum = addFunction.apply(10, 20);
	 
		 System.out.println("sum is => +sum");

		
	}
}

Conclusion

In this post, we have discussed Function and BiFunction Interface and how can we use these functions to write more concise and clean code.

Recommended Read

Java 8 Method Reference
Java 8 Stream API
Java 8 comparison using Lambda

Happy Learning !!

Leave a Comment