Declarative Matching with Java 8 Streams

If you are new to Java Streams, please refer to http://talks.skilltoz.com/streams-in-java-8/

How can you check if the objects in a stream match a particular condition?

A natural solution that comes to mind is to iterate through the elements of a stream and check each element to see if it matches the given condition. What if there is a better way to do this? From Java 8. it is possible to do declarative matching to check if the elements in a stream satisfy a condition.

Here are the steps for doing this

  • Define the condition using a Predicate instance
  • Use the methods allMatch, anyMatch, and noneMatch to the Stream which perform matching as per the given Predicate and return a boolean value as detailed here
    • The allMatch() method returns true if all the elements of the Stream match the given condition
    • The anyMatch() method returns true if any of the elements of the Stream match the given condition
    • The noneMatch() method returns true if none of the elements of the Stream match the given condition

In the below example, the List contains exactly one even number. You can see that the allMatch() method with the odd number condition returns false because all the elements are not odd. The anyMatch() method with the even number condition returns true because one element is even. The condition given to the noneMatch() method is whether each number is a multiple of the number 5. As all the elements are not multiples of 5, this returns false.

List<Integer> intList = Arrays.asList(1, 2, 3, 5, 7);
boolean allOdd = intList.stream().allMatch(i -> i % 2 != 0);
boolean oneEven = intList.stream().anyMatch(i -> i % 2 == 0);
boolean noMultipleOfFive = intList.stream().noneMatch(i -> i % 5 == 0);
System.out.println("All are odd: " + allOdd); // Prints false
System.out.println("One is even: " + oneEven); // Prints true
System.out.println("No multiples of 5:" + noMultipleOfFive); // Prints false

Quiz

1. Given the following piece of code.

String purple = "Purple";
List<String> balloons = Arrays.asList("Purple", "Yellow", "Green");

Which of the following pieces of code can be used to check if “Purple” is there in the given list?

a. hasPurple = balloons.stream().anyMatch(element -> element.contains(purple)); 
b. hasPurple = balloons.stream().anyMatch(purple::contains); 
c. hasPurple = balloons.stream().allMatch(element -> element.contains(purple));
d. hasPurple = balloons.stream().allMatch(purple::contains);

a and b are correct choices. The anyMatch() method is used to check if any of the elements in the stream matches the predicate condition. This is applied using lambda expression in choice A and using method reference syntax in choice b. Choices c and d are incorrect because the allMatch() method returns true only if every element of the stream matches the predicate condition.

2. What will be the result of compiling and running the following code?

Stream<Integer> numStream = Stream
    .of(1, 22, 12, 3, 14, 4)
    .filter(s -> s > 5);
boolean any = numStream.anyMatch(s -> true);
boolean none = numStream.noneMatch(s -> true);
System.out.println("Any=" + any + " None=" + none);

Choices

A. Does not compile
B. Throws exception at runtime
C. Prints “Any=true None=false”
D. Prints “Any=false None=false”

B is the correct answer. This code throws an exception at runtime because Java 8 streams are closed when you call a terminal operation and cannot be reused. In the given example, calling noneMatch() on the stream after calling anyMatch() causes IllegalStateException to be thrown.

Leave a Reply

Your email address will not be published. Required fields are marked *