Search

June 10, 2020

Java Joy: Infinite Stream Of Values Or Method Invocations

In Java we can use the generate method of the Stream class to create an infinite stream of values. The values are coming from a Supplier instance we pass as argument to the generate method. The Supplier instance usually will be a lambda expression. To give back a fixed value we simply implement a Supplier that returns the value. We can also have different values when we use a method that returns a different value on each invocation, for example the randomUUID method of the UUID class. When we use such a method we can create the Supplier as method reference: UUID::randomUUID.

The generate method returns an unbounded stream. We must use methods like limit and takeWhile to get a bounded stream again. We must use findFirst or findAny to terminate the unbounded stream and get a value.

In the following example we use the generate method with a Supplier that returns a repeating fixed String value and some different values from invoking the now method of LocalTime:

package mrhaki.stream;

import java.time.LocalTime;
import java.util.List;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toUnmodifiableList;

public class Generate {
    
    public static void main(String[] args) {
        // Create a infinite stream where each item is the string value "Java".
        // We let the supplier function return a fixed value "Java".
        assert Stream.generate(() -> "Java")
                     .limit(4)
                     .collect(toUnmodifiableList()).equals(List.of("Java", "Java", "Java", "Java"));

        // Create an infinite stream of function invocations of LocalTime.now().
        // The supplier function returns a different value for each invocation.
        var currentTimes = Stream.generate(LocalTime::now)
                                 .limit(2)
                                 .collect(toUnmodifiableList());
        assert currentTimes.get(0).isBefore(currentTimes.get(1));

        // Create a list of 100 time values where each value should be later than the next.
        var timeSeries = Stream.generate(LocalTime::now).limit(100).collect(toUnmodifiableList());
        assert latestTime(timeSeries).equals(timeSeries.get(timeSeries.size() - 1));
    }

    /**
     * Get the latest time from a serie of time values.
     *
     * @param times List with time values.
     * @return Latest time value from the collection.
     */
    private static LocalTime latestTime(List<LocalTime> times) {
        return times.stream().reduce((acc, time) -> {
            if (acc.isAfter(time)) { return acc; } else { return time; }
        }).get();
    }
}

Written with Java 14.