How do I join two lists in Java?

1,170,563

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);
Share:
1,170,563
Robert Atkins
Author by

Robert Atkins

Updated on November 25, 2021

Comments

  • Robert Atkins
    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);
    
  • ddimitrov
    ddimitrov over 15 years
    Irresponsible use of annonymous class. As the OP said - don't use it in production code.
  • Jorn
    Jorn over 14 years
    Ugly and evil, just as almost any use of double brace initialization. It ís shorter, though ;)
  • Quantum7
    Quantum7 about 13 years
    Nice, but requires apache commons. He did specify 'no external libraries'
  • MarnixKlooster ReinstateMonica
    MarnixKlooster ReinstateMonica almost 13 years
    +1, nice. Although Eclipse splits over six lines for me, and tells me to @SuppressWarnings("serial"). :-)
  • Joachim Sauer
    Joachim Sauer over 12 years
    @MarnixKlooster: Eclipse knows that you should not use it and makes it unpleasant to use ;-)
  • Robert Atkins
    Robert Atkins over 12 years
    While 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
    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
    AgentKnopf almost 12 years
    Would this cause duplicated Strings? Meaning a String that exists in both list will exist twice in the resulting list?
  • simbo1905
    simbo1905 over 11 years
    that 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
    splungebob over 11 years
    Though it is physically one line, I do not consider this a "one-liner".
  • Quantum7
    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
    NimChimpsky over 11 years
    why do people hate anonymous block initializers
  • Patrick
    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
    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
    David almost 11 years
    why should someone never use those?
  • Adrian Shum
    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
    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
    Michael Piefel over 10 years
    Avoid 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.
    Jimmy T. over 10 years
    How does the use of double brace initialization makes it a one-liner?
  • Robert Atkins
    Robert Atkins over 10 years
    Not 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
    Robert Atkins over 10 years
    Gawd, that's a thing in Java 8? Technically you win I guess, but that's a heck of a long line :-)
  • Richard
    Richard over 10 years
    @MichaelPiefel it seems the only method missing from Guava is a Lists.concat(...) method.
  • Michael Piefel
    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, use Lists.newArrayList(Iterables.concat(…)).
  • mingfai
    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
    meilechh about 10 years
    For example: Lists.newArrayList(Iterables.concat(list1,list2));
  • jwj
    jwj over 9 years
    This 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
    Radon Rosborough over 9 years
    Don't forget the @SafeVarargs!
  • Kevin K
    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 about CompositeUnmodifiableList are also true of Collections.unmodifiableList() as well.
  • Martin
    Martin almost 9 years
    x -> x.stream() could be replaced with Collection::stream.
  • Eric
    Eric about 8 years
    Isn'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
    bob about 8 years
    you should call com.google.common.collect.Iterators#concat(java.util.Iterato‌​r<? extends java.util.Iterator<? extends T>>) instead of Iterables#concat(); because the later still copy elements into temp link!
  • luk2302
    luk2302 over 7 years
    That 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
    Jorn over 7 years
    I wonder if creating and running through two Streams has a noticeable performance impact. I suppose it shouldn't, compared to creating two Iterators.
  • manuelvigarcia
    manuelvigarcia over 7 years
    This 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
    Stephan over 7 years
    For the casual reader, here is a shorter solution using also Java _ Streams: stackoverflow.com/a/34090554/363573
  • Tzen
    Tzen over 7 years
    Apache'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
    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
    Patrick Parker about 7 years
    The constructor can take List<? extends E>
  • Anton Balaniuc
    Anton Balaniuc about 7 years
    If 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
    Miles about 7 years
    This approach is already suggested by this answer: stackoverflow.com/a/37386846
  • Stefan Haberl
    Stefan Haberl almost 7 years
    I 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
    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
    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 of newListcame from (for example if newList was passed as a parameter.
  • 11684
    11684 over 6 years
    I'm curious; why .forEach(newList::addAll); instead of .collect(Collectors.toList());?
  • SpaceTrucker
    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
    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
    Egor Hans over 6 years
    @luk2302 Contains no semicolons though (except at the end), so it can be considered a one-liner.
  • Egor Hans
    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
    Egor Hans over 6 years
    I don't even understand what part is actually meant to be the answer...
  • Adrian Shum
    Adrian Shum over 6 years
    There 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
    Michael Haefele over 6 years
    Upvoted 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
    Usman Ismail over 6 years
    It 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
    Pat Myron almost 6 years
    Unfortunately, ListUtils.union() does not support more than 2 parameters
  • Roger
    Roger over 5 years
    I 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
    MC Emperor over 5 years
    ...or even with List::stream.
  • kravemir
    kravemir over 5 years
    This would create a new annonymous class. Not recommended approach!
  • Peter Walser
    Peter Walser about 5 years
    Alternative to concat: stream of streams Stream.of(listOne, listTwo).flatMap(Collection::stream).collect(Collectors.toLi‌​st())
  • shmosel
    shmosel almost 5 years
    How is the static import or the helper class relevant?
  • zh chen
    zh chen over 4 years
    This is basically the same thing of C# List<string> l = list1.Union(list2).ToList();, but is much more verbose.
  • FishingIsLife
    FishingIsLife over 4 years
    A few sentences of explanation would help a lot. Please keep that in mind for future comments
  • Jay
    Jay over 4 years
    Thanks, or even simpler listOne.addAll(listTwo)
  • Jason Aller
    Jason Aller about 4 years
    When 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
    Raymond Chenon about 4 years
    Use a LinkedList over ArrayList for efficient adding. stackoverflow.com/a/322742/311420
  • bvdb
    bvdb almost 4 years
    whenever you see usages of Vector, take a 5 minute break.
  • regulus
    regulus over 3 years
    oh boy, what if the items in the list have comma in them?
  • Raphael
    Raphael over 3 years
    @PeterWalser That should be a separate answer, since it also allows more than one list. flatMap, good call!
  • Raphael
    Raphael over 3 years
    Usually, when I get to a point where the only reasonable API is the one for streams, I realize that listOne and listTwo should have been streams all along.
  • wilmol
    wilmol about 3 years
    I dont think flatMap causes additional iteration, could you clarify?
  • Christian Brüggemann
    Christian Brüggemann about 3 years
    Without performance benchmarks, this is questionable advice, especially since your argument about add does not refer to the bulk addAll operation.
  • Kareem Jeiroudi
    Kareem Jeiroudi about 3 years
    But the union of two lists includes only distinct elements. Joining two lists must include all elements (duplicates or not).
  • Kira Resari
    Kira Resari almost 3 years
    Nice. I like this approach.
  • Farrukh Chishti
    Farrukh Chishti about 2 years
    Super. Also null safe. Both lists can be null and it would still work !