4.2.  Search stream data using search findFirst, findAny, anyMatch, allMatch and noneMatch methods

[Note]

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 numbers, finds the first square that is divisible by 7:


List<Integer> ints = List.of(1, 6, 22, 21, 35, 36);
Optional<Integer> result = ints.stream().filter(i ->i % 17 == 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 matche 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 !");
}

					

[Important]

Remember method signatures:

  • All findXxx() methods have no arguments and return Optional.

  • All xxxMatch(...) methods accept a Predicate and return a boolean primitive.

[Important]

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 "&&" operators. You need only find out that one expression is false to deduce that the whole expression will return false, no matter how long the expression is; there is no need to evaluate the entire expression. This is what short-circuiting refers to.

In relation to streams, operations anyMatch(...), allMatch(...), noneMatch(...), findFirst(), and findAny() do not need to process the whole stream to produce a result. As soon as an element is found, a result can be produced. These are short-circuiting terminal operations.

Professional hosting         Exam 1Z0-817: Upgrade OCP Java 6, 7 & 8 to Java SE 11 Developer Quiz     Exam 1Z0-810: Upgrade to Java SE 8 Programmer Quiz