Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elegant way to find out if a Java 8 stream filter has filtered something

I have a List of Item fetched from a database.

I do something like:

List<Item> list;
list.stream()
    .filter( i -> i.condition() )
    .mapToLong( Item::asLong )
    .sum()
    ;

Now I want to know, if the filter has filtered out something so I could delete this from my database where it is no longer needed.

I could do:

List<Item> list2 = list.stream()
    .filter( i -> i.condition() )
    .collect( Collectors.toList() )
    ;

int theSizeIWant = list2.size();

list2.stream().mapToLong( Item::asLong )
     .sum()
     ;

but I wonder if there is a more elegant solution which doesn't need to create the intermediate list.

like image 376
Scheintod Avatar asked Jan 29 '16 09:01

Scheintod


People also ask

What is filtered stream in Java?

The java.io package provides a set of abstract classes that define and partially implement filter streams. A filter stream filters data as it's being read from or written to the stream. The filter streams are FilterInputStream or FilterOutputStream , FilterInputStream , and FilterOutputStream. .

How do you filter a list of objects using a stream?

Java stream provides a method filter() to filter stream elements on the basis of given predicate. Suppose you want to get only even elements of your list then you can do this easily with the help of filter method. This method takes predicate as an argument and returns a stream of consisting of resulted elements.

What is the purpose of filter method of stream in Java 8?

Java 8 Stream interface introduces filter() method which can be used to filter out some elements from object collection based on a particular condition. This condition should be specified as a predicate which the filter() method accepts as an argument.

How do I know if my Java 8 stream is empty?

You have to consume the stream to find out if it's empty. That's the point of Stream's semantics (laziness). To check that the stream is not empty you have to attempt to consume at least one element. At that point the stream has lost its "virginity" and cannot be consumed again from the start.


2 Answers

A possible solution would be to partition the Stream with the predicate and sum the values. Partitioning is done with partitioningBy(predicate, downstream). In this case, the predicate would be your filtering function and the downstream collector would be summingLong to sum the values.

public static void main(String[] args) {
    List<Item> list = new ArrayList<>();
    Map<Boolean, Long> map = 
        list.stream()
            .collect(Collectors.partitioningBy(
                Item::condition, 
                Collectors.summingLong(Item::asLong)
            ));
    long sumWithTrueCondition = map.get(true);
    long sumWithFalseCondition = map.get(false);
}

The map will contain the sum where the predicate is true (resp. false) with the true key (resp. false).

This way, if something has been filtered, sumWithTrueCondition will be strictly greater than 0. Furthermore, you can get the total sum by adding sumWithTrueCondition and sumWithFalseCondition.

like image 121
Tunaki Avatar answered Oct 07 '22 17:10

Tunaki


Yes, you can do something like this.

Map<Boolean, List<Item>> partitions =
    list.stream.collect(Collectors.partitioningBy(i -> i.condition()));

Where partitions.get(true) will get you the good ones and partitions.get(false) will get you the ones to be deleted.

like image 5
Simon Avatar answered Oct 07 '22 17:10

Simon