Matching Elements – Streams
By Stephen Trude / August 23, 2023 / No Comments / Certifications of Oracle, Collecting to an Array, Multilevel Partitioning
Matching Elements
The match operations determine whether any, all, or none of the stream elements satisfy a given Predicate. These operations are not reductions, as they do not always consider all elements in the stream in order to return a result.
Analogous match operations are also provided by the numeric stream interfaces.
boolean anyMatch(Predicate<? super T> predicate)
boolean allMatch(Predicate<? super T> predicate)
boolean noneMatch(Predicate<? super T> predicate)
These three terminal operations determine whether any, all, or no elements of this stream match the specified predicate, respectively.
The methods may not evaluate the predicate on all elements if it is not necessary for determining the result; that is, they are short-circuit operations.
If the stream is empty, the predicate is not evaluated.
The anyMatch() method returns false if the stream is empty.
The allMatch() and noneMatch() methods return true if the stream is empty.
There is no guarantee that these operations will terminate if applied to an infinite stream.
The queries at (1), (2), and (3) below determine whether any, all, or no CDs are jazz music CDs, respectively. At (1), the execution of the pipeline terminates as soon as any jazz music CD is found—the value true is returned. At (2), the execution of the pipeline terminates as soon as a non-jazz music CD is found—the value false is returned. At (3), the execution of the pipeline terminates as soon as a jazz music CD is found—the value false is returned.
boolean anyJazzCD = CD.cdList.stream().anyMatch(CD::isJazz); // (1) true
boolean allJazzCds = CD.cdList.stream().allMatch(CD::isJazz); // (2) false
boolean noJazzCds = CD.cdList.stream().noneMatch(CD::isJazz); // (3) false
Given the following predicates:
Predicate<CD> eq2015 = cd -> cd.year().compareTo(Year.of(2015)) == 0;
Predicate<CD> gt2015 = cd -> cd.year().compareTo(Year.of(2015)) > 0;
The query at (4) determines that no CDs were released in 2015. The queries at (5) and (6) are equivalent. If all CDs were released after 2015, then none were released in or before 2015 (negation of the predicate gt2015).
boolean noneEQ2015 = CD.cdList.stream().noneMatch(eq2015); // (4) true
boolean allGT2015 = CD.cdList.stream().allMatch(gt2015); // (5) true
boolean noneNotGT2015 = CD.cdList.stream().noneMatch(gt2015.negate()); // (6) true
The code below uses the anyMatch() method on an int stream to determine whether any year is a leap year.
IntStream yrStream = IntStream.of(2018, 2019, 2020);
IntPredicate isLeapYear = yr -> Year.of(yr).isLeap();
boolean anyLeapYear = yrStream.anyMatch(isLeapYear);
out.println(“Any leap year: ” + anyLeapYear); // true
Example 16.10 illustrates using the allMatch() operation to determine whether a square matrix—that is, a two-dimensional array with an equal number of columns as rows—is an identity matrix. In such a matrix, all elements on the main diagonal have the value 1 and all other elements have the value 0. The methods isIdentityMatrixLoops() and isIdentityMatrixStreams() at (1) and (2) implement this test in different ways.
The method isIdentityMatrixLoops() at (1) uses nested loops. The outer loop processes the rows, whereas the inner loop tests that each row has the correct values. The outer loop is a labeled loop in order to break out of the inner loop if an element in a row does not have the correct value—effectively achieving short-circuit execution.
The method isIdentityMatrixStreams() at (2) uses nested numeric streams, where the outer stream processes the rows and the inner stream processes the elements in a row. The allMatch() method at (4) in the inner stream pipeline determines that all elements in a row have the correct value. It short-circuits the execution of the inner stream if that is not the case. The allMatch() method at (3) in the outer stream pipeline also short-circuits its execution if its predicate to process a row returns the value false. The stream-based implementation for the identity matrix test expresses the logic more clearly and naturally than the loop-based version.
Example 16.10 Identity Matrix Test
import static java.lang.System.out;
import java.util.Arrays;
import java.util.stream.IntStream;
public class IdentityMatrixTest {
public static void main(String[] args) {
// Matrices to test:
int[][] sqMatrix1 = { {1, 0, 0}, {0, 1, 0}, {0, 0, 1} };
int[][] sqMatrix2 = { {1, 1}, {1, 1} };
isIdentityMatrixLoops(sqMatrix1);
isIdentityMatrixLoops(sqMatrix2);
isIdentityMatrixStreams(sqMatrix1);
isIdentityMatrixStreams(sqMatrix2);
}
private static void isIdentityMatrixLoops(int[][] sqMatrix) { // (1)
boolean isCorrectValue = false;
outerLoop:
for (int i = 0; i < sqMatrix.length; ++i) {
for (int j = 0; j < sqMatrix[i].length; ++j) {
isCorrectValue = j == i ? sqMatrix[i][i] == 1
: sqMatrix[i][j] == 0;
if (!isCorrectValue) break outerLoop;
}
}
out.println(Arrays.deepToString(sqMatrix)
+ (isCorrectValue ? ” is “: ” is not “) + “an identity matrix.”);
}
private static void isIdentityMatrixStreams(int[][] sqMatrix) { // (2)
boolean isCorrectValue =
IntStream.range(0, sqMatrix.length)
.allMatch(i -> IntStream.range(0, sqMatrix[i].length) // (3)
.allMatch(j -> j == i // (4)
? sqMatrix[i][i] == 1
: sqMatrix[i][j] == 0));
out.println(Arrays.deepToString(sqMatrix)
+ (isCorrectValue ? ” is “: ” is not “) + “an identity matrix.”);
}
}
Output from the program:
Click here to view code image [[1, 0, 0], [0, 1, 0], [0, 0, 1]] is an identity matrix.
[[1, 1], [1, 1]] is not an identity matrix.
[[1, 0, 0], [0, 1, 0], [0, 0, 1]] is an identity matrix.
[[1, 1], [1, 1]] is not an identity matrix.