Closures in Java

Java supports anonymous classes and lambda expressions, which can form closures. Anonymous functions are useful when you want to define a function inline without having to name it.

import java.util.function.Supplier;

public class Closures {

    // This method returns a Supplier<Integer>, which is similar to a function
    // that takes no arguments and returns an integer. The returned Supplier
    // closes over the variable i to form a closure.
    public static Supplier<Integer> intSeq() {
        final int[] i = {0};  // We use an array to hold a mutable int
        return () -> ++i[0];
    }

    public static void main(String[] args) {
        // We call intSeq, assigning the result (a Supplier<Integer>)
        // to nextInt. This Supplier captures its own i value, which
        // will be updated each time we call nextInt.get().
        Supplier<Integer> nextInt = intSeq();

        // See the effect of the closure by calling nextInt.get()
        // a few times.
        System.out.println(nextInt.get());
        System.out.println(nextInt.get());
        System.out.println(nextInt.get());

        // To confirm that the state is unique to that
        // particular Supplier, create and test a new one.
        Supplier<Integer> newInts = intSeq();
        System.out.println(newInts.get());
    }
}

When you run this program, you’ll see the following output:

1
2
3
1

In this Java version, we use a Supplier<Integer> to represent a function that takes no arguments and returns an integer. The intSeq() method returns a Supplier<Integer> that increments and returns a counter.

We use an array with a single element to hold our mutable integer because Java’s closure implementation requires local variables to be effectively final. By using an array, we can modify its content while keeping the reference to the array itself final.

The main method demonstrates how the closure works, showing that each Supplier maintains its own separate state.

The last feature of functions we’ll look at for now is method references and lambda expressions, which are Java’s closest equivalents to anonymous functions.