Encounter Order and unordered()

Streams · lesson 35 of 42 · 4 min read

Which sources have an order, which ops must respect it, and what that costs in parallel.

Open this lesson in the learning hub

Key points

  • A List or an array has an encounter order. A HashSet does not, and never promises one.
  • findFirst, limit, skip and toList must honour it, so in parallel they need coordination.
  • forEach gives up ordering on a parallel stream. forEachOrdered keeps it, and pays for it.
  • unordered() says you do not care, letting distinct and limit skip the bookkeeping.
  • sorted() makes a stream ordered again, while toSet and groupingBy hand back unordered containers.

Example

import java.util.*;
import java.util.stream.*;

public class Main {
    public static void main(String[] args) {
        List<Integer> list = IntStream.rangeClosed(1, 8).boxed().toList();

        // Ordered terminal ops keep encounter order even in parallel.
        System.out.println("toList par     : " + list.parallelStream().map(n -> n * 2).toList());
        System.out.println("findFirst par  : "
                + list.parallelStream().filter(n -> n > 3).findFirst().orElseThrow());
        System.out.println("limit par      : " + list.parallelStream().limit(4).toList());

        // forEachOrdered keeps the order; plain forEach promises nothing in parallel.
        StringBuilder strict = new StringBuilder();
        list.parallelStream().forEachOrdered(strict::append);
        List<Integer> loose = Collections.synchronizedList(new ArrayList<>());
        list.parallelStream().forEach(loose::add);
        System.out.println("forEachOrdered : " + strict);
        System.out.println("forEach par    : " + loose + "   (order not promised)");

        // A HashSet has no encounter order for anything to preserve.
        Set<String> set = new HashSet<>(List.of("ada", "grace", "alan", "linus"));
        System.out.println("hash set       : " + set.stream().toList());

        // unordered() says "I do not care", so the pipeline can skip the bookkeeping.
        System.out.println("unordered      : " + list.parallelStream().unordered()
                .filter(n -> n % 2 == 0).collect(Collectors.toSet()));
    }
}

Order is a promise the runtime pays for. Give it up on purpose, never by accident.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Streams course, and every lesson in it is listed on the Streams contents page.