Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 Stream + Map + ForEach + Collect

I am reading values from a File and get List. like below -

List<String> fields = Utils.readFile("myText.txt", true);

Once I get this List<String> I want to iterate through this list and pass each value to a function which uses this value, queries into DB and prepares a List<MyCustomObject> and returns the same.

Implementing in Java 7 is quite easy but I'm unable to get it in Java 8 using Stream + Map/forEach + Collect operations.

I have tried the below -

Utils.readFile("myText-"+".txt", true)
        .stream()
        .map(str -> getListOfCustomObjForEachStr(str, pstmt))
        .collect(Collectors.toList());

But it returns a List<List<MyCustomObject>> instead of merged List<MyCustomObject>

getListOfCustomObjForEachStr() method returns a List for each input str passed in the above code. And I need a merged List

Can someone please guide me what can be done here to get a merged list? (I'm new to Java 8 so it might seem a silly question but any help is appreciated)

Edit 1 Got this implemented like below using FlatMap - Kindly suggest if any other better way to do it. Hope it helps someone somewhere someday :) Keep sharing.

List<MyCustomObjects> = Utils.readFile("myText-"+".txt", true)
    .stream()
    .map(str -> getListOfCustomObjForEachStr(str, pstmt))
    .flatMap(Collection::stream)
    .collect(Collectors.toList());
like image 973
Swapnil Jaju Avatar asked Jan 16 '17 02:01

Swapnil Jaju


People also ask

What is the difference between forEach and stream forEach?

The reason for the different results is that forEach() used directly on the list uses the custom iterator, while stream(). forEach() simply takes elements one by one from the list, ignoring the 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.

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

The forEach method was introduced in Java 8. It provides programmers a new, concise way of iterating over a collection. The forEach method performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception.

Is forEach a stream?

The forEach() method is part of the Stream interface and is used to execute a specified operation, defined by a Consumer . The Consumer interface represents any operation that takes an argument as input, and has no output.


1 Answers

Using flatMap is the canonical way to get a flat list. You may use a single step instead of map+flatMap:

List<MyCustomObjects> list = Utils.readFile("myText-"+".txt", true)
    .stream()
    .flatMap(str -> getListOfCustomObjForEachStr(str, pstmt).stream())
    .collect(Collectors.toList());

You may think about an alternative to getListOfCustomObjForEachStr returning a Stream in the first place. Further, not the existence of Files.lines, which returns a stream of line strings without filling a temporary List first.

In this specific case, there is an alternative. Considering that .collect(Collectors.toList()) is equivalent to .collect(ArrayList::new, List::add, List::addAll)¹, you also use

List<MyCustomObjects> list = Utils.readFile("myText-"+".txt", true)
    .stream()
    .map(str -> getListOfCustomObjForEachStr(str, pstmt))
    .collect(ArrayList::new, List::addAll, List::addAll);

replacing add with addAll, which is already sufficient to add all sub-List<MyCustomObjects>s to the result List<MyCustomObjects>.


¹ That’s how toList() works now, but since it not specified to do this, it might be different in other versions

like image 91
Holger Avatar answered Sep 25 '22 13:09

Holger