Sunday, March 19, 2017

5 ways to Convert Java 8 Stream to List - Example, Tutorial

One of the common problems while working with Stream API in Java 8 is how to convert a Stream to List in Java because there is no toList() method present in Stream class. When you are processing a List using Stream's map and filter method, you ideally want your result in some collection so that you can pass it to other parts of the program. Though java.util.stream.Stream class has toArray() method to convert Stream to Array, but there is no similar method to convert Stream to List or Set. Java has a design philosophy of providing conversion method between new and old API classes e.g. when they introduced Path class in JDK 7, which is similar to java.io.File, they provided a toPath() method to File class.


Similarly, they could have provided convenient methods like toList(), toSet() into Stream class, but unfortunately, they have not done that. Anyway, It seems they did think about this and provided a class called Collector to collect the result of stream operations into different containers or Collection classes.

Here you will find methods like toList(), which can be used to convert Java 8 Stream to List. You can also use any List implementation class e.g. ArrayList or LinkedList to get the contents of that Stream. I would have preferred having those methods at-least the common ones directly into Stream but nevertheless, there is something you can use to convert a Java 8 Stream to List.

By the way,  my research for this task also reveals several other ways to achieve the same result, which I have summarized in this tutorial. If would suggest preferring a standard way, which is by using Stream.collect() and Collectors class, but its good to know other ways, just in case if you need it.

And, If you are serious about improving Java functional programming skills then I highly recommend you check out the  Learn Java Functional Programming with Lambdas & Streams by Rang Rao Karnam on Udemy, which explains both Functional Programming and Java Stream fundamentals in good detail






Java 8 Stream to List conversion - 5 examples

Here are 5 simple ways to convert a Stream in Java 8 to List e.g. converting a Stream of String to a List of String, or converting a Stream of Integer to List of Integer and so on.


1. Using Collectors.toList() method


This is the standard way to collect the result of stream in a container e.g. List, Set or any Collection. Stream class has a collect() method which accepts a Collector and you can use Collectors.toList() method to collect the result in a List.

List listOfStream = streamOfString.collect(Collectors.toList());



2. Using Collectors.toCollection() method


This is actually a generalization of the previous method, here instead of creating List, you can collect elements of Stream in any Collection, including ArrayList, LinkedList or any other List. In this example, we are collecting Stream elements into ArrayList.

The toColection() method returns a Collector that accumulates the input elements into a new Collection, in encounter order. The Collection is created by the provided Supplier instance, in this case, we are using ArrayList::new, a constructor reference to collect them into ArrayList.

You can also use lambda expression in place of method reference here, but method reference results in much more readable and concise code.

List listOfString  = streamOfString
                    .collect(Collectors.toCollection(ArrayList::new));



3. Using forEach() method

You can also use forEach() method to go through all elements of Stream one by one and add them into a new List or ArrayList. This is a simple, pragmatic approach, which beginners can use to learn.

Stream streamOfLetters = Stream.of("abc", "cde",
                "efg", "jkd", "res");
ArrayList list = new ArrayList<>();
streamOfLetters.forEach(list::add);



4. Using forEachOrdered method

This is an extension of the previous example, if Stream is parallel then elements may be processed out of order but if you want to add them into the same order they were present in Stream, you can use forEachOrdered() method. If you are not comfortable with forEach, I suggest looking at this Stream tutorial to understand more.

Stream streamOfNumbers = Stream.of("one", "two",
                "three", "four", "five");
ArrayList myList = new ArrayList<>();
streamOfNumbers.parallel().forEachOrdered(myList::add);



5. Using toArray() method

Stream provides a direct method to convert Stream to the array, toArray(). The method which accepts no argument returns an object array as shown in our sample program, but you can still get which type of array you want by using an overloaded version of that method. Just like we have done in the following example to create String array :

Stream streamOfShapes = Stream.of("Rectangle", "Square", "Circle", "Oval");
String[] arrayOfShapes = streamOfShapes.toArray(String[]::new);
List listOfShapes = Arrays.asList(arrayOfShapes);



Sample Program to convert Stream to List in Java 8

Here is the complete Java program to demonstrate all these five methods of converting Java 8 Streams to List. You can directly run them if you have installed JDK 8 in your machine. BTW, You should be using Netbeans with JDK 8 to code, compile and run Java program. The IDE has got excellent support and will help you to learn Java 8 quickly.

Java 8 Stream to List Example




package test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Java Program to convert Stream to List in Java 8
 *
 * @author Javin Paul
 */
public class Java8StreamToList{

    public static void main(String args[]) throws IOException {
        Stream<String> streamOfString = Stream.of("Java", "C++",
                "JavaScript", "Scala", "Python");

        // converting Stream to List using Collectors.toList() method
        streamOfString = Stream.of("code", "logic",
                "program", "review", "skill");
        List<String> listOfStream 
                      = streamOfString.collect(Collectors.toList());
        System.out.println("Java 8 Stream to List, 1st example : "
                                 + listOfStream);

        // Java 8 Stream to ArrayList using Collectors.toCollection method
        streamOfString = Stream.of("one", "two",
                "three", "four", "five");
        listOfStream = streamOfString.collect(
                                  Collectors.toCollection(ArrayList::new));
        System.out.println("Java 8 Stream to List, 2nd Way : " 
                                       + listOfStream);

        // 3rd way to convert Stream to List in Java 8
        streamOfString = Stream.of("abc", "cde",
                "efg", "jkd", "res");
        ArrayList<String> list = new ArrayList<>();
        streamOfString.forEach(list::add);
        System.out.println("Java 8 Stream to List, 3rd Way : " + list);

        // 4th way to convert Parallel Stream to List
        streamOfString = Stream.of("one", "two",
                "three", "four", "five");
        ArrayList<String> myList = new ArrayList<>();
        streamOfString.parallel().forEachOrdered(myList::add);
        System.out.println("Java 8 Stream to List, 4th Way : " + myList);
        
        // 5th way of creating List from Stream in Java
        // but unfortunately this creates array of Objects
        // as opposed to array of String
        Stream<String> streamOfNames = Stream.of("James", "Jarry",
                                                 "Jasmine", "Janeth");
        Object[] arrayOfString = streamOfNames.toArray();
        List<Object> listOfNames = Arrays.asList(arrayOfString);
        System.out.println("5th example of Stream to List in Java 8 : "
                                           + listOfNames);
        

        // can we convert the above method to String[] instead of 
        // Object[], yes by using overloaded version of toArray()
        // as shown below :
        Stream<String> streamOfShapes = Stream.of("Rectangle", 
                                         "Square", "Circle", "Oval");
        String[] arrayOfShapes = streamOfShapes.toArray(String[]::new);
        List<String> listOfShapes = Arrays.asList(arrayOfShapes);
        System.out.println("modified version of last example : " 
                                         + listOfShapes);

    }

}


Output :
Java 8 Stream to List, 1st example : [code, logic, program, review, skill]
Java 8 Stream to List, 2nd Way : [one, two, three, four, five]
Java 8 Stream to List, 3rd Way : [abc, cde, efg, jkd, res]
Java 8 Stream to List, 4th Way : [one, two, three, four, five]
5th example of Stream to List in Java 8 : [James, Jarry, Jasmine, Janeth]
modified version of last example : [Rectangle, Square, Circle, Oval]


That's all about how to convert Stream to List in Java 8. You have seen there are several ways to perform the conversion but I would suggest you stick with standard approach i.e. by using Stream.collect(Collectors.toList()) method.

Further Learning
The Complete Java MasterClass
From Collections to Streams in Java 8
Refactoring to Java 8 Streams and Lambdas Self- Study Workshop

If you like this Java 8 tutorial and hungry for more, check out following Java 8 tutorials about lambda expression, Stream API, default methods and Date Time API :
  • Java 8 - 20 Date and Time Examples for beginners (see tutorial)
  • 5 FREE Java 8 tutorials and Books (resources)
  • How to Read File in Java 8 in one line? (example)
  • Simple Java 8 Comparator Example (example)
  • Top 10 tutorials to Learn Java 8 (tutorial)
  • How to use Map function in Java 8 (example)
  • Thinking of Java 8 Certification? (read more)
  • How to read/write RandomAccessFile in Java? (solution)
  • How to use Lambda Expression in Place of Anonymous class (solution)
  • 10 Examples of Stream API in Java (examples)
  • How to filter Collection in Java 8 using Predicates? (solution)
  • How to use the Default method in Java 8. (see here)
  • 10 Java 7 Feature to revisit before you start with Java 8 (read more)

2 comments :

Anonymous said...

When you get a list from Stream, does it also preserve the order of elements as they were in Stream? Same question is what if we get a Set from Stream and than convert it to list? Also, how can we get ArrayList or LinkedList or Vector from Stream?

javin paul said...

@Anonymous, if Stream is not parallel then yes it preserve the stream order but with parallel stream there is no guarantee, because elements are traversed in arbitrary order.

If you get Set the order is already lost, you won't get order back by converting to list.

Yes, you can get ArrayList from Stream by using Collectors.toCollection(ArrayList::new) method. Similarly you can collect stream elements into LinkedList and Vector.

Post a Comment