Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Better approach for stream filter in Java

Is there a way to simplify filter using stream? Or for it to be shorter or optimized? I'm not quite sure if using a for loop would be better to use in this scenario.

I'm just trying to separate the failed and the success messages using the failedIds.

Here is my code

List<Message> successMessages = messageList.stream()
        .filter(message -> !failedMessageIds.contains(message.getId()))
        .collect(Collectors.toList());

List<Message> failedMessages = messageList.stream()
        .filter(message -> failedMessageIds.contains(message.getId()))
        .collect(Collectors.toList());

Thank you!

like image 309
mengmeng Avatar asked Mar 19 '20 10:03

mengmeng


People also ask

How do you use the filter method in streams?

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.

Which methods can you use to filter and slice a stream in Java 8 +?

Streams Filtering & Slicing Basics: Java 8 Streams support declarative filtering out of elements along with the ability to slice-off portions of a list. Streams support four operations to achieve this – filter() , distinct() , limit(n) and skip(n) .

Is stream filter faster than for loop?

Yes, streams are sometimes slower than loops, but they can also be equally fast; it depends on the circumstances. The point to take home is that sequential streams are no faster than loops.

What kind of interface does the filter method in a stream accept?

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.


Video Answer


1 Answers

You may use groupingBy collector here. This solution passes over the collection only once. Also make sure to use a Set for failedMessageIds.

Map<Boolean, List<Message>> messagesByStateMap = messageList.stream()
    .collect(Collectors.groupingBy(m -> !failedMessageIds.contains(m.getId())));
List<Message> successMessages = messagesByStateMap.get(true);

A much better approach would be to use the partitioningBy collector as stated in the following comment since your classifier function is a just a Predicate.

Map<Boolean, List<Message>> messagesByStateMap = messageList.stream()
    .collect(Collectors.partitioningBy(m -> !failedMessageIds.contains(m.getId())));

However, since the use of streams has sparked some controversy, here's the equivalent iterative solution using Java 8.

for (Message message : messageList)
    messagesByStateMap.computeIfAbsent(!failedMessageIds.contains(message.getId()), 
        unused -> new ArrayList<>())
    .add(message);
like image 70
Ravindra Ranwala Avatar answered Sep 23 '22 04:09

Ravindra Ranwala