Вопрос-ответ

How can I concatenate two arrays in Java?

Как я могу объединить два массива в Java?

Мне нужно объединить два String массива в Java.

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

Какой самый простой способ сделать это?

Переведено автоматически
Ответ 1

Я нашел однострочное решение из старой доброй библиотеки Apache Commons Lang.
ArrayUtils.addAll(T[], T...)

Код:

String[] both = ArrayUtils.addAll(first, second);
Ответ 2

Вот простой метод, который объединит два массива и вернет результат:

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

Обратите внимание, что это не будет работать с примитивными типами данных, только с типами объектов.

Следующая, немного более сложная версия работает как с объектными, так и с примитивными массивами. Она делает это, используя T вместо T[] в качестве типа аргумента.

Это также позволяет объединять массивы двух разных типов, выбирая наиболее общий тип в качестве типа компонента результата.

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

Вот пример:

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 }));
Ответ 3

Использование Stream в Java 8:

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

Или подобным образом, используя flatMap:

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

Чтобы сделать это для универсального типа, вы должны использовать отражение:

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

Можно написать полностью универсальную версию, которую можно даже расширить для объединения любого количества массивов. Для этих версий требуется Java 6, поскольку они используют Arrays.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;
}
java arrays