Explain Codes LogoExplain Codes Logo

How can I turn a List of Lists into a List in Java 8?

java
list-flattening
streams
functional-programming
Nikita BarsukovbyNikita Barsukov·Aug 3, 2024
TLDR

Convert a List<List<T>> into a List<T> sing flatMap in Java 8:

List<T> flatList = listOfLists.stream() .flatMap(Collection::stream) .collect(Collectors.toList());

This usage of flatMap allows lists to be merged and then transformed into a List, maintaining the order of original elements.

Peel the onion: Detailed explanation

Let's dive into the layers and explore additional ways of converting nested lists in Java 8.

When flatMap is too mainstream: Using forEach and addAll

If you find flatMap a bit too trendy, or just prefer a good old-school way of doing things, here's an alternative using forEach and List.addAll:

// Because doing thngs the cool kid's way is too mainstream, right? List<Object> flatList = new ArrayList<>(); listOfLists.forEach(flatList::addAll);

Collector's item: Using custom collections

If your heart set on a specific type of collection:

// Your wish is Java's command! List<T> flatList = listOfLists.stream() .flatMap(List::stream) .collect(Collectors.toCollection(LinkedList::new));

Because two heads are better than one: Using reduce

For those feeling particularly academic or adventurous, there's a reduce option using addAll:

// "Two of us... List<Object> flatList = listOfLists.stream() .reduce(new ArrayList<>(), (acc, list) -> { acc.addAll(list); return acc; });

Turn the function up: Streamlining with method references

For the enthusiasts embracing functional programming, let's make that code snappy with some method references:

// Saving the world, one keystroke at a time! List<T> mergedByMethodRef = listOfLists.stream() .flatMap(List::stream) .collect(Collectors.toCollection(ArrayList::new));

Null, the unexpected guest: Handling nulls and empty lists

Handling null elements or empty lists is like expecting unexpected guests. Gracefully handle these with the filter method:

// At least it's not an ArrayIndexOutOfBoundsException... List<T> flatListWithFilter = listOfLists.stream() .filter(Objects::nonNull) .flatMap(List::stream) .collect(Collectors.toList());

Flat is not enough: Going beyond

When flattening a List<List<T>> is simply the beginning of your journey, here are additional transformations you can apply to the stream elements.

Counter-Strike: Mapping during flattening

In the legendary clash between Mapping and Flattening, why choose one over the other?:

// In a world...where map and flatMap can coexist. List<U> flatMappedList = listOfLists.stream() .flatMap(list -> list.stream().map(T::someTransformation)) .collect(Collectors.toList());

Divide and conquer: Parallelizing for performance

Wrestling with large datasets? Use parallel streams for a potential performance improvement:

// It's not about working hard, it's about working smart. List<T> parallelFlatList = listOfLists.parallelStream() .flatMap(List::stream) .collect(Collectors.toList());

However, keep in mind, that performance benefits are not guaranteed and the original order of elements might not be preserved.

Diplomatic immunity: A look at languages

For those interested in seeing how Java's list flattening compares to another language, here's the Python's list comprehension equivalent:

# Python equivalent # When Python says "I come in peace". flat_list = [item for sublist in list_of_lists for item in sublist]