Introduction: Why Merge Lists in Java and How to Avoid Confusion
Imagine: you have two task lists — "urgent" and "important". Or two client lists — from last month's database and this month's. To work with them as a single whole, you need to merge them. In Java, this task is so common that the question "How do I join two lists in Java?" on Stack Overflow gathers thousands of views. And this is no coincidence: for beginners, merging lists often causes confusion — either a compilation error, or the list turns out to be immutable, or data gets lost.
In this article, we will cover 5 proven ways to merge two lists in Java — from the classic addAll to the elegant Stream API. You will learn which method to choose for different situations, how to avoid pitfalls, and how to write code that works quickly and predictably. Let's go!
Method 1: Classic addAll — Simple and Reliable
The most straightforward way is to use the addAll() method from the Collection interface. It adds all elements of one collection to another. Sounds ideal, but there is a nuance: it modifies the original list. If you need to keep the original lists untouched — create a new one.
Example: Merging While Preserving Originals
import java.util.ArrayList;import java.util.List;
public class JoinListsExample { public static void main(String[] args) { List<String> listA = new ArrayList<>(List.of("Java", "Python", "C++")); List<String> listB = new ArrayList<>(List.of("JavaScript", "Go", "Rust"));
// Create a new list and add both lists to it List<String> mergedList = new ArrayList<>(listA); mergedList.addAll(listB);
System.out.println(mergedList); // [Java, Python, C++, JavaScript, Go, Rust] // Original lists remain unchanged }}Pros: intuitive, works with any List types, does not require Java 8+.
Cons: modifies the original list if not creating a new one; does not support lazy evaluation.
Method 2: Stream API — Modern and Flexible
If you are using Java 8 or newer, the Stream API offers an elegant way to merge lists. It does not modify the original data and easily combines with other operations — filtering, sorting, transformation.
Basic Merging with Stream.concat
import java.util.List;import java.util.stream.Collectors;import java.util.stream.Stream;
public class StreamJoinExample { public static void main(String[] args) { List<String> listA = List.of("Red", "Green", "Blue"); List<String> listB = List.of("Yellow", "Purple");
List<String> mergedList = Stream.concat(listA.stream(), listB.stream()) .collect(Collectors.toList());
System.out.println(mergedList); // [Red, Green, Blue, Yellow, Purple] }}Merging with Filtering and Sorting
Suppose you need to merge two lists of numbers, keep only even numbers, and sort them in descending order:
import java.util.List;import java.util.Comparator;import java.util.stream.Collectors;import java.util.stream.Stream;
public class StreamAdvancedJoin { public static void main(String[] args) { List<Integer> listA = List.of(5, 2, 8, 1); List<Integer> listB = List.of(7, 4, 9, 3);
List<Integer> result = Stream.concat(listA.stream(), listB.stream()) .filter(n -> n % 2 == 0) // only even numbers .sorted(Comparator.reverseOrder()) .collect(C