![]() | |
|
Java stream order of processing
Streams may or may not have a defined encounter order. Whether or not a stream
has an encounter order depends on the source and the intermediate operations. Certain stream sources (such as
java.util.List
or arrays) are intrinsically ordered, whereas others (such as java.util.HashSet
)
are not. Some intermediate operations, such as sorted()
, may impose an encounter order on an otherwise
unordered stream, and others may render an ordered stream unordered, such as BaseStream.unordered()
.
Further, some terminal operations may ignore encounter order, such as forEach()
.
If a stream is ordered, most operations are constrained to operate on the elements in their encounter
order; if the source of a stream is a List
containing [1, 2, 3]
, then the result of
executing map(x -> x*2)
must be [2, 4, 6]
.
List<Integer> ints = List.of(1, 2, 3); Stream<Integer> str = ints.stream(); Spliterator<Integer> spl = str.spliterator(); System.out.print(spl.hasCharacteristics(Spliterator.ORDERED));
true
However, if the source has no defined encounter order, then any permutation of the
values [2, 4, 6]
would be a valid result.
HashSet<Integer> ints = new HashSet<>(); ints.add(1); ints.add(2); ints.add(3); Stream<Integer> str = ints.stream(); Spliterator<Integer> spl = str.spliterator(); System.out.print(spl.hasCharacteristics(Spliterator.ORDERED));
false
For sequential streams, the presence or absence of an encounter order does not affect performance, only determinism. If a stream is ordered, repeated execution of identical stream pipelines on an identical source will produce an identical result; if it is not ordered, repeated execution might produce different results.
For parallel streams, relaxing the ordering constraint can sometimes enable more efficient execution
Finding the first element - findFirst()
For ordered streams you may wish to find the first element. There is the findFirst()
method for this:
Optional<T> findFirst();
For example, given a list of integers, finds the first number that is divisible by 7
:
List<Integer> ints = List.of(1, 6, 22, 21, 35, 36); Optional<Integer> result = ints.stream().filter(i -> i % 7 == 0).findFirst(); result.ifPresentOrElse(System.out::print, () -> System.out.print("No results found"));
Finding an element - findAny()
The findAny()
method returns an arbitrary element of the current stream.
Optional<T> findAny();
It can be used in conjunction with other stream operations. For example, you may wish to find any manager
from employee list. You can combine the filter(...)
method and findAny
to express this query:
public class Employee { public static final int MANAGER=100; public int type; public String name; public Employee(int t, String n) { type = t; name = n; } }
Stream<Employee> emps = Stream.of(new Employee(100, "John"), new Employee(100, "Jane"), new Employee(99, "Deb")); Optional<Employee> mgr = emps.filter(a -> a.type == Employee.MANAGER).findAny(); System.out.print(mgr.get().name);
The stream pipeline will be optimized behind the scenes to perform a single pass and finish as soon as a result is found by using short-circuiting.
You may wonder why Java 8.0 introduced both findFirst()
and findAny()
. The reason behind
findAny()
is to give a more flexible alternative to findFirst()
. If you are
not interested in getting a specific element, this gives the implementing stream more flexibility in case
it is a parallel stream.
No effort will be made to randomize the element returned, it just does
not give the same guarantees as findFirst()
, and might therefore be faster.
The behavior of findAny()
operation is explicitly nondeterministic; it is free to select
any element in the stream. This is to allow for maximal performance in parallel operations; the cost
is that multiple invocations on the same source may not return the same result. If a stable result is
desired, use findFirst()
instead.
Checking to see if a predicate matches at least one element - anyMatch(...)
The anyMatch(...)
method can be used to answer the question "Is there an element in the stream
matching the given predicate?" It accepts Predicate
as parameter:
boolean anyMatch(Predicate<? super T> predicate);
For example, you can use it to find out whether company has an employee with name "Mikalai
":
Stream<Employee> emps = Stream.of(new Employee(100, "Minerva"), new Employee(100, "Mikalai"), new Employee(99, "Michael")); boolean b = emps.anyMatch(e -> "Mikalai".equalsIgnoreCase(e.name)); if (b) { System.out.print("There is an employee with name 'Mikalai'"); }
The anyMatch(...)
method returns a boolean
and is therefore a terminal operation.
Checking to see if a predicate matches all elements - allMatch(...)
The allMatch(...)
method works similarly to anyMatch(...)
but will check to see
if all the elements of the stream match the given predicate:
boolean allMatch(Predicate<? super T> predicate);
For example, you can use it to find out
whether all employee names start with "Mi
":
Stream<Employee> emps = Stream.of(new Employee(100, "Minerva"), new Employee(100, "Mikalai"), new Employee(99, "Michael")); boolean b = emps.allMatch(e -> e.name.startsWith("Mi")); if (b) { System.out.println("All employee names start with 'Mi'"); }
Checking to see if a predicate does not match any element - noneMatch(...)
The opposite of allMatch(...)
is noneMatch(...)
. It ensures that no elements in the
stream match the given predicate:
boolean noneMatch(Predicate<? super T> predicate);
For example, you can use it to find out whether company has an employee with
name "Gandalf
":
Stream<Employee> emps = Stream.of(new Employee(100, "Minerva"), new Employee(100, "Mikalai"), new Employee(99, "Michael")); boolean b = emps.noneMatch(e -> e.name.equals("Gandalf")); if (b) { System.out.print("Gandalf is employed by some other company !"); }
![]() | |
Remember method signatures:
|
![]() | |
Some operations do not need to process the whole stream to produce a result. For example,
you need to evaluate a large boolean expression chained with "
In relation to streams, operations |
![]() ![]() ![]() |