Cogs and Levers A blog full of technical stuff

Getting functional with Java 8

Java 8 provides developers with functional programming facilities that are very new to the language itself.

In today’s post, I’ll go through a primer of the different facilities that you can use.

Functional Interfaces

Single abstract method interfaces have been taken a step further in Java 8, where the programmer is able to decorate their interface using a @FunctionalInterface annotation. These can then be represented as lambda expressions and method references. These are building blocks for functional programming.

Consumer<T>

Represents an operation that accepts a single input argument and returns no result. Unlike most other functional interfaces, Consumer is expected to operate via side-effects.

Uses are passing to the forEach function.

Supplier<T>

This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

Used in the creation of streams.

Predicate<T>

This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

Used with filter

Function<T, R>

This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.

Used to pass to map

Functional Syntax

Defining a Functional Interface

@FunctionalInterface
public interface TailCall<T> {
  
  TailCall<T> apply();

  default boolean isComplete() { return false; }

}

A functional interface must:

  • Have one abstract, unimplemented method
  • May have zero or more default or implemented methods
  • May have static methods

Lambda expressions

// no parameters
() -> func(1)

// explicit definition of parameter types
(final String colour) -> System.out.println(colour)

// implicit parameter definition
(colour) -> System.out.println(colour)
colour -> System.out.println(colour)

// multiples
(x, y) -> x * y

// multi-line lambda
(x) -> {
  func1(x);
  func2(x);
}

Composition, method references

products.stream()
        .filter(Pricing::hasDiscount)
        .mapToDouble(Product::getUnitPrice)
        .average()
        .getAsDouble();