How do I join two lists in Java?
Solution 1
In Java 8:
List<String> newList = Stream.concat(listOne.stream(), listTwo.stream())
.collect(Collectors.toList());
Solution 2
Off the top of my head, I can shorten it by one line:
List<String> newList = new ArrayList<String>(listOne);
newList.addAll(listTwo);
Solution 3
You could use the Apache commons-collections library:
List<String> newList = ListUtils.union(list1, list2);
Solution 4
Another Java 8 one-liner:
List<String> newList = Stream.of(listOne, listTwo)
.flatMap(Collection::stream)
.collect(Collectors.toList());
As a bonus, since Stream.of()
is variadic, you may concatenate as many lists as you like.
List<String> newList = Stream.of(listOne, listTwo, listThree)
.flatMap(Collection::stream)
.collect(Collectors.toList());
Solution 5
One of your requirements is to preserve the original lists. If you create a new list and use addAll()
, you are effectively doubling the number of references to the objects in your lists. This could lead to memory problems if your lists are very large.
If you don't need to modify the concatenated result, you can avoid this using a custom list implementation. The custom implementation class is more than one line, obviously...but using it is short and sweet.
CompositeUnmodifiableList.java:
public class CompositeUnmodifiableList<E> extends AbstractList<E> {
private final List<? extends E> list1;
private final List<? extends E> list2;
public CompositeUnmodifiableList(List<? extends E> list1, List<? extends E> list2) {
this.list1 = list1;
this.list2 = list2;
}
@Override
public E get(int index) {
if (index < list1.size()) {
return list1.get(index);
}
return list2.get(index-list1.size());
}
@Override
public int size() {
return list1.size() + list2.size();
}
}
Usage:
List<String> newList = new CompositeUnmodifiableList<String>(listOne,listTwo);
Robert Atkins
Updated on November 25, 2021Comments
-
Robert Atkins over 2 years
Conditions: do not modify the original lists; JDK only, no external libraries. Bonus points for a one-liner or a JDK 1.3 version.
Is there a simpler way than:
List<String> newList = new ArrayList<String>(); newList.addAll(listOne); newList.addAll(listTwo);
-
Boris Treukhov almost 10 yearsIf you are doing this solely for iteration purposes see another question - there are google guava and java 8 solutions stackoverflow.com/questions/4896662/…
-
akhil_mittal almost 7 yearsJava 8 solution with utility method: stackoverflow.com/a/37386846/1216775
-
-
ddimitrov over 15 yearsIrresponsible use of annonymous class. As the OP said - don't use it in production code.
-
Jorn over 14 yearsUgly and evil, just as almost any use of double brace initialization. It ís shorter, though ;)
-
Quantum7 about 13 yearsNice, but requires apache commons. He did specify 'no external libraries'
-
MarnixKlooster ReinstateMonica almost 13 years+1, nice. Although Eclipse splits over six lines for me, and tells me to
@SuppressWarnings("serial")
. :-) -
Joachim Sauer over 12 years@MarnixKlooster: Eclipse knows that you should not use it and makes it unpleasant to use ;-)
-
Robert Atkins over 12 yearsWhile you're technically correct, you have shortened it by one line, the asymmetry of this bugs me. Enough that I'm happier to "spend" the extra line.
-
tster about 12 years@Quantum7, still useful for other people ;) Also, is apache commons even an external library? I don't start anything without it!
-
AgentKnopf almost 12 yearsWould this cause duplicated Strings? Meaning a String that exists in both list will exist twice in the resulting list?
-
simbo1905 over 11 yearsthat is know as a "double brace object" which very handy in junit test code to create an object which returns a given value as you can invoke the protected setter right there and pass in some final reference to test data. then again with a good mocking framework...
-
splungebob over 11 yearsThough it is physically one line, I do not consider this a "one-liner".
-
Quantum7 over 11 years@Platinum No, according to the docs ListUtils.union is exactly equivalent to OP's code. But perhaps it is misleading to use a SET operation ("Union") in a list context. I can see how you might expect this to remove duplicates or something, but it appears the method does not do that.
-
NimChimpsky over 11 yearswhy do people hate anonymous block initializers
-
Patrick over 11 years@Zainodis Yes, there could be duplicates. The
List
structure imposes no uniqueness constraints. You can remove dupes by doing the same thing with sets.Set<String> newSet = new HashSet<>(setOne); newSet.addAll(setTwo);
-
Patrick over 11 years@NimChimpsky I think it's mostly because it's not just an anonymous block initializer, but you're actually creating an anonymous subclass of ArrayList. That being said, if you trust the results of this Double Brace Initilization question, it makes it seem like hating DBI is mostly a matter of stylistic taste and micro-optimization. As far as I can tell, there are no major penalties for doing it. The sneaky downside would be if you ever tried to compare its class because it won't be ArrayList.
-
David almost 11 yearswhy should someone never use those?
-
Adrian Shum almost 11 years@David because it aimed to be used internally in JDK. If you used that in your code, your code will quite probably not running on non-Sun (or non-Oracle now) JDK/JRE.
-
TWiStErRob over 10 years@MarnixKlooster it doesn't tell you to add suppress warnings, it tells you there's something wrong with the code, and of course "if you turn the log-level to FATAL you don't get DEBUG messages"
-
Michael Piefel over 10 yearsAvoid Apache Commons Collections. It’s not typesafe, there are no generics. Great if you use Java 1.4, but for Java 5 and above, I’d prefer Google Guava.
-
Jimmy T. over 10 yearsHow does the use of double brace initialization makes it a one-liner?
-
Robert Atkins over 10 yearsNot modifying the original lists was one of the criteria, but this is useful to have here as an example for situations where that's not a constraint.
-
Robert Atkins over 10 yearsGawd, that's a thing in Java 8? Technically you win I guess, but that's a heck of a long line :-)
-
Richard over 10 years@MichaelPiefel it seems the only method missing from Guava is a Lists.concat(...) method.
-
Michael Piefel over 10 years@Richard Yes, but how about
Iterables.concat()
? Most of the times its exactly what you want. If you absolutely need a new list, useLists.newArrayList(Iterables.concat(…))
. -
mingfai over 10 years@MichaelPiefel The latest Apache Commons Collections 4 is type-safe. With Java 8 method reference, this kind of static utilities become very important.
-
meilechh about 10 yearsFor example: Lists.newArrayList(Iterables.concat(list1,list2));
-
jwj over 9 yearsThis is a workable solution, but do note that if the underlying list objects change (list1, list2), the contents of this list change. You may not be able to modify an instance of the CompositeUnmodifiableList itself but if you can get a reference to the original lists, then you can. Also for those that are unfamiliar: the final modifier just affects the reference to the list object itself can't change but it's still possible for the contents of the list to change!
-
Radon Rosborough over 9 yearsDon't forget the
@SafeVarargs
! -
Kevin K about 9 years@jwj all very good points, thank you. The class name probably deserves some explanation. I see this class as doing something very similar to the
Collections.unmodifiableList()
method, which wraps a list to make it unmodifiable.CompositeUnmodifiableList
does the same thing, except it wraps two lists and provides a concatenated view. All the points you make aboutCompositeUnmodifiableList
are also true ofCollections.unmodifiableList()
as well. -
Martin almost 9 years
x -> x.stream()
could be replaced withCollection::stream
. -
Eric about 8 yearsIsn't there a problem here where the newList's interal array will be initialized to the size of listOne and then have to potentially expand when adding all of the items from listTwo? Would it be better to take the size of each list and use that to size the new array?
-
bob about 8 yearsyou should call
com.google.common.collect.Iterators#concat(java.util.Iterator<? extends java.util.Iterator<? extends T>>)
instead ofIterables#concat()
; because the later still copy elements into temp link! -
luk2302 over 7 yearsThat is one disgusting line of code. Probably highly more performance intensive than all the other solutions (combined), makes a ton of assumptions you should really not have to make, not really a one-liner (you can put an entire program into one line technically).
-
Jorn over 7 yearsI wonder if creating and running through two Streams has a noticeable performance impact. I suppose it shouldn't, compared to creating two Iterators.
-
manuelvigarcia over 7 yearsThis was the solution that worked best for me. I made a comparison on the performance of different solutions this came out winner, together with creating the empty list and then
addAll()
of both. I tried all those that suggest not copying the lists and they result having a lot of overhead we didn't need this time. -
Stephan over 7 yearsFor the casual reader, here is a shorter solution using also Java _ Streams: stackoverflow.com/a/34090554/363573
-
Tzen over 7 yearsApache's ListUtils is a very good library, easy to use ListUtils.uniion(list1, list2) as you say, but do you need the other methods, for instance longestCommonSubsequence(...) or fixedSizeList(...)? Can be useful to consider what else is dragged in that you might not need when it is so easy to join lists as List.addAll()
-
riwnodennyk over 7 years@NimChimpsky another reason why anonymous block initializers may be evil is that they will leak the outer object instance same as any anonymous class in Java. However, should be safe to use in static methods.
-
Patrick Parker about 7 yearsThe constructor can take
List<? extends E>
-
Anton Balaniuc about 7 yearsIf I am not wrong this is actually not recommended - docs.oracle.com/javase/8/docs/api/java/util/stream/… Please see side -effects section. > Side-effects in behavioral parameters to stream operations are, in general, discouraged, as they can often lead to unwitting violations of the statelessness requirement, as well as other thread-safety hazards. So in this case it is better to use Collectors.toList()
-
Miles about 7 yearsThis approach is already suggested by this answer: stackoverflow.com/a/37386846
-
Stefan Haberl almost 7 yearsI would add that this solution is probably more performant than the one using
flatMap
, because the lists are only iterated once when they are collected -
Alex almost 7 years@NimChimpsky You can check out this article about the disadvantages of double brace initialisation: Don’t be “Clever”: The Double Curly Braces Anti Pattern
-
SpaceTrucker almost 7 years@AntonBalaniuc Question is if whether this is really a side effect. At that point
newList
is not observable by any other thread. But you are correct that this probably shouldn't be done if it is unknown where the value ofnewList
came from (for example ifnewList
was passed as a parameter. -
11684 over 6 yearsI'm curious; why
.forEach(newList::addAll);
instead of.collect(Collectors.toList());
? -
SpaceTrucker over 6 years@11684 because the collector would collect a
List<List<Object>>
. What you may have in mind is something like this: stackoverflow.com/questions/189559/… -
11684 over 6 years@SpaceTrucker Oops, I overlooked that. Thanks for clearing up my confusion. Yes, I should have been thinking of
flatMap
. -
Egor Hans over 6 years@luk2302 Contains no semicolons though (except at the end), so it can be considered a one-liner.
-
Egor Hans over 6 years@AdrianShum Are there other JDKs/JREs than Oracle? That would surprise me. Even if limited to the most common API functionality, rebuilding that whole stuff would probably take ages...
-
Egor Hans over 6 yearsI don't even understand what part is actually meant to be the answer...
-
Adrian Shum over 6 yearsThere is quite a lot of JVM. Most commonly seen one in enterprise world should be the IBM one which is, iirc, bundled with websphere
-
Michael Haefele over 6 yearsUpvoted as this is the only answer that didn't require multiple method calls. Streams are fun, but having to do n method calls for every...single...little....thing... seems error prone. Joining two lists SHOULD be a simple operation.
-
Usman Ismail over 6 yearsIt is ugly but at least its fluent and can be used without multi line lambdas. I really wish there was a fluent addAll that returned the concatinated list.
-
Pat Myron almost 6 yearsUnfortunately, ListUtils.union() does not support more than 2 parameters
-
Roger over 5 yearsI guess it's worth noting that it's really easy to get a distinct list out of this too, like so:
List<String> newList = Stream.concat(listOne.stream(), listTwo.stream()).distinct().collect(Collectors.toList());
-
MC Emperor over 5 years...or even with
List::stream
. -
kravemir over 5 yearsThis would create a new annonymous class. Not recommended approach!
-
Peter Walser about 5 yearsAlternative to concat: stream of streams
Stream.of(listOne, listTwo).flatMap(Collection::stream).collect(Collectors.toList())
-
shmosel almost 5 yearsHow is the static import or the helper class relevant?
-
zh chen over 4 yearsThis is basically the same thing of C#
List<string> l = list1.Union(list2).ToList();
, but is much more verbose. -
FishingIsLife over 4 yearsA few sentences of explanation would help a lot. Please keep that in mind for future comments
-
Jay over 4 yearsThanks, or even simpler listOne.addAll(listTwo)
-
Jason Aller about 4 yearsWhen answering an eleven year old question with thirty other answers be sure to point out what new aspects of the question your answer addresses, and to note if these techniques would have worked when the question was asked, or if they depend on features that have been introduced over the years.
-
Raymond Chenon about 4 years
-
bvdb almost 4 yearswhenever you see usages of
Vector
, take a 5 minute break. -
regulus over 3 yearsoh boy, what if the items in the list have comma in them?
-
Raphael over 3 years@PeterWalser That should be a separate answer, since it also allows more than one list.
flatMap
, good call! -
Raphael over 3 yearsUsually, when I get to a point where the only reasonable API is the one for streams, I realize that
listOne
andlistTwo
should have been streams all along. -
wilmol about 3 yearsI dont think
flatMap
causes additional iteration, could you clarify? -
Christian Brüggemann about 3 yearsWithout performance benchmarks, this is questionable advice, especially since your argument about
add
does not refer to the bulkaddAll
operation. -
Kareem Jeiroudi about 3 yearsBut the union of two lists includes only distinct elements. Joining two lists must include all elements (duplicates or not).
-
Kira Resari almost 3 yearsNice. I like this approach.
-
Farrukh Chishti about 2 yearsSuper. Also null safe. Both lists can be null and it would still work !