Skip to content

Commit eefe5c8

Browse files
ivamlygarydgregory
andauthored
[LANG-1707] Add ArrayUtils.concat methods for concatenating multiple arrays (#1519)
* LANG-1707 add concat methods to ArrayUtils * Add missing test assertions for null inputs - Javadoc - Use longer lines * Add Javadoc @throws --------- Co-authored-by: Gary Gregory <garydgregory@users.noreply.github.com>
1 parent d4cb592 commit eefe5c8

3 files changed

Lines changed: 409 additions & 0 deletions

File tree

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@
7777
<version>5.6.0</version>
7878
<scope>test</scope>
7979
</dependency>
80+
<dependency>
81+
<groupId>org.mockito</groupId>
82+
<artifactId>mockito-inline</artifactId>
83+
<version>${commons.mockito.version}</version>
84+
</dependency>
8085
<!-- For Javadoc links -->
8186
<dependency>
8287
<groupId>org.apache.commons</groupId>

src/main/java/org/apache/commons/lang3/ArrayUtils.java

Lines changed: 286 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9340,6 +9340,283 @@ public static String[] toStringArray(final Object[] array, final String valueFor
93409340
return map(array, String.class, e -> Objects.toString(e, valueForNullElements));
93419341
}
93429342

9343+
/**
9344+
* Concatenates multiple boolean arrays into a single array.
9345+
* <p>
9346+
* This method combines all input arrays in the order they are provided,
9347+
* creating a new array that contains all elements from the input arrays.
9348+
* The resulting array length is the sum of lengths of all non-null input arrays.
9349+
* </p>
9350+
*
9351+
* @param arrays the arrays to concatenate. Can be empty, contain nulls,
9352+
* or be null itself (treated as empty varargs).
9353+
* @return a new boolean array containing all elements from the input arrays
9354+
* in the order they appear, or an empty array if no elements are present.
9355+
* @throws NullPointerException if the input array of arrays is null.
9356+
* @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
9357+
* @since 3.21.0
9358+
*/
9359+
public static boolean[] concat(boolean[]... arrays) {
9360+
int totalLength = 0;
9361+
for (boolean[] array : arrays) {
9362+
totalLength = addExact(totalLength, array);
9363+
}
9364+
final boolean[] result = new boolean[totalLength];
9365+
int currentPos = 0;
9366+
for (boolean[] array : arrays) {
9367+
if (array != null && array.length > 0) {
9368+
System.arraycopy(array, 0, result, currentPos, array.length);
9369+
currentPos += array.length;
9370+
}
9371+
}
9372+
return result;
9373+
}
9374+
9375+
/**
9376+
* Concatenates multiple byte arrays into a single array.
9377+
* <p>
9378+
* This method combines all input arrays in the order they are provided,
9379+
* creating a new array that contains all elements from the input arrays.
9380+
* The resulting array length is the sum of lengths of all non-null input arrays.
9381+
* </p>
9382+
*
9383+
* @param arrays the arrays to concatenate. Can be empty, contain nulls,
9384+
* or be null itself (treated as empty varargs).
9385+
* @return a new byte array containing all elements from the input arrays
9386+
* in the order they appear, or an empty array if no elements are present.
9387+
* @throws NullPointerException if the input array of arrays is null.
9388+
* @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
9389+
* @since 3.21.0
9390+
*/
9391+
public static byte[] concat(byte[]... arrays) {
9392+
int totalLength = 0;
9393+
for (byte[] array : arrays) {
9394+
totalLength = addExact(totalLength, array);
9395+
}
9396+
final byte[] result = new byte[totalLength];
9397+
int currentPos = 0;
9398+
for (byte[] array : arrays) {
9399+
if (array != null && array.length > 0) {
9400+
System.arraycopy(array, 0, result, currentPos, array.length);
9401+
currentPos += array.length;
9402+
}
9403+
}
9404+
return result;
9405+
}
9406+
9407+
/**
9408+
* Concatenates multiple char arrays into a single array.
9409+
* <p>
9410+
* This method combines all input arrays in the order they are provided,
9411+
* creating a new array that contains all elements from the input arrays.
9412+
* The resulting array length is the sum of lengths of all non-null input arrays.
9413+
* </p>
9414+
*
9415+
* @param arrays the arrays to concatenate. Can be empty, contain nulls,
9416+
* or be null itself (treated as empty varargs).
9417+
* @return a new char array containing all elements from the input arrays
9418+
* in the order they appear, or an empty array if no elements are present.
9419+
* @throws NullPointerException if the input array of arrays is null.
9420+
* @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
9421+
* @since 3.21.0
9422+
*/
9423+
public static char[] concat(char[]... arrays) {
9424+
int totalLength = 0;
9425+
for (char[] array : arrays) {
9426+
totalLength = addExact(totalLength, array);
9427+
}
9428+
final char[] result = new char[totalLength];
9429+
int currentPos = 0;
9430+
for (char[] array : arrays) {
9431+
if (array != null && array.length > 0) {
9432+
System.arraycopy(array, 0, result, currentPos, array.length);
9433+
currentPos += array.length;
9434+
}
9435+
}
9436+
return result;
9437+
}
9438+
9439+
/**
9440+
* Concatenates multiple double arrays into a single array.
9441+
* <p>
9442+
* This method combines all input arrays in the order they are provided,
9443+
* creating a new array that contains all elements from the input arrays.
9444+
* The resulting array length is the sum of lengths of all non-null input arrays.
9445+
* </p>
9446+
*
9447+
* @param arrays the arrays to concatenate. Can be empty, contain nulls,
9448+
* or be null itself (treated as empty varargs).
9449+
* @return a new double array containing all elements from the input arrays
9450+
* in the order they appear, or an empty array if no elements are present.
9451+
* @throws NullPointerException if the input array of arrays is null.
9452+
* @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
9453+
* @since 3.21.0
9454+
*/
9455+
public static double[] concat(double[]... arrays) {
9456+
int totalLength = 0;
9457+
for (double[] array : arrays) {
9458+
totalLength = addExact(totalLength, array);
9459+
}
9460+
final double[] result = new double[totalLength];
9461+
int currentPos = 0;
9462+
for (double[] array : arrays) {
9463+
if (array != null && array.length > 0) {
9464+
System.arraycopy(array, 0, result, currentPos, array.length);
9465+
currentPos += array.length;
9466+
}
9467+
}
9468+
return result;
9469+
}
9470+
9471+
/**
9472+
* Concatenates multiple float arrays into a single array.
9473+
* <p>
9474+
* This method combines all input arrays in the order they are provided,
9475+
* creating a new array that contains all elements from the input arrays.
9476+
* The resulting array length is the sum of lengths of all non-null input arrays.
9477+
* </p>
9478+
*
9479+
* @param arrays the arrays to concatenate. Can be empty, contain nulls,
9480+
* or be null itself (treated as empty varargs).
9481+
* @return a new float array containing all elements from the input arrays
9482+
* in the order they appear, or an empty array if no elements are present.
9483+
* @throws NullPointerException if the input array of arrays is null.
9484+
* @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
9485+
* @since 3.21.0
9486+
*/
9487+
public static float[] concat(float[]... arrays) {
9488+
int totalLength = 0;
9489+
for (float[] array : arrays) {
9490+
totalLength = addExact(totalLength, array);
9491+
}
9492+
final float[] result = new float[totalLength];
9493+
int currentPos = 0;
9494+
for (float[] array : arrays) {
9495+
if (array != null && array.length > 0) {
9496+
System.arraycopy(array, 0, result, currentPos, array.length);
9497+
currentPos += array.length;
9498+
}
9499+
}
9500+
return result;
9501+
}
9502+
9503+
/**
9504+
* Concatenates multiple int arrays into a single array.
9505+
* <p>
9506+
* This method combines all input arrays in the order they are provided,
9507+
* creating a new array that contains all elements from the input arrays.
9508+
* The resulting array length is the sum of lengths of all non-null input arrays.
9509+
* </p>
9510+
*
9511+
* @param arrays the arrays to concatenate. Can be empty, contain nulls,
9512+
* or be null itself (treated as empty varargs).
9513+
* @return a new int array containing all elements from the input arrays
9514+
* in the order they appear, or an empty array if no elements are present.
9515+
* @throws NullPointerException if the input array of arrays is null.
9516+
* @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
9517+
* @since 3.21.0
9518+
*/
9519+
public static int[] concat(int[]... arrays) {
9520+
int totalLength = 0;
9521+
for (int[] array : arrays) {
9522+
totalLength = addExact(totalLength, array);
9523+
}
9524+
final int[] result = new int[totalLength];
9525+
int currentPos = 0;
9526+
for (int[] array : arrays) {
9527+
if (array != null && array.length > 0) {
9528+
System.arraycopy(array, 0, result, currentPos, array.length);
9529+
currentPos += array.length;
9530+
}
9531+
}
9532+
return result;
9533+
}
9534+
9535+
/**
9536+
* Concatenates multiple long arrays into a single array.
9537+
* <p>
9538+
* This method combines all input arrays in the order they are provided,
9539+
* creating a new array that contains all elements from the input arrays.
9540+
* The resulting array length is the sum of lengths of all non-null input arrays.
9541+
* </p>
9542+
*
9543+
* @param arrays the arrays to concatenate. Can be empty, contain nulls,
9544+
* or be null itself (treated as empty varargs).
9545+
* @return a new long array containing all elements from the input arrays
9546+
* in the order they appear, or an empty array if no elements are present.
9547+
* @throws NullPointerException if the input array of arrays is null.
9548+
* @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
9549+
* @since 3.21.0
9550+
*/
9551+
public static long[] concat(long[]... arrays) {
9552+
int totalLength = 0;
9553+
for (long[] array : arrays) {
9554+
totalLength = addExact(totalLength, array);
9555+
}
9556+
final long[] result = new long[totalLength];
9557+
int currentPos = 0;
9558+
for (long[] array : arrays) {
9559+
if (array != null && array.length > 0) {
9560+
System.arraycopy(array, 0, result, currentPos, array.length);
9561+
currentPos += array.length;
9562+
}
9563+
}
9564+
return result;
9565+
}
9566+
9567+
/**
9568+
* Concatenates multiple short arrays into a single array.
9569+
* <p>
9570+
* This method combines all input arrays in the order they are provided,
9571+
* creating a new array that contains all elements from the input arrays.
9572+
* The resulting array length is the sum of lengths of all non-null input arrays.
9573+
* </p>
9574+
*
9575+
* @param arrays the arrays to concatenate. Can be empty, contain nulls,
9576+
* or be null itself (treated as empty varargs).
9577+
* @return a new short array containing all elements from the input arrays
9578+
* in the order they appear, or an empty array if no elements are present.
9579+
* @throws NullPointerException if the input array of arrays is null.
9580+
* @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
9581+
* @since 3.21.0
9582+
*/
9583+
public static short[] concat(short[]... arrays) {
9584+
int totalLength = 0;
9585+
for (short[] array : arrays) {
9586+
totalLength = addExact(totalLength, array);
9587+
}
9588+
final short[] result = new short[totalLength];
9589+
int currentPos = 0;
9590+
for (short[] array : arrays) {
9591+
if (array != null && array.length > 0) {
9592+
System.arraycopy(array, 0, result, currentPos, array.length);
9593+
currentPos += array.length;
9594+
}
9595+
}
9596+
return result;
9597+
}
9598+
9599+
/**
9600+
* Safely adds the length of an array to a running total, checking for overflow.
9601+
*
9602+
* @param totalLength the current accumulated length
9603+
* @param array the array whose length should be added (can be {@code null},
9604+
* in which case its length is considered 0)
9605+
* @return the new total length after adding the array's length
9606+
* @throws IllegalArgumentException if total arrays length exceed {@link ArrayUtils#SAFE_MAX_ARRAY_LENGTH}.
9607+
*/
9608+
private static int addExact(final int totalLength, final Object array) {
9609+
try {
9610+
final int length = MathBridge.addExact(totalLength, getLength(array));
9611+
if (length > SAFE_MAX_ARRAY_LENGTH) {
9612+
throw new IllegalArgumentException("Total arrays length exceed " + SAFE_MAX_ARRAY_LENGTH);
9613+
}
9614+
return length;
9615+
} catch (final ArithmeticException exception) {
9616+
throw new IllegalArgumentException("Total arrays length exceed " + SAFE_MAX_ARRAY_LENGTH);
9617+
}
9618+
}
9619+
93439620
/**
93449621
* ArrayUtils instances should NOT be constructed in standard programming. Instead, the class should be used as {@code ArrayUtils.clone(new int[] {2})}.
93459622
* <p>
@@ -9352,4 +9629,13 @@ public static String[] toStringArray(final Object[] array, final String valueFor
93529629
public ArrayUtils() {
93539630
// empty
93549631
}
9632+
9633+
/**
9634+
* Bridge class to {@link Math} methods for testing purposes.
9635+
*/
9636+
static class MathBridge {
9637+
static int addExact(final int a, final int b) {
9638+
return Math.addExact(a, b);
9639+
}
9640+
}
93559641
}

0 commit comments

Comments
 (0)