Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to count matches on a stream filter?

How can I count the matches of a stream filter? I'm trying to refactor the following code to java8 stream:

//java7
int i = 0;
for (Node node : response.getNodes()) {
    Integer id = node.getId();
    if (id != null) {
        node.setContent("This is the id: " + id);
        i++;
    }
}

//java8
response.getNodes().stream()
    .filter(node -> node.getId() != null)
    .forEach(node -> node.setValue("This is the id: " + node.getId()));

How can I now get the count of filtered elements that were applied? Sidequestion: in the old code I can reuse the Integer id multiple times. How can I achieve the same with streams?

like image 801
membersound Avatar asked Mar 25 '15 15:03

membersound


People also ask

How do you count filters in Java?

We can filter collections with multiple criteria: getPoints() > 10 && c. getName(). startsWith("Charles")) . count(); assertThat(count).

Is there a count method in Java?

Core Java bootcamp program with Hands on practiceThe counting() method of the Java 8 Collectors class returns a Collector accepting elements of type T that counts the number of input elements.

How do you use the filter method in stream?

The filter() function of the Java stream allows you to narrow down the stream's items based on a criterion. If you only want items that are even on your list, you can use the filter method to do this. This method accepts a predicate as an input and returns a list of elements that are the results of that predicate.


1 Answers

Since setValue is a side-effect function, you can use peek:

long i = response.getNodes()
                 .stream()
                 .filter(node -> node.getId() != null)
                 .peek(node -> node.setValue("This is the id: " + node.getId()))
                 .count();

I'm not a fan of this approach because peak is meant to use for debugging purpose (this would do the trick). Note that in Java 9, count() may be able to not execute the stream pipeline if it can compute the count directly from the source (I don't think it's the case here, since you apply a filtering but it's good to keep it in mind).

Sidequestion: in the old code I can reuse the Integer id multiple times. How can I achieve the same with streams?

It depends on your use-case, since the API doesn't have tuples your best chance is to create a class, let's say Tuple2, so that you can map each node to a new tuple and reuse the id.

Something like:

.stream().map(node -> new Tuple2<>(node, node.getId()).moreStreamOps(...);
                                                      ^
                                                      |
                 at that point you have a Stream<Tuple2<Node, Integer>> 
                 from which you can grab the id with Tuple2#getSecond

In your case, if you stay with a stream of nodes, you can just grab the id with getId() at any time.

like image 193
Alexis C. Avatar answered Oct 24 '22 05:10

Alexis C.