Java 8 – Functional Interfaces

Functional Interfaces is one of the new important things of Java 8. In previous article, we had a little view about common use cases of Lambda Expression including Runnable and ActionListener. They are example of Functional Interfaces.

This tutorial helps you have deeper concept of Functional Interface, then some interfaces which are provided in java.util.function package such as Predicate and Function.

I. Functional Interfaces

An interface with only one abstract method inside is Functional Interface.

public interface MyFuncInterface {
	void doWork();
}

We add @FunctionalInterface annotation to annotate that an interface is Functional Interface. It can be used for making compiler errors when the interface is not a valid Functional Interface.
For example, when we have more than one abstract method inside, it throws a compiler error:

@FunctionalInterface
public interface MyFuncInterface {
	void doWork();
	void doAnotherWork();
}

Invalid '@FunctionalInterface' annotation; MyFuncInterface is not a functional interface
So, we can apply them simply:

@FunctionalInterface
public interface MyFuncInterface {
	void doWork();
}

public class MainApp {
	
	public static void executeFunction(MyFuncInterface func) {
		func.doWork();
	}

	public static void main(String[] args) {
		executeFunction(new MyFuncInterface() {
			
			@Override
			public void doWork() {
				System.out.println("invoke Function using Anonymous Inner Class");
			}
		});
		
		// with Lambda Expression
		executeFunction(() -> System.out.println("invoke Function using Lambda Expression"));
	}
}

For Functional Interface with only one method, we can make code lean and beautiful with Lambda Expression, it seem like that we pass a method as argument to a function. It is the convenience when using that kind of interface – take advantage of Java 8 Lambda Expression.

In previous article: Java 8 – Lambda Expressions, we have apply Lambda Expression for two Java Functional Interfaces:
Runnable with single abstract method run()
ActionListener with single abstract method actionPerformed(…)

		// Lambda Runnable
		Runnable r2 = () -> System.out.println("Hello world!");

		// Listener Lambda
		JButton testButton = new JButton("Test Button");
		testButton.addActionListener(e -> System.out.println("Lambda Listner Detected"));
II. java.util.function Package

Java 8 provides the java.util.function package with a number of standard functional interfaces which are designed as a starter set for developers, these are some of them:
Predicate<T>: Represents a predicate (boolean-valued function) of one argument, functional method: test(Object).
Consumer<T>: Represents an operation that accepts a single input argument and returns no result, functional method: accept(Object).
Function<T,R>: Represents a function that accepts one argument and produces a result, functional method: apply(Object).
Supplier<T>: Provides an instance of a T (such as a factory), functional method: get().

This tutorial introduces 2 functional interfaces: Predicate and Function.

1. Predicate

Predicate interface has method test(Object) to return a boolean value. The idea for this functional interface is that an object is tested to be true or false.

@FunctionalInterface
public interface Predicate {
    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}

We use Predicate<T> interface to check if a number in list is suitable for specific condition by method test(T t), and the function checkList receive Predicate<Integer> object as an input parameter:

    public static void checkList(List list, Predicate predicate) {
        for (Integer i : list) {
            if (predicate.test(i)) {
                System.out.print(i + " ");
            }
        }
    }

Lambda expression is used to assign method operation to Predicate object or just as an input parameter:

    List list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9);
		
    System.out.println("Display all numbers > 5 in list");
    Predicate predicate = i -> i > 5;
    checkList(list, predicate);

    System.out.println("\nDisplay all numbers < 5 in list");
    checkList(list, i -> i < 5);

Run these statement, we will have the result:

Display all numbers > 5 in list:
6 7 8 9 
Display all numbers < 5 in list:
1 2 3 4 
2. Function

Function<T,R> interface takes a generic class T and returns a generic class R by the method apply(T t);

@FunctionalInterface
public interface Function {
    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
}

To be clear, look at the example below.
This is Customer class:

public class Customer {
	private String firstName;
	private String lastName;

	public Customer(String firstName, String lastName) {
		this.firstName = firstName;
		this.lastName = lastName;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	@Override
	public String toString() {
		return String.format("Customer[firstName='%s', lastName='%s']", firstName, lastName);
	}

	public String printName(Function f) {
		return f.apply(this);
	}
}

To make the print method more flexible than toString() with the modified printing function input, we have this method:

	public String printName(Function f) {
		return f.apply(this);
	}

A Function f will be passed to the method and a String will be returned corresponding to Customer. The method apply processes a lambda expression which determines what kind of Customer information is returned.

This is the testing code:

    System.out.println("\n=== Test Function ===");
    List customers = new ArrayList<>();
    customers.add(new Customer("Jack", "Smith"));
    customers.add(new Customer("Adam", "Johnson"));

    Function displayFullName = customer -> {
        return customer.getFirstName() + " " + customer.getLastName();
    };

    for (Customer customer : customers) {
        System.out.println(customer.printName(displayFullName));
    }

    System.out.println("=== Uppercase FirstName ===");
    for (Customer customer : customers) {
        System.out.println(customer.printName(c -> {
            return c.getFirstName().toUpperCase();
        }));
    }

And the result in Console Window:

=== Test Function ===
Jack Smith
Adam Johnson
=== Uppercase FirstName ===
JACK
ADAM
III. Source code

Technology:
- Java 8
- Eclipse Mars.1 Release (4.5.1)
funtionalinterface



By grokonez | October 21, 2016.

Last updated on June 4, 2017.



Related Posts


Got Something To Say:

Your email address will not be published. Required fields are marked *

*