在Java中如何连接两个数组?

1577

我需要在Java中合并两个String数组。

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

最简单的方法是什么?


4
Guava 中的 Bytes.concat 函数 - Ben Page
2
我看到这里有很多回复,但问题用词不当(“最简单的方法”?)无法表明最佳答案... - Artur Opalinski
3
这里有数十个答案将数据复制到一个新数组中,因为这是要求的 - 但是当不是严格必要时复制数据是一件坏事,特别是在Java中。相反,跟踪索引并将这两个数组视为已连接即可。我添加了一个说明这种技术的解决方案。 - Douglas Held
47
这个问题目前有50个不同的答案,让我想知道为什么Java从未提供一个简单的array1 + array2连接函数。 - JollyJoker
2
你可以用两行标准的Java代码完美高效地实现它(请参见我的答案),因此使用单个方法并不能获得太多好处。所有这些奇怪而神奇的解决方案都有点浪费时间。 - rghome
显示剩余2条评论
66个回答

27
ArrayList<String> both = new ArrayList(Arrays.asList(first));
both.addAll(Arrays.asList(second));

both.toArray(new String[0]);

3
答案很好,但有一点小问题。要使它完美,您应该将所需类型的数组传递给toArray()方法。在上面的例子中,代码应该是:both.toArray(new String[0])。参见:https://dev59.com/Xm855IYBdhLWcg3w_5mm - Ronen Rabinovici
不知道为什么这个答案评分不高...虽然似乎需要@RonenRabinovici建议的更改。 - drmrbrewer
4
更好的写法是避免不必要的零长度数组分配:both.toArray(new String[both.size()]) ;) - Honza
2
@Honza 推荐阅读 - Holger
嗨@Honza,能否用三行代码返回一个原始整数数组? - jumping_monkey

20

使用Java8中的Stream还有另外一种方法

  public String[] concatString(String[] a, String[] b){ 
    Stream<String> streamA = Arrays.stream(a);
    Stream<String> streamB = Arrays.stream(b);
    return Stream.concat(streamA, streamB).toArray(String[]::new); 
  }

17
这是silvertab解决方案的一种改进版本,已经进行了泛型调整:
static <T> T[] concat(T[] a, T[] b) {
    final int alen = a.length;
    final int blen = b.length;
    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;
}

注意:请参考Joachim的答案,获取Java 6解决方案。它不仅消除了警告,而且更短、更高效、更易于阅读!


你可以抑制这个方法的警告,但除此之外你没有太多的选择。数组和泛型并不是很兼容。 - Dan Dyer
4
如果您使用Arrays.copyOf(),则可以消除未经检查的警告。请查看我的答案以获取实现方式。 - Joachim Sauer
@SuppressWarnings("unchecked") - Mark Renouf

15

你可以尝试将它转换为 ArrayList,然后使用 addAll 方法,最后再转换回数组。

List list = new ArrayList(Arrays.asList(first));
  list.addAll(Arrays.asList(second));
  String[] both = list.toArray();

好的解决方案——如果代码重构以避免使用数组而改用ArrayList,那就更好了,但这超出了“答案”的控制范围,由提问者决定。 - Bill K
我计算出需要4个额外的临时对象才能工作。 - rghome
2
@rghome,至少它不需要额外的库来实现这样简单的任务。 - Farid

13

如果您使用此方法,则无需导入任何第三方类。

如果您想要连接String

连接两个字符串数组的示例代码

public static String[] combineString(String[] first, String[] second){
        int length = first.length + second.length;
        String[] result = new String[length];
        System.arraycopy(first, 0, result, 0, first.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }

如果您想连接Int

连接两个整数数组的示例代码

public static int[] combineInt(int[] a, int[] b){
        int length = a.length + b.length;
        int[] result = new int[length];
        System.arraycopy(a, 0, result, 0, a.length);
        System.arraycopy(b, 0, result, a.length, b.length);
        return result;
    }

这里是主方法

    public static void main(String[] args) {

            String [] first = {"a", "b", "c"};
            String [] second = {"d", "e"};

            String [] joined = combineString(first, second);
            System.out.println("concatenated String array : " + Arrays.toString(joined));

            int[] array1 = {101,102,103,104};
            int[] array2 = {105,106,107,108};
            int[] concatenateInt = combineInt(array1, array2);

            System.out.println("concatenated Int array : " + Arrays.toString(concatenateInt));

        }
    }  

我们也可以使用这种方式。


12

请原谅我在这个已经很长的列表中添加另一个版本。我查看了每一个答案,并决定我真的想要一个只有一个参数签名的版本。我还添加了一些参数检查,以便在出现意外输入时从早期失败中受益,并提供合理的信息。

@SuppressWarnings("unchecked")
public static <T> T[] concat(T[]... inputArrays) {
  if(inputArrays.length < 2) {
    throw new IllegalArgumentException("inputArrays must contain at least 2 arrays");
  }

  for(int i = 0; i < inputArrays.length; i++) {
    if(inputArrays[i] == null) {
      throw new IllegalArgumentException("inputArrays[" + i + "] is null");
    }
  }

  int totalLength = 0;

  for(T[] array : inputArrays) {
    totalLength += array.length;
  }

  T[] result = (T[]) Array.newInstance(inputArrays[0].getClass().getComponentType(), totalLength);

  int offset = 0;

  for(T[] array : inputArrays) {
    System.arraycopy(array, 0, result, offset, array.length);

    offset += array.length;
  }

  return result;
}

我会在同一个循环中汇总长度,就像你在进行空值检查的循环中一样--但这是其他答案的一个非常好的总结。我相信它甚至处理了内置类型,比如“int”,而不需要将它们更改为Integer对象,这确实是处理它们作为数组而不仅仅是将所有内容更改为ArrayLists的唯一原因。此外,您的方法可以接受2个数组和一个(...)参数,以便调用者知道他在运行之前需要传递至少两个数组,然后看到错误,但这会使循环代码变得复杂.... - Bill K

11

使用Java 8+流,您可以编写以下函数:

private static String[] concatArrays(final String[]... arrays) {
    return Arrays.stream(arrays)
         .flatMap(Arrays::stream)
         .toArray(String[]::new);
}

9

这应该是一行文字。

public String [] concatenate (final String array1[], final String array2[])
{
    return Stream.concat(Stream.of(array1), Stream.of(array2)).toArray(String[]::new);
}

7

这个代码可以运行,但是你需要自己添加错误检查。

public class StringConcatenate {

    public static void main(String[] args){

        // Create two arrays to concatenate and one array to hold both
        String[] arr1 = new String[]{"s","t","r","i","n","g"};
        String[] arr2 = new String[]{"s","t","r","i","n","g"};
        String[] arrBoth = new String[arr1.length+arr2.length];

        // Copy elements from first array into first part of new array
        for(int i = 0; i < arr1.length; i++){
            arrBoth[i] = arr1[i];
        }

        // Copy elements from second array into last part of new array
        for(int j = arr1.length;j < arrBoth.length;j++){
            arrBoth[j] = arr2[j-arr1.length];
        }

        // Print result
        for(int k = 0; k < arrBoth.length; k++){
            System.out.print(arrBoth[k]);
        }

        // Additional line to make your terminal look better at completion!
        System.out.println();
    }
}

这可能不是最有效的方法,但它不依赖于除Java自身API之外的任何东西。


2
+1。最好用以下代码替换第二个for循环:for(int j = 0; j < arr2.length; j++){arrBoth[arr1.length+j] = arr2[j];} - bancer
使用String[] arrBoth = java.util.Arrays.copyOf(arr1, arr1.length + arr2.length)来跳过第一个for循环。这样可以节省与arr1大小成比例的时间。 - John

7

这里是实现silvertab伪代码解决方案的工作代码示例。

感谢silvertab!

public class Array {

   public static <T> T[] concat(T[] a, T[] b, ArrayBuilderI<T> builder) {
      T[] c = builder.build(a.length + b.length);
      System.arraycopy(a, 0, c, 0, a.length);
      System.arraycopy(b, 0, c, a.length, b.length);
      return c;
   }
}

以下是构建器接口。
注意:由于Java的泛型类型擦除,不可能使用new T[size],因此构建器是必要的。
public interface ArrayBuilderI<T> {

   public T[] build(int size);
}

以下是一个实现该接口的具体构建器,它正在构建一个 Integer 数组:

public class IntegerArrayBuilder implements ArrayBuilderI<Integer> {

   @Override
   public Integer[] build(int size) {
      return new Integer[size];
   }
}

最后是应用/测试:


@Test
public class ArrayTest {

   public void array_concatenation() {
      Integer a[] = new Integer[]{0,1};
      Integer b[] = new Integer[]{2,3};
      Integer c[] = Array.concat(a, b, new IntegerArrayBuilder());
      assertEquals(4, c.length);
      assertEquals(0, (int)c[0]);
      assertEquals(1, (int)c[1]);
      assertEquals(2, (int)c[2]);
      assertEquals(3, (int)c[3]);
   }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接