The filter() and noneMatch() operations are provided by Java 8 Stream API. In this post, we will see the difference between noneMatch and filter operations and how to use them together. Both filter and noneMatch methods serve different purposes.
A filter is an intermediate operation whereas noneMatch is a short circuiting terminal operation.
noneMatch syntax
boolean noneMatch(Predicate<? super T> predicate)
filter syntax
Stream<T> filter(Predicate<? super T> predicate)
From the syntax, it is observed that the filter operation returns Stream, and noneMatch returns a boolean value. So the intermediate operation filter will return another Stream and will not return an end result. The terminal operation noneMatch returns an end result. The stream is closed.
Here we take a part of the code from the noneMatch() example.
boolean studentsScoreMatch = stdList.stream().
noneMatch(c -> c.getScore() < 70);
noneMatch operation is used to verify if no elements of a stream match the input predicate. noneMatch may not evaluate the predicate on all elements if it is not necessary for determining the result. Note that if the input stream is empty, it returns true and the predicate will not be evaluated. False is returned, if at least one element matches the given predicate.
package com.digitizedpost.match;
import java.util.ArrayList;
import java.util.List;
public class MatchScore {
public static void main(String[] args) {
List<Student> stdList = new ArrayList<>();
stdList.add(new Student("Robert", 75));
stdList.add(new Student("Martin", 85));
stdList.add(new Student("Jack", 95));
stdList.add(new Student("John", 60));
stdList.add(new Student("Doe", 100));
stdList.add(new Student("Sam", 75));
//check students academics matches the given predicate by score
boolean tempList = stdList.stream().noneMatch(e -> e.getScore() > 65);
System.out.println(tempList);
}
}
class Student {
private String name;
private int score;
public Student(String name, int score) {
super();
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
Output: false
The output of this program returns false. Line stdList.stream().noneMatch(e -> e.getScore() > 65) can be read as none of the student score is greater than 65? It's not true because five students' scores are greater than 65. If all Student's score are Sixty Five are less than Sixty Five then this method will return true
Let's rewrite the above code with the filter() operation and see the result. As the filter returns a Stream, we require a List as the return type. So collect(Collectors.toList()) is used to return the filtered results as List.
Here the noneMatch() is replaced with the filter() operation,
List<Student> studentsScoreMatch = stdList.stream().
filter(c -> c.getScore() < 70)
.collect(Collectors.toList());
The filter result is collected in a List to check the list of candidates with scores less than 70.
package com.digitizedpost.match;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class FilterScore {
public static void main(String[] args) {
List<Student> stdList= new ArrayList<>();
stdList.add(new Student("Robert", 75));
stdList.add(new Student("Martin", 85));
stdList.add(new Student("Jack", 95));
stdList.add(new Student("John", 60));
stdList.add(new Student("Doe", 100));
stdList.add(new Student("Sam", 75));
//Filter out students by score
List<Student> tempList = stdList.stream()
.filter(e -> e.getScore() > 65)
.collect(Collectors.toList());
//Print the filtered words
tempList.forEach(e -> System.out.println("Name :- " + e.getName()
+ ", Score :- " + e.getScore()));
}
}
class Student {
private String name;
private int score;
public Student(String name, int score) {
super();
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
Output:
Name : Robert, Score : 75
Name : Martin, Score : 85
Name : Jack, Score : 95
Name : Doe, Score : 100
Name : Sam, Score : 75
As the noneMatch() operation return type is boolean, this method can be used in conditional checks like if statement or inside the filter operation.
Usage of noneMatch operation in conditional if statement
int[] scores = {70, 60, 65,72, 67};
if (Arrays.stream(scores).noneMatch(n -> n > 75 )) {
System.out.println("None of the scores are greater than 75.");
} else {
System.out.println("One or more than a score matches greagter than 75.");
}
This example checks if none of the scores is greater than the given predicate, else outputs a message that at least one number is greater than the given predicate using the noneMatch method.
Using noneMatch and filter together
Sometimes you may encounter a situation to use both noneMatch and filter together.
public static void main(String[] args) {
List<Student> stdList = new ArrayList<>();
stdList.add(new Student("Robert", 75));
stdList.add(new Student("Martin", 85));
stdList.add(new Student("Jack", 95));
stdList.add(new Student("John", 60));
stdList.add(new Student("Doe", 100));
stdList.add(new Student("Sam", 75));
//Filter out students by score and check none of the students score is > than 100
boolean noneGreaterThanHundred = stdList.stream()
.filter(e -> e.getScore() > 65)
.noneMatch(n -> n.getScore() > 95);
System.out.println(noneGreaterThanHundred);
}
}
Output: true
In this noneMatch and filter together example, students are filtered by the passing score of 65 and it checks none of the student's score is greater than 95.
Using noneMatch method inside the filter method
Here is another example of how to use the noneMatch method inside the filter method. Here each Student has a score list. noneMatch inside the filter method checks none of the student scores are greater than 95. Student John scored 100 in a subject. So filter method returns other records that are returned as true by noneMatch.
package com.digitizedpost.match;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class NoneMatchInsideFilter {
public static void main(String[] args) {
List<Student> stdList = new ArrayList<>();
stdList.add(new Student("Robert", Arrays.asList(78, 72, 90, 73, 94)));
stdList.add(new Student("Martin", Arrays.asList(84, 67, 87, 85, 74)));
stdList.add(new Student("Jack", Arrays.asList(77, 73, 90, 85, 95)));
stdList.add(new Student("John", Arrays.asList(67, 70, 93, 85, 100)));
stdList.add(new Student("Doe", Arrays.asList(65, 75, 82, 93, 91)));
stdList.add(new Student("Sam", Arrays.asList(72, 70, 90, 85, 76)));
List<Student> filteredWords = stdList.stream()
.filter(word -> word.getScores().stream().noneMatch(e -> e > 95))
.collect(Collectors.toList());
filteredWords.forEach(e -> System.out.println("Name :- " + e.getName()
+ ", Score :- " + e.getScores()));
}
}
class Student {
private String name;
private List<Integer> scores;
public Student(String name, List<Integer> scores) {
super();
this.name = name;
this.scores = scores;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Integer> getScores() {
return scores;
}
public void setScores(List<Integer> scores) {
this.scores = scores;
}
}