Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java8 Stream - use filter collect foreach in single line

Is't possible to use filter(),collect() and foreach() in single statement instead of multiple statements?

I have a map and need to filter based on some condition and set some values to the content and return the map. My current looks like below, but i want all 3 in single statement.

Map inputMap (contains all info)

Map<String, Person> returnMap; 
            returnMap = map.entrySet().stream()
            .filter(p ->  p.getValue().getCourse() == 123)
            .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));

            returnMap.entrySet().stream().forEach((entry) -> {
                Person person= entry.getValue();                
                person.setAction("update");
                person.setLastUpdatedTime(new Date());
            });

can this be converted to,

  Map<String, Person> returnMap; 
                returnMap = map.entrySet().stream()
                .filter(p ->  p.getValue().getCourse() == 123)
                .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue())) 
 .forEach((entry) -> {
                    Person person= entry.getValue();                
                    person.setAction("update");
                    person.setLastUpdatedTime(new Date());
                });

(this code doesn't work)

like image 832
skumar Avatar asked Jun 08 '16 19:06

skumar


People also ask

Can we use filter and forEach in Java 8?

Java 8 Stream - filter() and forEach() Example forEach() method with an example. Java stream provides a filter() method to filter stream elements on the basis of a given predicate. This method takes a predicate as an argument and returns a stream consisting of resulted elements.

What is difference between collection stream () forEach () and collection forEach ()?

Collection.forEach()stream(). forEach() is also used for iterating the collection but it first converts the collection to the stream and then iterates over the stream of collection. Collection. forEach() uses the collections iterator.

How do I replace forEach with stream?

Save this question. Show activity on this post. TreeMap<Integer, List<String>> myMap = new TreeMap<>(); List<Integer> myList = getDataForTest(true); List<String> wordList = getWordList(true); List<Integer> intList = Collections.

Is stream better than forEach?

stream(). forEach() is undefined. In most cases, it doesn't make a difference which of the two we choose.


2 Answers

The problem is that forEach does not return an object so you have to handle it different. You can do it this way:

Map<String, Person> returnMap = new HashMap<>(); 
map.entrySet().stream()
              .filter(p ->  p.getValue().getCourse() == 123)
              .forEach((entry) -> {
                    Person person = entry.getValue();                
                    person.setAction("update");
                    person.setLastUpdatedTime(new Date());
                    returnMap.put(entry.getKey(), person);
                });
like image 118
Kevin Wallis Avatar answered Oct 13 '22 02:10

Kevin Wallis


There is no sense in insisting on doing it with one operation. Regardless of how you write it down, these are two operations.

But one thing you should consider, is, that there are more ways than entrySet().stream() to process all elements:

Map<String, Person> returnMap = map.entrySet().stream()
    .filter(p ->  p.getValue().getCourse() == 123)
    .collect(Collectors.toMap(p -> p.getKey(), p -> p.getValue()));

returnMap.values().forEach(person -> {          
    person.setAction("update");
    person.setLastUpdatedTime(new Date());
});

If you still insist on making it look like a single operation, you can do it this way:

Map<String, Person> returnMap = map.entrySet().stream()
    .filter(p ->  p.getValue().getCourse() == 123)
    .collect(Collectors.collectingAndThen(
        Collectors.toMap(p -> p.getKey(), p -> p.getValue()),
        tmp -> {
            tmp.values().forEach(person -> {          
                person.setAction("update");
                person.setLastUpdatedTime(new Date());
            });
            return tmp;
        })
    );

This is syntactically a single statement, still, it does exactly the same as the former variant.

like image 38
Holger Avatar answered Oct 13 '22 02:10

Holger