8.3.  Use built-in functional interfaces including Predicate, Consumer, Function, and Supplier

[Note]

Develop code that uses the Function interface

A java.util.function.Function is a Java 8 functional interface whose sole purpose is to return any result by working on a single input argument. It accepts an argument of type T and returns a result of type R, by applying specified logic on the input via the apply method. The interface definition shown here:


package java.util.function;

@FunctionalInterface
public interface Function<T extends Object, R extends Object> {

    public R apply(T t);

    ...

}

					

A Function interface is used in cases when you want to encapsulate some code into a method which accepts some value as an input parameter and then returns another value after performing required operations on the input. The input parameter type and the return type of the method can either be same or different:


Function<String, Boolean> f = s -> new Boolean(s);

System.out.println(f.apply("TRUE"));
System.out.println(f.apply("true"));
System.out.println(f.apply("Java8"));
System.out.println(f.apply(null));

					

Output:

true
true
false
false
					

Develop code that uses the Consumer interface

The java.util.function.Consumer<T> interface defines an abstract method named accept that takes an object of generic type T and returns no result (void):


package java.util.function;

@FunctionalInterface
public interface Consumer<T extends Object> {

    public void accept(T t);

    ...
}

					

You might use this interface when you need to access an object of type T and perform some operations on it. For example, you can use it to create a method processList, which takes a list of objects and applies an operation on each element of that list. In the following listing you use this processList method combined with a lambda to print all the elements of the list:


public class ConsumerDemo<T extends Object> {

    public void processList(List<T> list, Consumer<T> cons) {
        for(T s : list) {
            cons.accept(s);
        }
    }

    public static void main(String[] args) {
        List<String> l = Arrays.asList(new String[] {"Java", "8", "is", "great", "!"});
        Consumer<String> c = s -> System.out.print(String.format("%s ", s));
        new ConsumerDemo<String>().processList(l, c);
    }
}

					

output is:

Java 8 is great !
					

Develop code that uses the Supplier interface

The java.util.function.Supplier<T> is a functional interface in Java 8, with one abstract method named T get() that returns an instance of T. In other words, this is a factory that keeps on giving without expecting anything as input.


package java.util.function;

@FunctionalInterface
public interface Supplier<T extends Object> {

    public T get();

}
					

In the most basic form a Supplier will return an instance. For example, we could implement Supplier<Book> to return an instance of Book, like so:


public class Book {
    String title;
    String author;

    public Book(String t, String a) {
        title = t;
        author = a;
    }

    public String toString() {
        return title + " by " + author;
    }
}

...
...
Supplier<Book> s1 = () -> new Book("Upgrade to Java 8 Guide", "Mikalai Zaikin");
Supplier<Book> s2 = () -> { return new Book("Upgrade to Java 11 Guide", "Mikalai Zaikin"); };

System.out.println(s1.get());
System.out.println(s2.get());

					

output:

Upgrade to Java 8 Guide by Mikalai Zaikin
Upgrade to Java 11 Guide by Mikalai Zaikin
					

Alternatively, we could use a constructor reference (T::new) instead of the traditional (new T()) syntax to instantiate an instance. A constructor reference is much like a method reference, except it is a reference to a constructor instead of a method. We can use a constructor reference anywhere a lambda expression does nothing more than instantiate an instance. The only limitation with Supplier that constructor must take no arguments. For example:


public class Book {
    String title;
    String author;

    public Book() {
        title = "Default title";
        author = "Default author";
    }

    public String toString() {
        return title + " by " + author;
    }
}
...
...
Supplier<Book> s1 = Book::new;
System.out.println(s1.get());

					

output:

Default title by Default author
					

Develop code that uses the UnaryOperator interface

The java.util.function.UnaryOperator is a Java 8 functional interface that extends java.util.function.Function:


package java.util.function;

@FunctionalInterface
public interface UnaryOperator<T extends Object> extends Function<T, T> {

    ...

}

					

The UnaryOperator is used to work on a single operand and it returns the same type as an operand. UnaryOperator can be used as lambda expression to pass as an argument. While defining UnaryOperator, we need to define T apply(T t) method inherited from java.util.function.Function.


UnaryOperator<String> uo = s -> s + " is great !";
System.out.print(uo.apply("Java 11"));

					

output:

Java 11 is great !
					

Develop code that uses the Predicate interface

The java.util.function.Predicate<T> interface defines an abstract method named test(T t) that accepts an object of generic type T and returns a boolean primitive.


package java.util.function;

@FunctionalInterface
public interface Predicate<T extends Object> {

    public boolean test(T t);

    ...

}

					

You might want to use this interface when you need to represent a boolean expression that uses an object of type T. For example, you can define a lambda that accepts String objects, as shown in the following listing:


Predicate<String> longString = s -> s.length() > 5;

// Will print true
System.out.print(longString.test("Hi there !"));

					

Predicates may also be passed into functions:


Predicate<String> longString = s -> s.length() > 5;
validateString("Hello again !", longString);
...
...
void validateString(String s, Predicate<String> p) {
    if (p.test(s)) {
        System.out.print("Test passed !");
    }
}

					

Professional hosting         Exam 1Z0-817: Upgrade OCP Java 6, 7 & 8 to Java SE 11 Developer Quiz     Exam 1Z0-810: Upgrade to Java SE 8 Programmer Quiz