Java 8 categories of functional interfaces

Java 8 functional interface categories

We already talked about Java functional interfaces in the following article, which I recommend you read, before this article:

Now I would like to talk to you about the various categories of functional interfaces most used and known.

Briefly repeating what has already been said in the other article, a functional interface is an interface with only one abstract method.
We can find many functional interfaces in java.util.function package.

In “java.util.function” we have:

  • Suppliers: its functional method get() never takes an argument and it always returns something.
  • Consumers: its functional method accept() always takes an argument and never returns anything.
  • Predicates: (to test) its functional method test() takes a value, does a logical test and returns tue or false (a boolean).
  • Functions: (the most generic) its functional method apply() takes an argument and returns a value (with a sub-category, the Operators).

Using Suppliers – functional interfaces

The Supplier method returns ever something, even if you don’t need anything.

Supplier<Integer> answerSupplier = () -> 42;

Its declaration:

public interface Supplier<T> {
  public T get();

There are more specific suppliers for autoboxing: IntSupplier, DoubleSupplier, LongSupplier, to avoid autoboxing if you want a primitive.

An example is the new log() method in Logger that get in like arguments a status and a Supplier<String>. With this overloaded method we can, for instance, do an heavy operation (an url connection) only when need that status log (the logger level is set on that level).

Logger logger = Logger.getLogger("Status log");
logger.setLevel(Level.SEVER); // log level
Supplier<String> status = () -> {
  int timeout = 1000;
  try (Socket socket = new Socket()) {
    socket.connect(new IntSocketAddress("", 80, timeout);
    return "up";
  } catch (IOException e) {
    return "down";
try {
  logger.log(Level.INFO, status); // only calls get() when level is INFO
} catch (Exception e) {
  logger.log(Level.SEVERE, status);

Using Consumers

It’s the opposite of Supplier, it accepts an input parameter and never returns anything.

Its declaration:

public interface Consumer<T> {
  public void accept(T t);

With an accept() method that can take one argument, like an object, or a primitive with: IntConsumer, DoubleConsumer, LongConsumer.

There also ObjIntConsumer, ObjDoubleConsumer, and ObjLongConsumer for objects and primitives.

We have also BiConsumer that get two arguments, userful for maps.

There is a forEach() Java 8 method added to Iterable interface (an interface of lists) that takes a Consumer like argument.

List<String> potterNames = Arrays.asList("Harry", "James", "Lily");
potterNames.forEach(name -> System.out.println(name));

We know that we can’t modify variables from external of a lambda expression but we can cheat and modify only an attribute of those objects. This can be did.

Map<String, String> env = System.getenv();
User user = new User();
BiConsumer<String, String> findUsername = (key, value) -> {
if (key.equals("USER")) user.setUsername(value);

Another method that can be used with consumers is andThen(), a default method on Consumer.

Consumer<Potter> displayName = p -> System.out.println(p);
    p -> p.doPatronus();

We must declare first the consumer to attach to it the andThen() method! We can’t do:

(p -> p).andThen(...); // not compiles!

And we can’t chain a Consumer with a BiConsumer and viceversa.

Using Predicates

It’s a generic functional interface that takes something and returns a boolean, testing it.

It functional method is test().
Its declaration:

public interface Predicate {
  public boolean test();

One simply example:

Predicate<Potter> p = p -> p.getAge() >= 11;

Tests if a Potter is older or equals than 11 and can go to the Hogwarts school.

Potter harry = new Potter("Harry", 11);
p.test(harry); // true

A JDK method removeIf() of ArrayList takes a Predicate.

There are some default methods: and(), or(), negate() to chain predicates:

Predicate<Potter> name = p -> p.getName().equals("James");
Predicate<Potter> age = p -> p.getAge() == 11;

Using it:

Predicate<Potter> nameAndAge = p -> name.and(age).test(p);
// or, more concise:
Predicate<Potter> nameAndAge = name.and(age);

There are also DoublePredicate, IntPredicate, LongPredicate to avoid autoboxing and BiPredicate to take two arguments.

Using Functions

It’s a generic functional interface that takes an argument of a type and returns something of another type.

Its declaration:

public interface Function<T, R> {
  public R apply(T t);

It has a functional method apply().

An example to change a numbe to string:

Function<Integer, String> horcruxNumber = h -> {
  if (a == 7) return "seven horcruxes";

There is also a BiFunction that takes two arguments and returns one (type of) value.

BiFunction<String, String, String> nameSurname =
    (name, surname) -> name + " " + surname;

In JDK we can find two examples of these functions: map.computerIfAbsent() and map.replaceAll():

Map<String, String> map = new TreeMap<>();
// put on map...
// check if a key exists and, if not, run a lambda:
map.computeIfAbsent("aKey", k -> "a value"); // a very simple lambda
map.replaceAll((key, oldValue) -> oldValue.toUppeCase()); // BiFunction

The other default and static functions are: andThen() (to chain Functions, like the Consumer’s andThen()), identity() and compose().

compose() is the same of andThen() except it run functions in reverse order and identity() returns only the input value. It’s a “do nothing” method.

Function<Integer, Integer> id = Fucntion.identity();
id.apply(42); // returns 42

There are many other variations of Function: DoubleToIntFunction, DoubleToLongFunction, …, LongToIntFunction, ToIntFunction, ToIntBiFunction, …and others.

They have a variation of first apply() method. For instance, IntToDoubleFunction has applyAsDouble() method.

Using Operators

The most famous Operator that we can know is the UnaryOperator. Operators extend Function but UnaryOperator has only a type.

Its declaration:

public interface UnaryOperator<T> extends Function<T, T>

An example of its use may be a mathematical operation:

UnaryOperator<Double log2 = v -> Math.log(v) / Math.log(2);

Writing Java functional interfaces

Obviously we can create functional interfaces from us.
An example would be a Predicate that accepts 3 arguments.

public interface TriPredicate<T, U, V> {
  boolean test(T t, U u, V v);

And we would use it as we normally use any other functional interface:

(s, n, w) -> {
  return s != null && s.equals(n) && s.equals(w);

That’s all on categories of Java functional interfaces.

Try it at home!

1 person likes this.
Please wait...

9 thoughts on...
  1. Way cool! Some extremely valid points! I appreciate you penning this post plus the rest of the site is also really good. Noni Agustin Sharma

  2. Excellent article. Keep posting such kind of information on your page. Lelah Hewie Birch

  3. I really like your article. Thanks for writing this. Averyl Merv Hachmann

  4. Excellent post! We will be linking to this great post on our site. Keep up the great writing. Katharina Chucho Lynett

  5. Howdy! I simply would like to give you a big thumbs up for the great info you have here on this post. I am coming back to your web site for more soon. Dulce Pren Desta

  6. We are will rapidly as well as effectively generate a guarantee Premium remodelling manhattan. Marianna Josias Heshum

Leave a Reply

Thanks for choosing to leave a comment.
Please keep in mind that all comments are moderated according to our comment policy, and your email address will NOT be published.
Please do NOT use keywords in the name field. Let's have a personal and meaningful conversation.