1. Introduction
Do you want to know the simplest way to join two data sets in Java? Check out this article on concatenating collections in Java and learn how easy it can be! No matter what objects or primitives you are dealing with, concatenating collections must no longer be challenging. With just a few lines of code, merging simple or complex datasets is now possible – why wait any longer?
Concatenation in Java often entails preserving the order of all the elements from different collections, such as lists, sets, or maps, into a single collection. The addAll() method and the Java Stream API are a few common approaches for loops. Third-party libraries like Apache Commons may provide the same operations more quickly.
2. Concatenating Collections Using Java Stream API
Using the Java Stream API, we can concatenate collections in Java. A functional and declarative programming approach is provided by this robust tool, which makes many operations—such as merging collections—simpler.
The Stream.concat() method can combine two collections. This technique produces a concatenated stream comprising every element from the first stream and every element from the second stream. If one of the input streams is parallel or is ordered, the output stream will be parallel.
Here’s an example to demonstrate merging two lists of strings:
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class ConcatCollectionsExample { public static void main(String[] args) { List<String> list1 = Arrays.asList("a", "b", "c"); List<String> list2 = Arrays.asList("d", "e", "f"); List<String> mergedList = Stream.concat(list1.stream(), list2.stream()) .collect(Collectors.toList()); System.out.println(mergedList); // Output: [a, b, c, d, e, f] } }
We might need to ensure there are no duplicate elements in the final collection when concatenating sets in Java. In this situation, we may use the Collectors.toSet() collector to turn the concatenated stream into a set:
import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; public class ConcatCollectionsExample { public static void main(String[] args) { Set<String> set1 = new HashSet<>(Arrays.asList("a", "b", "c")); Set<String> set2 = new HashSet<>(Arrays.asList("c", "d", "e")); Set<String> mergedSet = Stream.concat(set1.stream(), set2.stream()) .collect(Collectors.toSet()); System.out.println(mergedSet); // Output: [a, b, c, d, e] } }
When concatenating sets, remember that the order of the items cannot be preserved.
It’s important to note that by chaining several calls to Stream.concat(), we can concatenate more than two collections using the same method. However, using the Stream.of() method with flatMap() in these circumstances is thought to be more readable and compelling:
import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; public class ConcatCollectionsExample { public static void main(String[] args) { List<String> list1 = Arrays.asList("a", "b", "c"); List<String> list2 = Arrays.asList("d", "e", "f"); List<String> list3 = Arrays.asList("g", "h", "i"); List<String> mergedList = Stream.of(list1, list2, list3) .flatMap(List::stream) .collect(Collectors.toList()); // Output: [a, b, c, d, e, f, g, h, i] System.out.println(mergedList); } }
3. Concatenating Collections Using Java for Loops
It’s vital to note that Java for loops may be used to work with any form of collection, including lists, sets, and maps before we go into the code. Despite not being the most effective way to concatenate collections, it does the job.
Start with a straightforward illustration. Consider the scenario where we need to combine two ArrayList objects into a single ArrayList. Here’s how a Java for loop can help us accomplish that:
List<String> list1 = Arrays.asList("a", "b", "c"); List<String> list2 = Arrays.asList("d", "e", "f"); List<String> concatenatedList = new ArrayList<>(list1); for (String element : list2) { concatenatedList.add(element); }
All the elements from the first list were used to initialise a new instance of the ArrayList class in the code above. The second list was iterated using a for-each loop, and each entry was then appended to the concatenated list.
Concatenate multiple collections, such as sets and maps, can be handled using this general strategy, albeit the implementation may vary slightly. For instance, we might utilise the AddAll() method of the destination set when concatenating sets:
Set<String> set1 = new HashSet<>(Arrays.asList("a", "b", "c")); Set<String> set2 = new HashSet<>(Arrays.asList("d", "e", "f")); Set<String> concatenatedSet = new HashSet<>(set1); concatenatedSet.addAll(set2);
If we have multiple collections, we can concatenate them by looping through each collection and adding it to the final result of the concatenation. But keep in mind that when working with huge collections, Java for loops might not be the most excellent option in terms of performance.
4. Combining Collections with the addAll Method
A destination collection and an array of elements to append are both accepted by the addAll function. This technique can be used to combine multiple collections, as seen below:
import java.util.ArrayList; import java.util.Collections; public class Main { public static void main(String[] args) { ArrayList<String> list1 = new ArrayList<>(); list1.add("alpha"); list1.add("bravo"); ArrayList<String> list2 = new ArrayList<>(); list2.add("charlie"); list2.add("delta"); Collections.addAll(list1, list2.toArray(new String[0])); System.out.println("Combined list: " + list1); } }
In this example, list1 and list2 are two ArrayList objects created with various string contents. We add all the elements from list2 to list1 using the addAll function. Before sending list2 to the addAll method, we use the toArray method to turn it into an array.
Other collection types like LinkedList, HashSet, or TreeSet can also be used using the addAll method. Applying the same procedure is possible if the element types line up. However, remember that when using addAll with unordered collections like HashSet, the order of the all the elements from the input collections cannot be preserved.
In conclusion, the addAll method in Java provides a straightforward, simple approach that can be used for various collection types for concatenating collections.
5. Apache Commons
Apache Commons has a utility class, ListUtils, allows combining two lists. Internally it uses a similar approach as the example before, and the concatenation is achieved in a single line. The advantage of a single-line approach disappears if the number of lists to combine is more than two since the union method only takes two parameters.
private static List<String> union(List<String> one, List<String> two) { List<String> three = ListUtils.union(one, two); return three; }
We can also use the IterableUtils class to join collections together. We can accomplish this by invoking the chainedIterable method and passing it to our collections as parameters. This function returns a single Iterable that enables traversal through the input collections’ elements in the specified order. A lazy concatenation is provided by not polling the source iterators until it is necessary to do so.
Let’s use two lists as an example:
import org.apache.commons.collections4.IterableUtils; List<String> list1 = Arrays.asList("Apple", "Banana", "Cherry"); List<String> list2 = Arrays.asList("Orange", "Grape", "Mango"); Iterable<String> concatenated = IterableUtils.chainedIterable(list1, list2); for (String fruit : concatenated) { System.out.println(fruit); }
This method is advantageous when working with huge collections or needing the combined output quickly. It also works with other iterable types like queues and sets.
In conclusion, the Apache Commons Collections library makes Java collection concatenation simpler. We can quickly and lazily merge multiple collections into one logical collection using the chainedIterable method from IterableUtils without writing boilerplate code.
6. Performance Comparison
public static void main(String[] args) { List<String> one = new ArrayList<>(); List<String> two = new ArrayList<>(); IntStream.range(0, 1000000) .forEach(num -> { one.add("Test String"); two.add("Test String"); }); long startTime = System.currentTimeMillis(); of(one, two); long elapsed = (System.currentTimeMillis() - startTime); System.out.println("Elapsed by Stream Of: " + elapsed + "ms"); startTime = System.currentTimeMillis(); concat(one, two); elapsed = (System.currentTimeMillis() - startTime); System.out.println("Elapsed by Stream concat: " + elapsed + "ms"); startTime = System.currentTimeMillis(); addAll(one, two); elapsed = (System.currentTimeMillis() - startTime); System.out.println("Elapsed by addAll: " + elapsed + "ms"); startTime = System.currentTimeMillis(); union(one, two); elapsed = (System.currentTimeMillis() - startTime); System.out.println("Elapsed by union: " + elapsed + "ms"); }
I was curious about the performance of the different concatenation approaches, so I decided to conduct a little performance test on each. The test data consists of two lists with million elements each. Below I have captured the runtime of each method once the concatenation has been completed.
Elapsed by Stream Of: 90ms
Elapsed by Stream concat: 73ms
Elapsed by addAll: 260ms
Elapsed by union: 41ms
As you can see, the difference in ms varies between the methods, which will further increase when dealing with a more substantial number of elements. However, if many elements are not a concern or the application is not performance critical, you can get away with any of them.
Last, keep in mind that Java’s performance may differ between versions. String concatenation performance, for instance, can vary between Java 8 and Java 11. Make sure to verify the functionality of your code on the particular Java version you’re aiming for.
7. Summary
We’ve investigated the most straightforward methods to concatenate collections in Java, examining each option’s talents and suggesting when it might be best used. To cap off our exploration, we conducted a race between these solutions – pitting them against one another with test lists of a million elements apiece! It was close, but one method came out on top… guess you’ll have to read through this article for the results!
Daniel Barczak
Daniel Barczak is a software developer with a solid 9-year track record in the industry. Outside the office, Daniel is passionate about home automation. He dedicates his free time to tinkering with the latest smart home technologies and engaging in DIY projects that enhance and automate the functionality of living spaces, reflecting his enthusiasm and passion for smart home solutions.
Leave a Reply