我需要在Java中连接两个字符串数组。

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

哪种方法最简单?


当前回答

我最近一直在与过度的记忆循环作斗争。如果已知a和/或b通常是空的,这里是silvertab代码的另一种修改(也被通用化):

private static <T> T[] concatOrReturnSame(T[] a, T[] b) {
    final int alen = a.length;
    final int blen = b.length;
    if (alen == 0) {
        return b;
    }
    if (blen == 0) {
        return a;
    }
    final T[] result = (T[]) java.lang.reflect.Array.
            newInstance(a.getClass().getComponentType(), alen + blen);
    System.arraycopy(a, 0, result, 0, alen);
    System.arraycopy(b, 0, result, alen, blen);
    return result;
}

编辑:这篇文章的前一个版本指出,像这样的数组重用应该清楚地记录下来。正如Maarten在评论中指出的那样,一般来说,最好删除if语句,这样就不需要文档了。但话说回来,那些if语句首先就是这个特定优化的要点。我会在这里留下这个答案,但要小心!

其他回答

另一个基于SilverTab的建议,但它支持x个参数,不需要Java6。它也不是通用的,但我确信它可以是通用的。

private byte[] concat(byte[]... args)
{
    int fulllength = 0;
    for (byte[] arrItem : args)
    {
        fulllength += arrItem.length;
    }
    byte[] retArray = new byte[fulllength];
    int start = 0;
    for (byte[] arrItem : args)
    {
        System.arraycopy(arrItem, 0, retArray, start, arrItem.length);
        start += arrItem.length;
    }
    return retArray;
}

我最近一直在与过度的记忆循环作斗争。如果已知a和/或b通常是空的,这里是silvertab代码的另一种修改(也被通用化):

private static <T> T[] concatOrReturnSame(T[] a, T[] b) {
    final int alen = a.length;
    final int blen = b.length;
    if (alen == 0) {
        return b;
    }
    if (blen == 0) {
        return a;
    }
    final T[] result = (T[]) java.lang.reflect.Array.
            newInstance(a.getClass().getComponentType(), alen + blen);
    System.arraycopy(a, 0, result, 0, alen);
    System.arraycopy(b, 0, result, alen, blen);
    return result;
}

编辑:这篇文章的前一个版本指出,像这样的数组重用应该清楚地记录下来。正如Maarten在评论中指出的那样,一般来说,最好删除if语句,这样就不需要文档了。但话说回来,那些if语句首先就是这个特定优化的要点。我会在这里留下这个答案,但要小心!

可以编写一个完全通用的版本,甚至可以扩展到连接任意数量的数组。这些版本需要Java 6,因为它们使用Array.copyOf()

这两个版本都避免创建任何中间List对象,并使用System.arraycopy()确保复制大型数组的速度尽可能快。

对于两个阵列,其外观如下:

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;
}

对于任意数量的数组(>=1),如下所示:

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;
}

我看到许多带有公共静态T[]concat(T[]a,T[]b){}等签名的通用答案,但据我所知,这些答案只适用于Object数组,而不适用于基元数组。下面的代码既适用于对象数组,也适用于基元数组,使其更通用。。。

public static <T> T concat(T a, T b) {
        //Handles both arrays of Objects and primitives! E.g., int[] out = concat(new int[]{6,7,8}, new int[]{9,10});
        //You get a compile error if argument(s) not same type as output. (int[] in example above)
        //You get a runtime error if output type is not an array, i.e., when you do something like: int out = concat(6,7);
        if (a == null && b == null) return null;
        if (a == null) return b;
        if (b == null) return a;
        final int aLen = Array.getLength(a);
        final int bLen = Array.getLength(b);
        if (aLen == 0) return b;
        if (bLen == 0) return a;
        //From here on we really need to concatenate!

        Class componentType = a.getClass().getComponentType();
        final T result = (T)Array.newInstance(componentType, aLen + bLen);
        System.arraycopy(a, 0, result, 0, aLen);
        System.arraycopy(b, 0, result, aLen, bLen);
        return result;
    }

    public static void main(String[] args) {
        String[] out1 = concat(new String[]{"aap", "monkey"}, new String[]{"rat"});
        int[] out2 = concat(new int[]{6,7,8}, new int[]{9,10});
    }

使用Java集合

好吧,Java没有提供连接数组的助手方法。然而,自Java5以来,Collections实用程序类引入了addAll(Collection<?super T>c,T…elements)方法。

我们可以创建一个List对象,然后调用该方法两次,将这两个数组添加到列表中。最后,我们将生成的List转换回数组:

static <T> T[] concatWithCollection(T[] array1, T[] array2) {
    List<T> resultList = new ArrayList<>(array1.length + array2.length);
    Collections.addAll(resultList, array1);
    Collections.addAll(resultList, array2);

    @SuppressWarnings("unchecked")
    //the type cast is safe as the array1 has the type T[]
    T[] resultArray = (T[]) Array.newInstance(array1.getClass().getComponentType(), 0);
    return resultList.toArray(resultArray);
}

Test

@Test
public void givenTwoStringArrays_whenConcatWithList_thenGetExpectedResult() {
    String[] result = ArrayConcatUtil.concatWithCollection(strArray1, strArray2);
    assertThat(result).isEqualTo(expectedStringArray);
}