“If we knew what it was we were doing, it would not be called research, would it?”
― Albert Einstein
Contents
1. Introduction
Java 8 Streams provide a cool facility to combine several operations in a single statement and express it concisely. Once the data is processed, you can collect the data in a List (or another collection). In this article, we present several methods to collect the results of these stream operations into collections.
2. Convert Stream to a List
Here is a simple example. Stream.of() creates a stream from the names which is collected in a list.
List<String> alist = Stream.of("Sarah", "Ariana", "Liliana", "Clara", "Mariah", "Naomi", "Bailey") .collect(Collectors.toList()); System.out.println(alist); # prints [Sarah, Ariana, Liliana, Clara, Mariah, Naomi, Bailey]
3. Stream to List: Specify the List Type
The method Collectors.toList() returns a List whose actual implementation is unknown. What if you want to collect the items in a particular type of list, say a LinkedList? Here is how you can do it?
List<String> alist = Stream.of("Sarah", "Ariana", "Liliana", "Clara", "Mariah", "Naomi", "Bailey") .collect(Collectors.toCollection(LinkedList::new));
Would you like to convert the Stream to a plain array instead of a Collection? Use toArray() as follows:
String[] arr = Stream.of("Sarah", "Ariana", "Liliana", "Clara", "Mariah", "Naomi", "Bailey") .toArray(String[]::new); System.out.println("t3: {" +Arrays.stream(arr).collect(Collectors.joining(", "))+"}"); # prints t3: {Sarah, Ariana, Liliana, Clara, Mariah, Naomi, Bailey}
4. Convert Stream to Set
Using the toSet() method is straightforward enough to convert a Stream to a Set.
Set<String> aset = Stream.of("Sarah", "Ariana", "Liliana", "Clara", "Mariah", "Naomi", "Bailey") .collect(Collectors.toSet()); System.out.println(aset); # prints [Naomi, Liliana, Mariah, Sarah, Clara, Ariana, Bailey]
And as before, to specify the type of the Set, use toCollection().
HashSet<String> aset = Stream.of("Sarah", "Ariana", "Liliana", "Clara", "Mariah", "Naomi", "Bailey") .collect(Collectors.toCollection(HashSet::new));
5. Convert Stream to Map
Converting data from a Stream to a Map is a bit more involved since you need a key mapper function and a value mapper function.
In the following example, we read a CSV file of first-name frequencies by state, apply a filter for the year 2010 and the state of CA, and collect the results in a map of Name => Frequency
.
String fileName = "StateNames.csv"; Pattern pattern = Pattern.compile(","); try (BufferedReader in = new BufferedReader(new FileReader(fileName));){ Map<String,Integer> amap = in .lines() .skip(1) .map(line -> pattern.split(line)) .filter(x -> x[2].equals("2010") && x[4].equals("CA") && Integer.parseInt(x[5]) > 50) .collect(Collectors.toMap(x -> x[1] + "(" + x[3] + ")", x -> new Integer(x[5]))); System.out.println(amap); } # prints ... Shaun(M)=54, Arturo(M)=217, Moises(M)=209, Malachi(M)=161, Maverick(M)=62, Erica(F)=70, Julieta(F)=80 ...
To specify the type of the Map to use, you need to specify a merge function and a map supplier function.
The merge function takes two values and returns a single value. It is used when there are multiple mappings for the same key. In our case, we know we won’t have collisions because the names are unique for a state, so we use a dummy function that just returns the first value.
... (x, y) -> x ...
And for the map supplier function, we use the constructor reference for HashMap.
... HashMap::new ...
The whole invocation now looks like this, and the output is a HashMap.
Map<String,Integer> amap = in .lines() .skip(1) .map(line -> pattern.split(line)) .filter(x -> x[2].equals("2010") && x[4].equals("CA") && Integer.parseInt(x[5]) > 50) .collect(Collectors.toMap(x -> x[1] + "(" + x[3] + ")", x -> new Integer(x[5]), (x, y) -> x, HashMap::new));
Review
We presented some ways of converting a java 8 Stream to several collection types, including a List, Set and Map.