Profile Photo

Function interface in java 8

Created on: Oct 1, 2024

Functional programming is a paradigm that allow programming using expression. We can declare, pass function as argument, statement.

Below are four main functional program introduced in java 8.

  1. Consumer
  2. Predicate
  3. Supplier
  4. Function

Let's understand each of them using example.

1. Consumer

It is a built in package in java.util.function package. This takes a input value and return nothing.

// syntex public interface Consumer<T> { void accept(T t); default Consumer<T> andThen(Consumer<? super T> after) }
class User { private String name; private String email; public User(String name, String email) { this.name = name; this.email = email; } public String getName() { return name; } public String getEmail() { return email; } } class NotificationService { public static void main(String[] args) { List<User> users = Arrays.asList( new User("John", "john@example.com"), new User("Alice", "alice@example.com"), new User("Bob", "bob@example.com") ); Consumer<User> sendNotification = new Consumer<User>() { @Override public void accept(User user) { System.out.println("Sending notification to " + user.getName() + " at " + user.getEmail()); } }; users.forEach(sendNotification); } }
Sending notification to John at john@example.com Sending notification to Alice at alice@example.com Sending notification to Bob at bob@example.com

In the above example, we can change the sendNotification part with lambda expression as follows and the result will be same.

Consumer<User> sendNotification = user -> System.out.println("Sending notification to " + user.getName() + " at " + user.getEmail());

Real usage of Consumer in collection frameworks

  1. forEach uses Consumer in stream api.
public interface Stream<T> extends BaseStream<T, Stream<T>> { void forEach(Consumer<? super T> action); }
  1. forEach in map uses Biconsumer to parse the map. Below is syntex.
public interface Map<K, V> { default void forEach(BiConsumer<? super K, ? super V> action) }
public class Hello { public static void main(String[] args) { Map<String, Integer> ageMap = new HashMap<>(); ageMap.put("Alice", 25); ageMap.put("Bob", 30); ageMap.put("Charlie", 35); ageMap.forEach((key, value) -> System.out.println(key + " is " + value + " years old")); } }

2. Predicate

A Predicate is a functional interface, which accepts an argument and returns a boolean. Usually, it is used to apply in a filter for a collection of objects.

Main method in predicate functional interface.

boolean test(T value); default Predicate<T> and(Predicate<? super T> other); default Predicate<T> negate(); default Predicate<T> or(Predicate<? super T> other); static <T> Predicate<T> isEqual(Object targetRef); static <T> Predicate<T> not(Predicate<? super T> target);

Sample program to filter city

import java.util.List; import java.util.ArrayList; import java.util.function.Predicate; public class Hello { public static void main(String[] args) { List<String> cities = new ArrayList<>(); cities.add("Delhi"); cities.add("Mumbai"); cities.add("Goa"); cities.add("Pune"); Predicate<String> cityFilter = new Predicate<String>() { @Override public boolean test(String s) { return s.equalsIgnoreCase("Mumbai"); } }; String city = cities.stream().filter(cityFilter).findFirst().get(); System.out.println(city); } }

In above case we can change cityFilter in lambda expression.

Predicate<String> cityFilter = s-> s.equalsIgnoreCase("Mumbai");

3. Function

A Function is another in-build functional interface in java.util.function package, the function takes an input value and returns a value. Below are main method in Function interface.

R apply(T var1); default <V> Function<V, R> compose(Function<V, T> before); default <V> Function<T, V> andThen(Function<R, V> after); static <T> Function<T, T> identity();

Given a list of city, print the first letter of each city in a list

import java.util.List; import java.util.ArrayList; import java.util.function.Function; import java.util.stream.Collectors; public class Hello { public static void main(String[] args) { List<String> cities = new ArrayList<>(); cities.add("Delhi"); cities.add("Mumbai"); cities.add("Goa"); cities.add("Pune"); Function<String, Character> function = new Function<String, Character>() { @Override public Character apply(String s) { return s.charAt(0); } }; List<Character> characterList = cities.stream().map(function).collect(Collectors.toList()); System.out.println(characterList); } }

Supplier

It does not take any input but produce a value.

import java.util.List; import java.util.function.Supplier; import java.util.stream.Collectors; public class Hello { public static void main(String[] args) { Supplier<List<String>> supplier = new Supplier<List<String>>() { @Override public List<String> get() { return List.of("Delhi", "Mumbai", "Goa", "Pune"); } }; List<String> cities = supplier.get().stream().collect(Collectors.toList()); System.out.println(cities); } }