How can I concatenate two arrays in Java?

1,264,510

Solution 1

I found a one-line solution from the good old Apache Commons Lang library.
ArrayUtils.addAll(T[], T...)

Code:

String[] both = ArrayUtils.addAll(first, second);

Solution 2

Here's a simple method that will concatenate two arrays and return the result:

public <T> T[] concatenate(T[] a, T[] b) {
    int aLen = a.length;
    int bLen = b.length;

    @SuppressWarnings("unchecked")
    T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen + bLen);
    System.arraycopy(a, 0, c, 0, aLen);
    System.arraycopy(b, 0, c, aLen, bLen);

    return c;
}

Note that it will not work with primitive data types, only with object types.

The following slightly more complicated version works with both object and primitive arrays. It does this by using T instead of T[] as the argument type.

It also makes it possible to concatenate arrays of two different types by picking the most general type as the component type of the result.

public static <T> T concatenate(T a, T b) {
    if (!a.getClass().isArray() || !b.getClass().isArray()) {
        throw new IllegalArgumentException();
    }

    Class<?> resCompType;
    Class<?> aCompType = a.getClass().getComponentType();
    Class<?> bCompType = b.getClass().getComponentType();

    if (aCompType.isAssignableFrom(bCompType)) {
        resCompType = aCompType;
    } else if (bCompType.isAssignableFrom(aCompType)) {
        resCompType = bCompType;
    } else {
        throw new IllegalArgumentException();
    }

    int aLen = Array.getLength(a);
    int bLen = Array.getLength(b);

    @SuppressWarnings("unchecked")
    T result = (T) Array.newInstance(resCompType, aLen + bLen);
    System.arraycopy(a, 0, result, 0, aLen);
    System.arraycopy(b, 0, result, aLen, bLen);        

    return result;
}

Here is an example:

Assert.assertArrayEquals(new int[] { 1, 2, 3 }, concatenate(new int[] { 1, 2 }, new int[] { 3 }));
Assert.assertArrayEquals(new Number[] { 1, 2, 3f }, concatenate(new Integer[] { 1, 2 }, new Number[] { 3f }));

Solution 3

Using Stream in Java 8:

String[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b))
                      .toArray(String[]::new);

Or like this, using flatMap:

String[] both = Stream.of(a, b).flatMap(Stream::of)
                      .toArray(String[]::new);

To do this for a generic type you have to use reflection:

@SuppressWarnings("unchecked")
T[] both = Stream.concat(Arrays.stream(a), Arrays.stream(b)).toArray(
    size -> (T[]) Array.newInstance(a.getClass().getComponentType(), size));

Solution 4

It's possible to write a fully generic version that can even be extended to concatenate any number of arrays. This versions require Java 6, as they use Arrays.copyOf()

Both versions avoid creating any intermediary List objects and use System.arraycopy() to ensure that copying large arrays is as fast as possible.

For two arrays it looks like this:

public static <T> T[] concat(T[] first, T[] second) {
  T[] result = Arrays.copyOf(first, first.length + second.length);
  System.arraycopy(second, 0, result, first.length, second.length);
  return result;
}

And for a arbitrary number of arrays (>= 1) it looks like this:

public static <T> T[] concatAll(T[] first, T[]... rest) {
  int totalLength = first.length;
  for (T[] array : rest) {
    totalLength += array.length;
  }
  T[] result = Arrays.copyOf(first, totalLength);
  int offset = first.length;
  for (T[] array : rest) {
    System.arraycopy(array, 0, result, offset, array.length);
    offset += array.length;
  }
  return result;
}

Solution 5

Or with the beloved Guava:

String[] both = ObjectArrays.concat(first, second, String.class);

Also, there are versions for primitive arrays:

  • Booleans.concat(first, second)
  • Bytes.concat(first, second)
  • Chars.concat(first, second)
  • Doubles.concat(first, second)
  • Shorts.concat(first, second)
  • Ints.concat(first, second)
  • Longs.concat(first, second)
  • Floats.concat(first, second)
Share:
1,264,510
devlearn
Author by

devlearn

Updated on April 02, 2022

Comments

  • devlearn
    devlearn about 2 years

    I need to concatenate two String arrays in Java.

    void f(String[] first, String[] second) {
        String[] both = ???
    }
    

    Which is the easiest way to do this?

    • Ben Page
      Ben Page about 8 years
      Bytes.concat from Guava
    • Artur Opalinski
      Artur Opalinski almost 8 years
      I see a lot of responses here but the question is so worded ('easiest way' ?) that it does not allow to indicate the best answer...
    • Douglas Held
      Douglas Held over 7 years
      Dozens of answers here are copying the data into a new array because that is what was asked for - but copying data when not strictly necessary is a bad thing to do especially in Java. Instead, keep track of the indexes and use the two arrays as if they were joined. I have added a solution illustrating the technique.
    • Bill K
      Bill K over 6 years
      The simplest is that you probably shouldn't be using arrays in the first place, you should be using ArrayLists, and your output should be an ArrayList. Once you've made these your pre-condition, the operation is built-in--first.addAll(second). The only case where this wouldn't be pretty much automatic is when your arrays are non-object types (int, long, double, ...), in that case intrinsic arrays can have a big advantage over ArrayLists--but for Strings--meh
    • JollyJoker
      JollyJoker over 6 years
      The fact that a question like this currently has 50 different answers makes me wonder why Java never got a simple array1 + array2 concatenation.
    • rghome
      rghome about 6 years
      You can do it perfectly well and very efficiently in two lines of standard Java (see my answer), so there is not an awful lot to be gained by having a single method to do it. All of these weird-and-wonderful solutions are a bit of a waste of time.
  • Tim Frey
    Tim Frey over 15 years
    Had to downvote this one for all the unnecessary List object creation.
  • Dan Dyer
    Dan Dyer over 15 years
    You can suppress the warning for this method, but other than that there isn't much you can do. Arrays and generics don't really mix.
  • Lorenzo Boccaccia
    Lorenzo Boccaccia over 15 years
    this however means that you are returning the same array and changing a value on the returned array changes the value in the same position of the input array returned.
  • volley
    volley about 15 years
    Yes - see comment at the end of my post regarding array re-usage. The maintenance overhead imposed by this solution was worth it in our particular case, but defensive copying should probably be used in most cases.
  • Joachim Sauer
    Joachim Sauer about 15 years
    The unchecked warning can be eliminated if you use Arrays.copyOf(). See my answer for an implementation.
  • Josh
    Josh about 15 years
    @SuppressWarnings("unchecked")
  • palantus
    palantus almost 15 years
    I still like Joachim Sauer's solution better.
  • Damo
    Damo almost 15 years
    I'm still on Java 5 so can't use Arrays.copyOf() as Joachim is doing.
  • AdamC
    AdamC almost 15 years
    I agree, this isn't really answering the question. High level libraries can be great, but if you want to learn an efficient way to do it, you want to look at the code the library method is using. Also, in many situations, you can't just through another library in the product on the fly.
  • Adam
    Adam over 14 years
    I think this is a good answer. POJO solutions have also been provided, but if the OP is using Apache Commons in their program already (altogether possible considering its popularity) he may still not know this solution. Then he wouldn't be "adding a dependency for this one method," but would be making better use of an existing library.
  • Rosdi Kasim
    Rosdi Kasim almost 14 years
    Lorenzo / volley, can you explain which part in the code that cause array re-usage? I thought System.arraycopy copies the content of the array?
  • volley
    volley almost 14 years
    A caller would normally expect a call to concat() to return a newly allocated array. If either a or b is null, concat() will however return one of the arrays passed into it. This re-usage is what may be unexpected. (Yep, arraycopy only does copying. The re-usage comes from returning either a or b directly.)
  • bancer
    bancer over 13 years
    +1. It would be better to replace the second for loop with that: for(int j = 0; j < arr2.length; j++){arrBoth[arr1.length+j] = arr2[j];}
  • KJW
    KJW over 13 years
    @Outlaw Programmer, I think most people would rather have the simplest possible method. Java is verbose enough already.
  • kvn
    kvn about 13 years
    I like this suggestion since it is less dependent on the latest Java versions. In my projects I'm often stuck using older versions of Java or CLDC profiles where some of the facilities like those mentioned by Antti are not available.
  • Joachim Sauer
    Joachim Sauer almost 13 years
    @djBO: for primitive-typed arrays you'd need to make an overload for each type: just copy the code and replace each T with byte (and lose the <T>).
  • Johnydep
    Johnydep almost 13 years
    can you plese tell me how to use <T> operator type in my class?
  • Martin
    Martin almost 13 years
    Easy yes. But converting to and from a List does not sound very performant.
  • rektide
    rektide over 12 years
    Good general idea, but to anyone implementing: I'd prefer a copyOf and non-copyOf versions than one that does both by way of reflection.
  • marathon
    marathon over 12 years
    I'd add this to the beginning, just to be defensive. if (first == null) { if (second == null) { return null; } return second; } if (second == null) { return first; }
  • Sam Goldberg
    Sam Goldberg over 12 years
    @djBo: what about:ByteBuffer buffer = ByteBuffer.allocate(array1.length + array2.length); buffer.put(array1); buffer.put(array2); return buffer.array();
  • Leigh
    Leigh about 12 years
    Welcome to stackoverflow. As this question is quite old, and System.arraycopy was thoroughly discussed already, it is best to avoid resurrecting old threads unless the response contributes something significant to the thread.
  • Johnny Lim
    Johnny Lim almost 12 years
    I'm using commons-lang-2.4.jar. There's no generic version of addAll() in ArrayUtils. So I had to cast the returned Object[] to String[] explicitly.
  • ShadowFlame
    ShadowFlame over 11 years
    reworked mine for File[], but it's the same. Thanks for your solution
  • marcorossi
    marcorossi about 11 years
    you could have given the reference to the answer as you did, and pasted the implementation from the source. that would have solved the issues above about the "cheating" aspect of your answer.
  • orique
    orique almost 11 years
    Tricky, it compiles only if first and second are final
  • Frimousse
    Frimousse almost 11 years
    True. I thought it was worth it to add a one-liner without external library.
  • Malcolm
    Malcolm almost 11 years
    The OP asked for the easiest way to solve the problem. This really is the easiest way, but only under the assumption that the library is already present, which is not mentioned in the question. Otherwise it is actually much easier to copy and paste several lines of code instead of copying just one and then messing with adding a separate library to the project.
  • T-Bull
    T-Bull almost 11 years
    There's a bug in this approach which becomes apparent if you invoke these functions with arrays of different component types, for example concat(ai, ad), where ai is Integer[] and ad is Double[]. (In this case, the type parameter <T> is resolved to <? extends Number> by the compiler.) The array created by Arrays.copyOf will have the component type of the first array, i.e. Integer in this example. When the function is about to copy the second array, an ArrayStoreException will be thrown. The solution is to have an additional Class<T> type parameter.
  • Ravi Wallau
    Ravi Wallau over 10 years
    As much as I love Guava, the method from Apache Commons deals better with nullables.
  • PhoneixS
    PhoneixS about 10 years
    Simply, but inefficient as it make an array for ArrayList and then generate another for toArray method. But still valid as it's simple to read.
  • user924272
    user924272 about 10 years
    While it is good to use libraries, it's unfortunate that the problem has been abstracted away. Therefore the underlying solution remains elusive.
  • Sam Goldberg
    Sam Goldberg almost 10 years
    @BrettOkken: yes - you are correct. I don't know why I suggested it... (probably because I had just written code to concatentate byte arrays...)
  • Breno Salgado
    Breno Salgado almost 10 years
    Whats the problem with abstraction? Dunno what's the deal with reinventing the wheel here, if you want to learn the problem the check the source or read on it. Professional code should be using high-level libraries, much better if it's developed inside Google!
  • Jonas Czech
    Jonas Czech about 9 years
    Probably quite inefficient though.
  • Jonas Czech
    Jonas Czech about 9 years
    ..But inefficient and slow.
  • Adriaan Koster
    Adriaan Koster about 9 years
    This is not concatenation but copying. The destination must already have enough space to accommodate all the sources or the above code will cause an ArrayIndexOutOfBoundsException.
  • dragon66
    dragon66 almost 9 years
    The following line will break the generic part: concatenate(new String[]{"1"},new Object[] { new Object()})
  • Hindol
    Hindol almost 9 years
    If you are always worried about not adding a library for a single method, no new libraries will ever get added. Given the excellent utilities present in Apache Commons, I highly recommend adding it when the very first use case arises.
  • usr-local-ΕΨΗΕΛΩΝ
    usr-local-ΕΨΗΕΛΩΝ over 8 years
    For performance reasons, I would pre-compute the ArrayList's final size because ArrayList, by definition, allocates a new array and copies its elements every time the current array is full. Otherwise I would go straight for LinkedList which does not suffer such problem
  • Tripp Kinetics
    Tripp Kinetics over 8 years
    You might want to add null checks. And perhaps set some of your variables to final.
  • Ky -
    Ky - over 8 years
    How efficient is this?
  • Synox
    Synox over 8 years
    WOW nice! why not change the compiler to realize a java syntax problem. :) bold move!
  • Trevor Brown
    Trevor Brown about 8 years
    Worth a read: jaxenter.com/… tl;dr - streams could be performant or not, it depends on what you're doing with them and the constraints of the problem (isn't this always the answer? lol)
  • Marcin Zukowski
    Marcin Zukowski about 8 years
    Yeah, it's a risky solution from the performance point of view. It might be fast, but I wouldn't bet my application's performance on it ;)
  • Kasun Siyambalapitiya
    Kasun Siyambalapitiya almost 8 years
    @Antti Sykäri sorry for asking I'm a newbie to Java, why is (String[]) is used in String[] both = (String[])ArrayUtils.addAll(first, second); without it will it not combine the 2 arrays
  • Jeryl Cook
    Jeryl Cook almost 8 years
    using apache commons should never be called 'cheating' i question the sanity of developers who thing its an unnecessary dependency.
  • Will Hardwick-Smith
    Will Hardwick-Smith almost 8 years
    Additionally, if a or b are arrays of primitive types, their streams will need to be .boxed() so they are of type Stream rather than e.g. IntStream which cannot be passed as a parameter to Stream.concat.
  • Abdu
    Abdu over 7 years
  • Ronen Rabinovici
    Ronen Rabinovici about 7 years
    The answer is great but a tiny bit broken. To make it perfect you should pass to toArray() an array of the type you need. In the above example, the code should be: both.toArray(new String[0]) See: stackoverflow.com/questions/4042434/…
  • slartidan
    slartidan almost 7 years
    myList.addAll(new ArrayList<String>(Arrays.asList(second))); can be simplified to myList.addAll(Arrays.asList(second))
  • Holger
    Holger almost 7 years
    @Will Hardwick-Smith: no, you only have to pick the right stream class, e.g. if a and b are int[], use int[] both = IntStream.concat(Arrays.stream(a), Arrays.stream(b)).toArray();
  • Bill K
    Bill K over 6 years
    Good solution--would be better if the code was refactored to avoid arrays altogether in favor of ArrayLists, but that's outside the control of the "Answer" and up to the questioner.
  • Bill K
    Bill K over 6 years
    I'd sum up the length in the same loop where you are doing your null check--but this is a really good summary of the other answers here. I believe it even handles intrinsic types like "int" without changing them to Integer objects which is really the ONLY reason to deal with them as arrays rather than just changing everything to ArrayLists. Also your method could take 2 arrays and a (...) parameter so the caller knows he needs to pass in at least two arrays before he runs it and sees the error, but that complicates the looping code....
  • drmrbrewer
    drmrbrewer over 6 years
    Don't know why this answer isn't rated higher... though it does seem to need the change suggested by @RonenRabinovici
  • Lii
    Lii over 6 years
    @Supuhstar: It is probably not as fast as System.arrayCopy. But not particularly slow either. You probably have to do this a very many times with huge arrays in really performance sensitive contexts for the execution time difference to matter.
  • Honza
    Honza over 6 years
    Or better, without unnecessary allocation of zero-length array: both.toArray(new String[both.size()]) ;)
  • Sébastien Tromp
    Sébastien Tromp over 6 years
    @RaviWallau Could you link to the class that does this?
  • Ravi Wallau
    Ravi Wallau over 6 years
    @SébastienTromp It is the top solution for this question - ArrayUtils.
  • joro
    joro about 6 years
    applicable for Strings and objects (as question wants), but there is no addAll method for primary types (as ints)
  • Sina Madani
    Sina Madani about 6 years
    I wonder which is faster and more memory efficient: the concat method or flatMap? Or are they the same under the hood?
  • Rudra
    Rudra about 6 years
    Waste of CPU & Memory. See the answer from @Douglas-Held
  • Dave L.
    Dave L. about 6 years
    The latter solution is nice because it can be used for more than 2 arrays unlike most (if not all) the other answers.
  • rghome
    rghome about 6 years
    This is the same as a previous answer 10 Feb 16.
  • rghome
    rghome almost 6 years
    I count that it requires 4 additional temporary objects to work.
  • beaudet
    beaudet over 5 years
    would be nice not to have to use the @SuppressWarnings annotation - I'll post a solution for that below.
  • John
    John over 5 years
    Use String[] arrBoth = java.util.Arrays.copyOf(arr1, arr1.length + arr2.length) to skip the first for loop. Saves time proportional to size of arr1.
  • Holger
    Holger about 5 years
    @SinaMadani with all known implementations, the variant using concat will be faster and need less memory, because it can predict the resulting array size beforehand and will create and fill only one array. In contrast, the flatMap based solution will have to use a resizable buffer internally, with at least one final copying step.
  • Holger
    Holger about 5 years
    As elaborated in this article, using both.toArray(new String[0]) will be faster than both.toArray(new String[both.size()]), even if it contradicts our naive intuition. That’s why it is so important to measure the actual performance when optimizing. Or just use the simpler construct, when the advantage of the more complicated variant can’t be proven.
  • Holger
    Holger about 5 years
  • Maarten Bodewes
    Maarten Bodewes about 5 years
    Code should be as much self explanatory as possible. People reading the code should not have to lookup the JavaDoc of a called function to find out that it does one thing for one particular condition and something else for another. In short: you can generally not fix design problems like these with a comment. Just leaving the two if statements out would be the easiest fix.
  • volley
    volley about 5 years
    @MaartenBodewes I agree. This method was used at a very specific location to fix a very specific problem identified using profiling. I'll edit the comment about JavaDoc.
  • jpmc26
    jpmc26 about 5 years
    @OutlawProgrammer I rarely hesitate to add a dependency to my application if it makes the code simpler and means I have less to maintain. Most people don't work under the kinds of constraints that necessitate worrying about adding a dependency. (I.e., they have plenty of disk space, don't need the absolutely fastest in everything, etc.)
  • Maarten Bodewes
    Maarten Bodewes about 5 years
    An if statement per copy is not a brilliant idea as it will have a hefty performance hit.
  • Maarten Bodewes
    Maarten Bodewes about 5 years
    That's very convoluted, hard to understand, undocumented and - with two if statements in the loop - rather inefficient as well.
  • Maarten Bodewes
    Maarten Bodewes about 5 years
    resutlentArray? addTwoArray? Hard to read code and YouTube style comments !!!
  • Maarten Bodewes
    Maarten Bodewes about 5 years
    This seems like useful code and catches both objects and base types. I would however not call a function resizeArray because arrays cannot be resized in Java. This is why Arrays.copyOf does the same thing, but with a different method name.
  • c-chavez
    c-chavez about 5 years
    @MaartenBodewes it's always nice to learn new approaches focused on performance. Any suggestions to improve this?
  • Maarten Bodewes
    Maarten Bodewes about 5 years
    Well, yes, arrayCopy but I guess that's mentioned in quite a few other examples. Same for two or more for loops; it is possible to bring the branching (the if statements) out of the loop.
  • Maarten Bodewes
    Maarten Bodewes about 5 years
    @rghome You can link to answers by hitting the share button. Basic, why not remove the answer if there is a clear dupe of an earlier date? If you want you can improve the existing one, if anything is missing there.
  • Maarten Bodewes
    Maarten Bodewes about 5 years
    @TrippKinetics null checks would hide NPE's rather than showing them and using final for local vars doesn't have any benefit (yet).
  • Maarten Bodewes
    Maarten Bodewes about 5 years
    Personally I would use normal for loops with an index rather than for-each here. It's unlikely to the extreme that this will be refactored to using lists (you'd just write another method) and for-each will very likely be slower than direct array access through indexing. Nitpick: pos should be defined within the scope first for loop, not outside it.
  • spacebiker
    spacebiker about 5 years
    Not really, copyOf just makes a copy with the same length, if you read the code carefully, you will realize that the function receives the parameter newSize so resizeArray does just that, returns a resized array.
  • rghome
    rghome about 5 years
    @Maarten Bodewes I think you will find (if you benchmark it, which I have) that the for-each runs in the same time as the indexed loop on late versions of Java. The optimizer takes care of it.
  • mjs
    mjs almost 5 years
    Try using that on char[] = {'a'} :/
  • Artsiom Chapialiou
    Artsiom Chapialiou almost 5 years
    Is it possible to make it works for generic type (like in the answer above)? Something like T[] both = Stream.of(a, b).flatMap(Stream::of).toArray(T[]::new); Looks like T[]::new isn't allowed cause of type erasure...
  • Blake
    Blake almost 5 years
    +1 for Array.newInstance(a.getClass().getComponentType(), aLen + bLen);. I've surprisingly never seen that before. @beaudet I think the annotation is fine here, considering why it is being suppressed.
  • beaudet
    beaudet almost 5 years
    ha, call me a purist but I prefer clean code that doesn't require suppression of warnings in order to remove warnings
  • Melih
    Melih over 4 years
    These kind of solutions are helping to people working alone on their hobby projects but has no contribution when you are working on a company project or basically a project you just should not add a new dependency to concat two arrays.
  • Lii
    Lii over 4 years
    @ArtsiomChapialiou: You can, but it's not so pretty. You have to use reflection to create the array, and thus get an unchecked cast. I added that to the solution text.
  • Farid
    Farid about 4 years
    @rghome, at least it doesn't require additional library to implement such simple task
  • Stephen J
    Stephen J about 4 years
    There's a difference between semantic warnings and "I'm using raw memory like I would in C, so turn off your safety since I know what I'm doing" "I'm being unsafe" isn't a semantic warning suppression. It's a "I'm going lower level on purpose now, so stop whining." Feel lucky, as Swift 5 removed suppressors. Java, unlike Swift, is still made for programmers who aren't afraid of doing their own programming
  • jumping_monkey
    jumping_monkey about 4 years
    Hi @Honza, possible to do the same to return a primitive integer array in 3 lines?
  • Shebla Tsama
    Shebla Tsama about 4 years
    This is one of the best solutions. 100% standard Java. Fast/efficient. Should get more upvotes!
  • alexovits
    alexovits almost 4 years
    Definitely the best solution.
  • Satish Patro
    Satish Patro over 3 years
    One doubt, can it handle null, like if null is there response is null or blank string arr if other one is blank?
  • gouessej
    gouessej over 3 years
    I don't advise to add Guava into a project only to concatenate arrays, it's big and it has a serious lack of modularity. @BrenoSalgado "much better if it's developed inside Google" I strongly disagree with that.
  • Mr00Anderson
    Mr00Anderson over 3 years
    This should not be the number one answer. The answer using a external library for something so trivial is overkill.
  • javalearner_heaven
    javalearner_heaven over 3 years
    This must be the accepted answer "the more efficient"
  • XYZ
    XYZ about 3 years
    @JohnnyLim, how do you cast the Object[] to String[] when using ArrayUtils.addAll(Arr1, Arr2)? My Arr1 / Arr2 is initialized as List<Object> obj = new ArrayList<>(), with content from double, string etc.
  • Lakshitha Kanchana
    Lakshitha Kanchana almost 3 years
    Yes, this is the best solution. Should have more up votes.
  • Barracuda
    Barracuda almost 3 years
    The second version does not work with an array of strings as it's first and an array of long (primitives) as it's second.
  • Robert
    Robert about 2 years
    It's crazy that the JDK doesn't have a method like this.
  • M. Justin
    M. Justin about 2 years
    @RaviWallau Of course, the Guava nullability behavior is by design, so it really depends on whether you're trying to avoid nulls or not, and whether it would be an error for the calling site to see a null in the first place. "For [reasons mentioned on the linked page], many of Guava's utilities are designed to fail fast in the presence of null rather than allow nulls to be used, so long as there is a null-friendly workaround available."