Operations on arrays, primitive arrays (like {@code int[]}) and
+ * Operations on arrays, primitive arrays (like {@code int[]}) and
* primitive wrapper arrays (like {@code Integer[]}).
- *
- *
This class tries to handle {@code null} input gracefully.
+ *
+ * This class tries to handle {@code null} input gracefully.
* An exception will not be thrown for a {@code null}
* array input. However, an Object array that contains a {@code null}
- * element may throw an exception. Each method documents its behaviour.
- *
- *
#ThreadSafe#
+ * element may throw an exception. Each method documents its behavior.
+ *
+ *
+ * #ThreadSafe#
+ *
* @since 2.0
*/
public class ArrayUtils {
/**
- * An empty immutable {@code Object} array.
+ * An empty immutable {@code boolean} array.
+ */
+ public static final boolean[] EMPTY_BOOLEAN_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Boolean} array.
*/
- public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+ public static final Boolean[] EMPTY_BOOLEAN_OBJECT_ARRAY = {};
+
/**
- * An empty immutable {@code Class} array.
+ * An empty immutable {@code byte} array.
*/
- public static final Class>[] EMPTY_CLASS_ARRAY = new Class>[0];
+ public static final byte[] EMPTY_BYTE_ARRAY = {};
+
/**
- * An empty immutable {@code long} array.
+ * An empty immutable {@link Byte} array.
+ */
+ public static final Byte[] EMPTY_BYTE_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@code char} array.
+ */
+ public static final char[] EMPTY_CHAR_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Character} array.
+ */
+ public static final Character[] EMPTY_CHARACTER_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Class} array.
+ */
+ public static final Class>[] EMPTY_CLASS_ARRAY = {};
+
+ /**
+ * An empty immutable {@code double} array.
+ */
+ public static final double[] EMPTY_DOUBLE_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Double} array.
+ */
+ public static final Double[] EMPTY_DOUBLE_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Field} array.
+ *
+ * @since 3.10
+ */
+ public static final Field[] EMPTY_FIELD_ARRAY = {};
+
+ /**
+ * An empty immutable {@code float} array.
*/
- public static final long[] EMPTY_LONG_ARRAY = new long[0];
+ public static final float[] EMPTY_FLOAT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Float} array.
+ */
+ public static final Float[] EMPTY_FLOAT_OBJECT_ARRAY = {};
+
/**
* An empty immutable {@code int} array.
*/
- public static final int[] EMPTY_INT_ARRAY = new int[0];
+ public static final int[] EMPTY_INT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Integer} array.
+ */
+ public static final Integer[] EMPTY_INTEGER_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@code long} array.
+ */
+ public static final long[] EMPTY_LONG_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Long} array.
+ */
+ public static final Long[] EMPTY_LONG_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Method} array.
+ *
+ * @since 3.10
+ */
+ public static final Method[] EMPTY_METHOD_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Object} array.
+ */
+ public static final Object[] EMPTY_OBJECT_ARRAY = {};
+
/**
* An empty immutable {@code short} array.
*/
- public static final short[] EMPTY_SHORT_ARRAY = new short[0];
+ public static final short[] EMPTY_SHORT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Short} array.
+ */
+ public static final Short[] EMPTY_SHORT_OBJECT_ARRAY = {};
+
+ /**
+ * An empty immutable {@link String} array.
+ */
+ public static final String[] EMPTY_STRING_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Throwable} array.
+ *
+ * @since 3.10
+ */
+ public static final Throwable[] EMPTY_THROWABLE_ARRAY = {};
+
+ /**
+ * An empty immutable {@link Type} array.
+ *
+ * @since 3.10
+ */
+ public static final Type[] EMPTY_TYPE_ARRAY = {};
+
+ /**
+ * The index value when an element is not found in a list or array: {@code -1}.
+ * This value is returned by methods in this class and can also be used in comparisons with values returned by
+ * various method from {@link java.util.List}.
+ */
+ public static final int INDEX_NOT_FOUND = -1;
+
+ /**
+ * The {@code SOFT_MAX_ARRAY_LENGTH} constant from Java's internal ArraySupport class.
+ *
+ * @since 3.19.0
+ */
+ public static int SOFT_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}
+ * @param element the object to add at the last index of the new array
+ * @return A new array containing the existing elements plus the new element
+ * @since 2.1
+ */
+ public static boolean[] add(final boolean[] array, final boolean element) {
+ final boolean[] newArray = (boolean[]) copyArrayGrow1(array, Boolean.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}
+ * @param element the object to add at the last index of the new array
+ * @return A new array containing the existing elements plus the new element
+ * @since 2.1
+ */
+ public static byte[] add(final byte[] array, final byte element) {
+ final byte[] newArray = (byte[]) copyArrayGrow1(array, Byte.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}
+ * @param element the object to add at the last index of the new array
+ * @return A new array containing the existing elements plus the new element
+ * @since 2.1
+ */
+ public static char[] add(final char[] array, final char element) {
+ final char[] newArray = (char[]) copyArrayGrow1(array, Character.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}
+ * @param element the object to add at the last index of the new array
+ * @return A new array containing the existing elements plus the new element
+ * @since 2.1
+ */
+ public static double[] add(final double[] array, final double element) {
+ final double[] newArray = (double[]) copyArrayGrow1(array, Double.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}
+ * @param element the object to add at the last index of the new array
+ * @return A new array containing the existing elements plus the new element
+ * @since 2.1
+ */
+ public static float[] add(final float[] array, final float element) {
+ final float[] newArray = (float[]) copyArrayGrow1(array, Float.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}
+ * @param element the object to add at the last index of the new array
+ * @return A new array containing the existing elements plus the new element
+ * @since 2.1
+ */
+ public static int[] add(final int[] array, final int element) {
+ final int[] newArray = (int[]) copyArrayGrow1(array, Integer.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}
+ * @param element the object to add at the last index of the new array
+ * @return A new array containing the existing elements plus the new element
+ * @since 2.1
+ */
+ public static long[] add(final long[] array, final long element) {
+ final long[] newArray = (long[]) copyArrayGrow1(array, Long.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element.
+ *
+ *
+ * @param array the array to copy and add the element to, may be {@code null}
+ * @param element the object to add at the last index of the new array
+ * @return A new array containing the existing elements plus the new element
+ * @since 2.1
+ */
+ public static short[] add(final short[] array, final short element) {
+ final short[] newArray = (short[]) copyArrayGrow1(array, Short.TYPE);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Copies the given array and adds the given element at the end of the new array.
+ *
+ * The new array contains the same elements of the input
+ * array plus the given element in the last position. The component type of
+ * the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned
+ * whose component type is the same as the element, unless the element itself is null,
+ * in which case the return type is Object[]
+ *
+ *
+ * @param the component type of the array
+ * @param array the array to "add" the element to, may be {@code null}
+ * @param element the object to add, may be {@code null}
+ * @return A new array containing the existing elements plus the new element
+ * The returned array type will be that of the input array (unless null),
+ * in which case it will have the same type as the element.
+ * If both are null, an IllegalArgumentException is thrown
+ * @throws IllegalArgumentException if both arguments are null
+ * @since 2.1
+ */
+ public static T[] add(final T[] array, final T element) {
+ final Class> type;
+ if (array != null) {
+ type = array.getClass().getComponentType();
+ } else if (element != null) {
+ type = element.getClass();
+ } else {
+ throw new IllegalArgumentException("Arguments cannot both be null");
+ }
+ @SuppressWarnings("unchecked") // type must be T
+ final
+ T[] newArray = (T[]) copyArrayGrow1(array, type);
+ newArray[newArray.length - 1] = element;
+ return newArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new boolean[] array or {@code null}.
+ * @since 2.1
+ */
+ public static boolean[] addAll(final boolean[] array1, final boolean... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final boolean[] joinedArray = new boolean[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new byte[] array or {@code null}.
+ * @since 2.1
+ */
+ public static byte[] addAll(final byte[] array1, final byte... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final byte[] joinedArray = new byte[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new char[] array or {@code null}.
+ * @since 2.1
+ */
+ public static char[] addAll(final char[] array1, final char... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final char[] joinedArray = new char[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new double[] array or {@code null}.
+ * @since 2.1
+ */
+ public static double[] addAll(final double[] array1, final double... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final double[] joinedArray = new double[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new float[] array or {@code null}.
+ * @since 2.1
+ */
+ public static float[] addAll(final float[] array1, final float... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final float[] joinedArray = new float[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new int[] array or {@code null}.
+ * @since 2.1
+ */
+ public static int[] addAll(final int[] array1, final int... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final int[] joinedArray = new int[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new long[] array or {@code null}.
+ * @since 2.1
+ */
+ public static long[] addAll(final long[] array1, final long... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final long[] joinedArray = new long[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Adds all the elements of the given arrays into a new array.
+ *
+ * The new array contains all of the element of {@code array1} followed
+ * by all of the elements {@code array2}. When an array is returned, it is always
+ * a new array.
+ *
+ *
+ * @param array1 the first array whose elements are added to the new array.
+ * @param array2 the second array whose elements are added to the new array.
+ * @return The new short[] array or {@code null}.
+ * @since 2.1
+ */
+ public static short[] addAll(final short[] array1, final short... array2) {
+ if (array1 == null) {
+ return clone(array2);
+ }
+ if (array2 == null) {
+ return clone(array1);
+ }
+ final short[] joinedArray = new short[array1.length + array2.length];
+ System.arraycopy(array1, 0, joinedArray, 0, array1.length);
+ System.arraycopy(array2, 0, joinedArray, array1.length, array2.length);
+ return joinedArray;
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static boolean[] addFirst(final boolean[] array, final boolean element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static byte[] addFirst(final byte[] array, final byte element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static char[] addFirst(final char[] array, final char element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static double[] addFirst(final double[] array, final double element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static float[] addFirst(final float[] array, final float element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static int[] addFirst(final int[] array, final int element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static long[] addFirst(final long[] array, final long element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * Copies the given array and adds the given element at the beginning of the new array.
+ *
+ * The new array contains the same elements of the input array plus the given element in the first position. The
+ * component type of the new array is the same as that of the input array.
+ *
+ *
+ * If the input array is {@code null}, a new one element array is returned whose component type is the same as the
+ * element.
+ *
+ *
+ * @param array the array to "add" the element to, may be {@code null}.
+ * @param element the object to add.
+ * @return A new array containing the existing elements plus the new element The returned array type will be that of
+ * the input array (unless null), in which case it will have the same type as the element.
+ * @since 3.10
+ */
+ public static short[] addFirst(final short[] array, final short element) {
+ return array == null ? add(array, element) : insert(0, array, element);
+ }
+
+ /**
+ * A fluent version of {@link System#arraycopy(Object, int, Object, int, int)} that returns the destination array.
+ *
+ * @param the type.
+ * @param source the source array.
+ * @param sourcePos starting position in the source array.
+ * @param destPos starting position in the destination data.
+ * @param length the number of array elements to be copied.
+ * @param allocator allocates the array to populate and return.
+ * @return dest
+ * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds.
+ * @throws ArrayStoreException if an element in the {@code src} array could not be stored into the {@code dest} array because of a type
+ * mismatch.
+ * @throws NullPointerException if either {@code src} or {@code dest} is {@code null}.
+ * @since 3.15.0
+ */
+ public static T arraycopy(final T source, final int sourcePos, final int destPos, final int length, final Function allocator) {
+ return arraycopy(source, sourcePos, allocator.apply(length), destPos, length);
+ }
+
+ /**
+ * A fluent version of {@link System#arraycopy(Object, int, Object, int, int)} that returns the destination array.
+ *
+ * @param the type.
+ * @param source the source array.
+ * @param sourcePos starting position in the source array.
+ * @param destPos starting position in the destination data.
+ * @param length the number of array elements to be copied.
+ * @param allocator allocates the array to populate and return.
+ * @return dest
+ * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds.
+ * @throws ArrayStoreException if an element in the {@code src} array could not be stored into the {@code dest} array because of a type
+ * mismatch.
+ * @throws NullPointerException if either {@code src} or {@code dest} is {@code null}.
+ * @since 3.15.0
+ */
+ public static T arraycopy(final T source, final int sourcePos, final int destPos, final int length, final Supplier allocator) {
+ return arraycopy(source, sourcePos, allocator.get(), destPos, length);
+ }
+
+ /**
+ * A fluent version of {@link System#arraycopy(Object, int, Object, int, int)} that returns the destination array.
+ *
+ * @param the type
+ * @param source the source array.
+ * @param sourcePos starting position in the source array.
+ * @param dest the destination array.
+ * @param destPos starting position in the destination data.
+ * @param length the number of array elements to be copied.
+ * @return dest
+ * @throws IndexOutOfBoundsException if copying would cause access of data outside array bounds.
+ * @throws ArrayStoreException if an element in the {@code src} array could not be stored into the {@code dest} array because of a type
+ * mismatch.
+ * @throws NullPointerException if either {@code src} or {@code dest} is {@code null}.
+ * @since 3.15.0
+ */
+ public static T arraycopy(final T source, final int sourcePos, final T dest, final int destPos, final int length) {
+ System.arraycopy(source, sourcePos, dest, destPos, length);
+ return dest;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}
+ * @return the cloned array, {@code null} if {@code null} input
+ */
+ public static boolean[] clone(final boolean[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}
+ * @return the cloned array, {@code null} if {@code null} input
+ */
+ public static byte[] clone(final byte[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}
+ * @return the cloned array, {@code null} if {@code null} input
+ */
+ public static char[] clone(final char[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}
+ * @return the cloned array, {@code null} if {@code null} input
+ */
+ public static double[] clone(final double[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}
+ * @return the cloned array, {@code null} if {@code null} input
+ */
+ public static float[] clone(final float[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}
+ * @return the cloned array, {@code null} if {@code null} input
+ */
+ public static int[] clone(final int[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}
+ * @return the cloned array, {@code null} if {@code null} input
+ */
+ public static long[] clone(final long[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Clones an array or returns {@code null}.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array the array to clone, may be {@code null}
+ * @return the cloned array, {@code null} if {@code null} input
+ */
+ public static short[] clone(final short[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Shallow clones an array or returns {@code null}.
+ *
+ * The objects in the array are not cloned, thus there is no special handling for multi-dimensional arrays.
+ *
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param the component type of the array
+ * @param array the array to shallow clone, may be {@code null}
+ * @return the cloned array, {@code null} if {@code null} input
+ */
+ public static T[] clone(final T[] array) {
+ return array != null ? array.clone() : null;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * @param array the array to search
+ * @param valueToFind the value to find
+ * @return {@code true} if the array contains the object
+ */
+ public static boolean contains(final boolean[] array, final boolean valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(byte[])} and {@link Arrays#binarySearch(byte[], byte)}.
+ *
+ *
+ * @param array the array to search
+ * @param valueToFind the value to find
+ * @return {@code true} if the array contains the object
+ */
+ public static boolean contains(final byte[] array, final byte valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(char[])} and {@link Arrays#binarySearch(char[], char)}.
+ *
+ *
+ * @param array the array to search
+ * @param valueToFind the value to find
+ * @return {@code true} if the array contains the object
+ * @since 2.1
+ */
+ public static boolean contains(final char[] array, final char valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(double[])} and {@link Arrays#binarySearch(double[], double)}.
+ *
+ *
+ * @param array the array to search
+ * @param valueToFind the value to find
+ * @return {@code true} if the array contains the object
+ */
+ public static boolean contains(final double[] array, final double valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if a value falling within the given tolerance is in the
+ * given array. If the array contains a value within the inclusive range
+ * defined by (value - tolerance) to (value + tolerance).
+ *
+ * The method returns {@code false} if a {@code null} array
+ * is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(double[])} and {@link Arrays#binarySearch(double[], double)}.
+ *
+ *
+ * @param array the array to search
+ * @param valueToFind the value to find
+ * @param tolerance the array contains the tolerance of the search
+ * @return true if value falling within tolerance is in array
+ */
+ public static boolean contains(final double[] array, final double valueToFind, final double tolerance) {
+ return indexOf(array, valueToFind, 0, tolerance) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(float[])} and {@link Arrays#binarySearch(float[], float)}.
+ *
+ *
+ * @param array the array to search
+ * @param valueToFind the value to find
+ * @return {@code true} if the array contains the object
+ */
+ public static boolean contains(final float[] array, final float valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(int[])} and {@link Arrays#binarySearch(int[], int)}.
+ *
+ *
+ * @param array the array to search
+ * @param valueToFind the value to find
+ * @return {@code true} if the array contains the object
+ */
+ public static boolean contains(final int[] array, final int valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(long[])} and {@link Arrays#binarySearch(long[], long)}.
+ *
+ *
+ * @param array the array to search
+ * @param valueToFind the value to find
+ * @return {@code true} if the array contains the object
+ */
+ public static boolean contains(final long[] array, final long valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the object is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(Object[], Comparator)} and {@link Arrays#binarySearch(Object[], Object)}.
+ *
+ *
+ * @param array the array to search, may be {@code null}.
+ * @param objectToFind the object to find, may be {@code null}.
+ * @return {@code true} if the array contains the object
+ */
+ public static boolean contains(final Object[] array, final Object objectToFind) {
+ return indexOf(array, objectToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Checks if the value is in the given array.
+ *
+ * The method returns {@code false} if a {@code null} array is passed in.
+ *
+ *
+ * If the {@code array} elements you are searching implement {@link Comparator}, consider whether it is worth using
+ * {@link Arrays#sort(short[])} and {@link Arrays#binarySearch(short[], short)}.
+ *
+ *
+ * @param array the array to search
+ * @param valueToFind the value to find
+ * @return {@code true} if the array contains the object
+ */
+ public static boolean contains(final short[] array, final short valueToFind) {
+ return indexOf(array, valueToFind) != INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Returns a copy of the given array of size 1 greater than the argument.
+ * The last value of the array is left to the default value.
+ *
+ * @param array The array to copy, must not be {@code null}.
+ * @param newArrayComponentType If {@code array} is {@code null}, create a
+ * size 1 array of this type.
+ * @return A new copy of the array of size 1 greater than the input.
+ */
+ private static Object copyArrayGrow1(final Object array, final Class> newArrayComponentType) {
+ if (array != null) {
+ final int arrayLength = Array.getLength(array);
+ final Object newArray = Array.newInstance(array.getClass().getComponentType(), arrayLength + 1);
+ System.arraycopy(array, 0, newArray, 0, arrayLength);
+ return newArray;
+ }
+ return Array.newInstance(newArrayComponentType, 1);
+ }
+
+ /**
+ * Gets the nTh element of an array or null if the index is out of bounds or the array is null.
+ *
+ * @param The type of array elements.
+ * @param array The array to index.
+ * @param index The index
+ * @return the nTh element of an array or null if the index is out of bounds or the array is null.
+ * @since 3.11
+ */
+ public static T get(final T[] array, final int index) {
+ return get(array, index, null);
+ }
+
+ /**
+ * Gets the nTh element of an array or a default value if the index is out of bounds.
+ *
+ * @param The type of array elements.
+ * @param array The array to index.
+ * @param index The index
+ * @param defaultValue The return value of the given index is out of bounds.
+ * @return the nTh element of an array or a default value if the index is out of bounds.
+ * @since 3.11
+ */
+ public static T get(final T[] array, final int index, final T defaultValue) {
+ return isArrayIndexValid(array, index) ? array[index] : defaultValue;
+ }
+
+ /**
+ * Gets the length of the specified array.
+ * This method can deal with {@link Object} arrays and with primitive arrays.
+ *
+ * If the input array is {@code null}, {@code 0} is returned.
+ *
+ *
+ * @param array the array to retrieve the length from, may be {@code null}.
+ * @return The length of the array, or {@code 0} if the array is {@code null}
+ * @throws IllegalArgumentException if the object argument is not an array.
+ * @since 2.1
+ */
+ public static int getLength(final Object array) {
+ return array != null ? Array.getLength(array) : 0;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ * This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final boolean[] array, final boolean valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ * This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null}
+ * array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final boolean[] array, final boolean valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array == null) {
+ return bitSet;
+ }
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final byte[] array, final byte valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final byte[] array, final byte valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array == null) {
+ return bitSet;
+ }
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final char[] array, final char valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final char[] array, final char valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array == null) {
+ return bitSet;
+ }
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
This method returns empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final double[] array, final double valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value within a given tolerance in the array.
+ *
+ *
+ * This method will return all the indices of the value which fall between the region
+ * defined by valueToFind - tolerance and valueToFind + tolerance, each time between the nearest integers.
+ *
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param tolerance tolerance of the search
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final double[] array, final double valueToFind, final double tolerance) {
+ return indexesOf(array, valueToFind, 0, tolerance);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return a BitSet of the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final double[] array, final double valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array == null) {
+ return bitSet;
+ }
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
+ * This method will return the indices of the values which fall between the region
+ * defined by valueToFind - tolerance and valueToFind + tolerance, between the nearest integers.
+ *
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @param tolerance tolerance of the search
+ * @return a BitSet of the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final double[] array, final double valueToFind, int startIndex, final double tolerance) {
+ final BitSet bitSet = new BitSet();
+ if (array == null) {
+ return bitSet;
+ }
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex, tolerance);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final float[] array, final float valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final float[] array, final float valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array == null) {
+ return bitSet;
+ }
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final int[] array, final int valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final int[] array, final int valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array == null) {
+ return bitSet;
+ }
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final long[] array, final long valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final long[] array, final long valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array == null) {
+ return bitSet;
+ }
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given object in the array.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param objectToFind the object to find, may be {@code null}.
+ * @return a BitSet of all the indices of the object within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final Object[] array, final Object objectToFind) {
+ return indexesOf(array, objectToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given object in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param objectToFind the object to find, may be {@code null}.
+ * @param startIndex the index to start searching at
+ * @return a BitSet of all the indices of the object within the array starting at the index,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final Object[] array, final Object objectToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array == null) {
+ return bitSet;
+ }
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, objectToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the indices of the given value in the array.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final short[] array, final short valueToFind) {
+ return indexesOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the indices of the given value in the array starting at the given index.
+ *
+ *
This method returns an empty BitSet for a {@code null} input array.
+ *
+ *
A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return an empty BitSet.
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return a BitSet of all the indices of the value within the array,
+ * an empty BitSet if not found or {@code null} array input
+ * @since 3.10
+ */
+ public static BitSet indexesOf(final short[] array, final short valueToFind, int startIndex) {
+ final BitSet bitSet = new BitSet();
+ if (array == null) {
+ return bitSet;
+ }
+ while (startIndex < array.length) {
+ startIndex = indexOf(array, valueToFind, startIndex);
+ if (startIndex == INDEX_NOT_FOUND) {
+ break;
+ }
+ bitSet.set(startIndex);
+ ++startIndex;
+ }
+ return bitSet;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final boolean[] array, final boolean valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null}
+ * array input
+ */
+ public static int indexOf(final boolean[] array, final boolean valueToFind, final int startIndex) {
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final byte[] array, final byte valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final byte[] array, final byte valueToFind, final int startIndex) {
+ if (array == null) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ * @since 2.1
+ */
+ public static int indexOf(final char[] array, final char valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ * @since 2.1
+ */
+ public static int indexOf(final char[] array, final char valueToFind, final int startIndex) {
+ if (array == null) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final double[] array, final double valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value within a given tolerance in the array.
+ * This method will return the index of the first value which falls between the region
+ * defined by valueToFind - tolerance and valueToFind + tolerance.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param tolerance tolerance of the search
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final double[] array, final double valueToFind, final double tolerance) {
+ return indexOf(array, valueToFind, 0, tolerance);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final double[] array, final double valueToFind, final int startIndex) {
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ final boolean searchNaN = Double.isNaN(valueToFind);
+ for (int i = max0(startIndex); i < array.length; i++) {
+ final double element = array[i];
+ if (valueToFind == element || searchNaN && Double.isNaN(element)) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ * This method will return the index of the first value which falls between the region
+ * defined by valueToFind - tolerance and valueToFind + tolerance.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @param tolerance tolerance of the search
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final double[] array, final double valueToFind, final int startIndex, final double tolerance) {
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ final double min = valueToFind - tolerance;
+ final double max = valueToFind + tolerance;
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (array[i] >= min && array[i] <= max) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final float[] array, final float valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final float[] array, final float valueToFind, final int startIndex) {
+ if (isEmpty(array)) {
+ return INDEX_NOT_FOUND;
+ }
+ final boolean searchNaN = Float.isNaN(valueToFind);
+ for (int i = max0(startIndex); i < array.length; i++) {
+ final float element = array[i];
+ if (valueToFind == element || searchNaN && Float.isNaN(element)) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final int[] array, final int valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final int[] array, final int valueToFind, final int startIndex) {
+ if (array == null) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return the index of the value within the array, {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null}
+ * array input
+ */
+ public static int indexOf(final long[] array, final long valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final long[] array, final long valueToFind, final int startIndex) {
+ if (array == null) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given object in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param objectToFind the object to find, may be {@code null}.
+ * @return the index of the object within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final Object[] array, final Object objectToFind) {
+ return indexOf(array, objectToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given object in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}.
+ * @param objectToFind the object to find, may be {@code null}.
+ * @param startIndex the index to start searching at
+ * @return the index of the object within the array starting at the index,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final Object[] array, final Object objectToFind, int startIndex) {
+ if (array == null) {
+ return INDEX_NOT_FOUND;
+ }
+ startIndex = max0(startIndex);
+ if (objectToFind == null) {
+ for (int i = startIndex; i < array.length; i++) {
+ if (array[i] == null) {
+ return i;
+ }
+ }
+ } else {
+ for (int i = startIndex; i < array.length; i++) {
+ if (objectToFind.equals(array[i])) {
+ return i;
+ }
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the index of the given value in the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final short[] array, final short valueToFind) {
+ return indexOf(array, valueToFind, 0);
+ }
+
+ /**
+ * Finds the index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex is treated as zero. A startIndex larger than the array
+ * length will return {@link #INDEX_NOT_FOUND} ({@code -1}).
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the index to start searching at
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int indexOf(final short[] array, final short valueToFind, final int startIndex) {
+ if (array == null) {
+ return INDEX_NOT_FOUND;
+ }
+ for (int i = max0(startIndex); i < array.length; i++) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
When an array is returned, it is always a new array.
+ *
+ * @param index the position within {@code array} to insert the new values
+ * @param array the array to insert the values into, may be {@code null}
+ * @param values the new values to insert, may be {@code null}
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided
+ * and either {@code index < 0} or {@code index > array.length}
+ * @since 3.6
+ */
+ public static boolean[] insert(final int index, final boolean[] array, final boolean... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final boolean[] result = new boolean[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
When an array is returned, it is always a new array.
+ *
+ * @param index the position within {@code array} to insert the new values
+ * @param array the array to insert the values into, may be {@code null}
+ * @param values the new values to insert, may be {@code null}
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided
+ * and either {@code index < 0} or {@code index > array.length}
+ * @since 3.6
+ */
+ public static byte[] insert(final int index, final byte[] array, final byte... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final byte[] result = new byte[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
When an array is returned, it is always a new array.
+ *
+ * @param index the position within {@code array} to insert the new values
+ * @param array the array to insert the values into, may be {@code null}
+ * @param values the new values to insert, may be {@code null}
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided
+ * and either {@code index < 0} or {@code index > array.length}
+ * @since 3.6
+ */
+ public static char[] insert(final int index, final char[] array, final char... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final char[] result = new char[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
When an array is returned, it is always a new array.
+ *
+ * @param index the position within {@code array} to insert the new values
+ * @param array the array to insert the values into, may be {@code null}
+ * @param values the new values to insert, may be {@code null}
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided
+ * and either {@code index < 0} or {@code index > array.length}
+ * @since 3.6
+ */
+ public static double[] insert(final int index, final double[] array, final double... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final double[] result = new double[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
When an array is returned, it is always a new array.
+ *
+ * @param index the position within {@code array} to insert the new values
+ * @param array the array to insert the values into, may be {@code null}
+ * @param values the new values to insert, may be {@code null}
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided
+ * and either {@code index < 0} or {@code index > array.length}
+ * @since 3.6
+ */
+ public static float[] insert(final int index, final float[] array, final float... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final float[] result = new float[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
When an array is returned, it is always a new array.
+ *
+ * @param index the position within {@code array} to insert the new values
+ * @param array the array to insert the values into, may be {@code null}
+ * @param values the new values to insert, may be {@code null}
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided
+ * and either {@code index < 0} or {@code index > array.length}
+ * @since 3.6
+ */
+ public static int[] insert(final int index, final int[] array, final int... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final int[] result = new int[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
When an array is returned, it is always a new array.
+ *
+ * @param index the position within {@code array} to insert the new values
+ * @param array the array to insert the values into, may be {@code null}
+ * @param values the new values to insert, may be {@code null}
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided
+ * and either {@code index < 0} or {@code index > array.length}
+ * @since 3.6
+ */
+ public static long[] insert(final int index, final long[] array, final long... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final long[] result = new long[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Inserts elements into an array at the given index (starting from zero).
+ *
+ *
When an array is returned, it is always a new array.
+ *
+ * @param index the position within {@code array} to insert the new values
+ * @param array the array to insert the values into, may be {@code null}
+ * @param values the new values to insert, may be {@code null}
+ * @return The new array or {@code null} if the given array is {@code null}.
+ * @throws IndexOutOfBoundsException if {@code array} is provided
+ * and either {@code index < 0} or {@code index > array.length}
+ * @since 3.6
+ */
+ public static short[] insert(final int index, final short[] array, final short... values) {
+ if (array == null) {
+ return null;
+ }
+ if (isEmpty(values)) {
+ return clone(array);
+ }
+ if (index < 0 || index > array.length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + array.length);
+ }
+ final short[] result = new short[array.length + values.length];
+ System.arraycopy(values, 0, result, index, values.length);
+ if (index > 0) {
+ System.arraycopy(array, 0, result, 0, index);
+ }
+ if (index < array.length) {
+ System.arraycopy(array, index, result, index + values.length, array.length - index);
+ }
+ return result;
+ }
+
+ /**
+ * Checks if an array is empty or {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is empty or {@code null}
+ */
+ private static boolean isArrayEmpty(final Object array) {
+ return getLength(array) == 0;
+ }
+
+ /**
+ * Tests whether a given array can safely be accessed at the given index.
+ *
+ *
+ *
+ * @param the component type of the array
+ * @param array the array to inspect, may be {@code null}.
+ * @param index the index of the array to be inspected
+ * @return Whether the given index is safely-accessible in the given array
+ * @since 3.8
+ */
+ public static boolean isArrayIndexValid(final T[] array, final int index) {
+ return index >= 0 && getLength(array) > index;
+ }
+
+ /**
+ * Tests whether an array of primitive booleans is empty or {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is empty or {@code null}
+ * @since 2.1
+ */
+ public static boolean isEmpty(final boolean[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive bytes is empty or {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is empty or {@code null}
+ * @since 2.1
+ */
+ public static boolean isEmpty(final byte[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive chars is empty or {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is empty or {@code null}
+ * @since 2.1
+ */
+ public static boolean isEmpty(final char[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive doubles is empty or {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is empty or {@code null}
+ * @since 2.1
+ */
+ public static boolean isEmpty(final double[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive floats is empty or {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is empty or {@code null}
+ * @since 2.1
+ */
+ public static boolean isEmpty(final float[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive ints is empty or {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is empty or {@code null}
+ * @since 2.1
+ */
+ public static boolean isEmpty(final int[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive longs is empty or {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is empty or {@code null}
+ * @since 2.1
+ */
+ public static boolean isEmpty(final long[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of Objects is empty or {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is empty or {@code null}
+ * @since 2.1
+ */
+ public static boolean isEmpty(final Object[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive shorts is empty or {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is empty or {@code null}
+ * @since 2.1
+ */
+ public static boolean isEmpty(final short[] array) {
+ return isArrayEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive booleans is not empty and not {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is not empty and not {@code null}
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final boolean[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive bytes is not empty and not {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is not empty and not {@code null}
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final byte[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive chars is not empty and not {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is not empty and not {@code null}
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final char[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive doubles is not empty and not {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is not empty and not {@code null}
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final double[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive floats is not empty and not {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is not empty and not {@code null}
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final float[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive ints is not empty and not {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is not empty and not {@code null}
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final int[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive longs is not empty and not {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is not empty and not {@code null}
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final long[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of primitive shorts is not empty and not {@code null}.
+ *
+ * @param array the array to test
+ * @return {@code true} if the array is not empty and not {@code null}
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final short[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether an array of Objects is not empty and not {@code null}.
+ *
+ * @param the component type of the array
+ * @param array the array to test
+ * @return {@code true} if the array is not empty and not {@code null}
+ * @since 2.5
+ */
+ public static boolean isNotEmpty(final T[] array) {
+ return !isEmpty(array);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating
+ * {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}
+ * @param array2 the second array, may be {@code null}
+ * @return {@code true} if length of arrays matches, treating
+ * {@code null} as an empty array
+ */
+ public static boolean isSameLength(final boolean[] array1, final boolean[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating
+ * {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}
+ * @param array2 the second array, may be {@code null}
+ * @return {@code true} if length of arrays matches, treating
+ * {@code null} as an empty array
+ */
+ public static boolean isSameLength(final byte[] array1, final byte[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating
+ * {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}
+ * @param array2 the second array, may be {@code null}
+ * @return {@code true} if length of arrays matches, treating
+ * {@code null} as an empty array
+ */
+ public static boolean isSameLength(final char[] array1, final char[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating
+ * {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}
+ * @param array2 the second array, may be {@code null}
+ * @return {@code true} if length of arrays matches, treating
+ * {@code null} as an empty array
+ */
+ public static boolean isSameLength(final double[] array1, final double[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating
+ * {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}
+ * @param array2 the second array, may be {@code null}
+ * @return {@code true} if length of arrays matches, treating
+ * {@code null} as an empty array
+ */
+ public static boolean isSameLength(final float[] array1, final float[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating
+ * {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}
+ * @param array2 the second array, may be {@code null}
+ * @return {@code true} if length of arrays matches, treating
+ * {@code null} as an empty array
+ */
+ public static boolean isSameLength(final int[] array1, final int[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating
+ * {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}
+ * @param array2 the second array, may be {@code null}
+ * @return {@code true} if length of arrays matches, treating
+ * {@code null} as an empty array
+ */
+ public static boolean isSameLength(final long[] array1, final long[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating
+ * {@code null} arrays as length {@code 0}.
+ *
+ * Any multi-dimensional aspects of the arrays are ignored.
+ *
+ *
+ * @param array1 the first array, may be {@code null}
+ * @param array2 the second array, may be {@code null}
+ * @return {@code true} if length of arrays matches, treating
+ * {@code null} as an empty array
+ * @since 3.11
+ */
+ public static boolean isSameLength(final Object array1, final Object array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating
+ * {@code null} arrays as length {@code 0}.
+ *
+ * Any multi-dimensional aspects of the arrays are ignored.
+ *
+ *
+ * @param array1 the first array, may be {@code null}
+ * @param array2 the second array, may be {@code null}
+ * @return {@code true} if length of arrays matches, treating
+ * {@code null} as an empty array
+ */
+ public static boolean isSameLength(final Object[] array1, final Object[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same length, treating
+ * {@code null} arrays as length {@code 0}.
+ *
+ * @param array1 the first array, may be {@code null}
+ * @param array2 the second array, may be {@code null}
+ * @return {@code true} if length of arrays matches, treating
+ * {@code null} as an empty array
+ */
+ public static boolean isSameLength(final short[] array1, final short[] array2) {
+ return getLength(array1) == getLength(array2);
+ }
+
+ /**
+ * Tests whether two arrays are the same type taking into account
+ * multidimensional arrays.
+ *
+ * @param array1 the first array, must not be {@code null}
+ * @param array2 the second array, must not be {@code null}
+ * @return {@code true} if type of arrays matches
+ * @throws IllegalArgumentException if either array is {@code null}
+ */
+ public static boolean isSameType(final Object array1, final Object array2) {
+ if (array1 == null || array2 == null) {
+ throw new IllegalArgumentException("The Array must not be null");
+ }
+ return array1.getClass().getName().equals(array2.getClass().getName());
+ }
+
+ /**
+ * Tests whether the provided array is sorted according to natural ordering.
+ *
+ * @param array the array to check
+ * @return whether the array is sorted according to natural ordering
+ * @since 3.4
+ */
+ public static boolean isSorted(final double[] array) {
+ if (getLength(array) < 2) {
+ return true;
+ }
+ double previous = array[0];
+ final int n = array.length;
+ for (int i = 1; i < n; i++) {
+ final double current = array[i];
+ if (Double.compare(previous, current) > 0) {
+ return false;
+ }
+ previous = current;
+ }
+ return true;
+ }
+
+ /**
+ * Tests whether the provided array is sorted according to natural ordering.
+ *
+ * @param array the array to check
+ * @return whether the array is sorted according to natural ordering
+ * @since 3.4
+ */
+ public static boolean isSorted(final float[] array) {
+ if (getLength(array) < 2) {
+ return true;
+ }
+ float previous = array[0];
+ final int n = array.length;
+ for (int i = 1; i < n; i++) {
+ final float current = array[i];
+ if (Float.compare(previous, current) > 0) {
+ return false;
+ }
+ previous = current;
+ }
+ return true;
+ }
+
+ /**
+ * Tests whether the provided array is sorted according to the class's
+ * {@code compareTo} method.
+ *
+ * @param array the array to check
+ * @param the datatype of the array to check, it must implement {@link Comparable}
+ * @return whether the array is sorted
+ * @since 3.4
+ */
+ public static > boolean isSorted(final T[] array) {
+ return isSorted(array, Comparable::compareTo);
+ }
+
+ /**
+ * Tests whether the provided array is sorted according to the provided {@link Comparator}.
+ *
+ * @param array the array to check
+ * @param comparator the {@link Comparator} to compare over
+ * @param the datatype of the array
+ * @return whether the array is sorted
+ * @throws NullPointerException if {@code comparator} is {@code null}
+ * @since 3.4
+ */
+ public static boolean isSorted(final T[] array, final Comparator comparator) {
+ Objects.requireNonNull(comparator, "comparator");
+ if (getLength(array) < 2) {
+ return true;
+ }
+ T previous = array[0];
+ final int n = array.length;
+ for (int i = 1; i < n; i++) {
+ final T current = array[i];
+ if (comparator.compare(previous, current) > 0) {
+ return false;
+ }
+ previous = current;
+ }
+ return true;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) if
+ * {@code null} array input.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}
+ * @param valueToFind the object to find
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final boolean[] array, final boolean valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than
+ * the array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the start index to traverse backwards from
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final boolean[] array, final boolean valueToFind, int startIndex) {
+ if (isEmpty(array) || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}
+ * @param valueToFind the object to find
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final byte[] array, final byte valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
+ * array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the start index to traverse backwards from
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final byte[] array, final byte valueToFind, int startIndex) {
+ if (array == null || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}
+ * @param valueToFind the object to find
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ * @since 2.1
+ */
+ public static int lastIndexOf(final char[] array, final char valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
+ * array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the start index to traverse backwards from
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ * @since 2.1
+ */
+ public static int lastIndexOf(final char[] array, final char valueToFind, int startIndex) {
+ if (array == null || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}
+ * @param valueToFind the object to find
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final double[] array, final double valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value within a given tolerance in the array.
+ * This method will return the index of the last value which falls between the region
+ * defined by valueToFind - tolerance and valueToFind + tolerance.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to search for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param tolerance tolerance of the search
+ * @return the index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final double[] array, final double valueToFind, final double tolerance) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE, tolerance);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
+ * array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the start index to traverse backwards from
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final double[] array, final double valueToFind, int startIndex) {
+ if (isEmpty(array) || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ * This method will return the index of the last value which falls between the region
+ * defined by valueToFind - tolerance and valueToFind + tolerance.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
+ * array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the start index to traverse backwards from
+ * @param tolerance search for value within plus/minus this amount
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final double[] array, final double valueToFind, int startIndex, final double tolerance) {
+ if (isEmpty(array) || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ final double min = valueToFind - tolerance;
+ final double max = valueToFind + tolerance;
+ for (int i = startIndex; i >= 0; i--) {
+ if (array[i] >= min && array[i] <= max) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}
+ * @param valueToFind the object to find
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final float[] array, final float valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
+ * array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the start index to traverse backwards from
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final float[] array, final float valueToFind, int startIndex) {
+ if (isEmpty(array) || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}
+ * @param valueToFind the object to find
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final int[] array, final int valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
+ * array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the start index to traverse backwards from
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final int[] array, final int valueToFind, int startIndex) {
+ if (array == null || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}
+ * @param valueToFind the object to find
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final long[] array, final long valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
+ * array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the start index to traverse backwards from
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final long[] array, final long valueToFind, int startIndex) {
+ if (array == null || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given object within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}
+ * @param objectToFind the object to find, may be {@code null}
+ * @return the last index of the object within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final Object[] array, final Object objectToFind) {
+ return lastIndexOf(array, objectToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given object in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than
+ * the array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}
+ * @param objectToFind the object to find, may be {@code null}
+ * @param startIndex the start index to traverse backwards from
+ * @return the last index of the object within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final Object[] array, final Object objectToFind, int startIndex) {
+ if (array == null || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ if (objectToFind == null) {
+ for (int i = startIndex; i >= 0; i--) {
+ if (array[i] == null) {
+ return i;
+ }
+ }
+ } else if (array.getClass().getComponentType().isInstance(objectToFind)) {
+ for (int i = startIndex; i >= 0; i--) {
+ if (objectToFind.equals(array[i])) {
+ return i;
+ }
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ /**
+ * Finds the last index of the given value within the array.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * @param array the array to traverse backwards looking for the object, may be {@code null}
+ * @param valueToFind the object to find
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final short[] array, final short valueToFind) {
+ return lastIndexOf(array, valueToFind, Integer.MAX_VALUE);
+ }
+
+ /**
+ * Finds the last index of the given value in the array starting at the given index.
+ *
+ * This method returns {@link #INDEX_NOT_FOUND} ({@code -1}) for a {@code null} input array.
+ *
+ *
+ * A negative startIndex will return {@link #INDEX_NOT_FOUND} ({@code -1}). A startIndex larger than the
+ * array length will search from the end of the array.
+ *
+ *
+ * @param array the array to traverse for looking for the object, may be {@code null}
+ * @param valueToFind the value to find
+ * @param startIndex the start index to traverse backwards from
+ * @return the last index of the value within the array,
+ * {@link #INDEX_NOT_FOUND} ({@code -1}) if not found or {@code null} array input
+ */
+ public static int lastIndexOf(final short[] array, final short valueToFind, int startIndex) {
+ if (array == null || startIndex < 0) {
+ return INDEX_NOT_FOUND;
+ }
+ if (startIndex >= array.length) {
+ startIndex = array.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (valueToFind == array[i]) {
+ return i;
+ }
+ }
+ return INDEX_NOT_FOUND;
+ }
+
+ private static int max0(final int other) {
+ return Math.max(0, other);
+ }
+
+ /**
+ * Delegates to {@link Array#newInstance(Class,int)} using generics.
+ *
+ * @param The array type.
+ * @param componentType The array class.
+ * @param length the array length
+ * @return The new array.
+ * @throws NullPointerException if the specified {@code componentType} parameter is null.
+ * @since 3.13.0
+ */
+ @SuppressWarnings("unchecked") // OK, because array and values are of type T
+ public static T[] newInstance(final Class componentType, final int length) {
+ return (T[]) Array.newInstance(componentType, length);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns a default array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param The array type.
+ * @param array the array to check for {@code null} or empty
+ * @param defaultArray A default array, usually empty.
+ * @return the same array, or defaultArray if {@code null} or empty input.
+ * @since 3.15.0
+ */
+ public static T[] nullTo(final T[] array, final T[] defaultArray) {
+ return isEmpty(array) ? defaultArray : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static boolean[] nullToEmpty(final boolean[] array) {
+ return isEmpty(array) ? EMPTY_BOOLEAN_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static Boolean[] nullToEmpty(final Boolean[] array) {
+ return nullTo(array, EMPTY_BOOLEAN_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static byte[] nullToEmpty(final byte[] array) {
+ return isEmpty(array) ? EMPTY_BYTE_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static Byte[] nullToEmpty(final Byte[] array) {
+ return nullTo(array, EMPTY_BYTE_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static char[] nullToEmpty(final char[] array) {
+ return isEmpty(array) ? EMPTY_CHAR_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static Character[] nullToEmpty(final Character[] array) {
+ return nullTo(array, EMPTY_CHARACTER_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 3.2
+ */
+ public static Class>[] nullToEmpty(final Class>[] array) {
+ return nullTo(array, EMPTY_CLASS_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static double[] nullToEmpty(final double[] array) {
+ return isEmpty(array) ? EMPTY_DOUBLE_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static Double[] nullToEmpty(final Double[] array) {
+ return nullTo(array, EMPTY_DOUBLE_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static float[] nullToEmpty(final float[] array) {
+ return isEmpty(array) ? EMPTY_FLOAT_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static Float[] nullToEmpty(final Float[] array) {
+ return nullTo(array, EMPTY_FLOAT_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static int[] nullToEmpty(final int[] array) {
+ return isEmpty(array) ? EMPTY_INT_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static Integer[] nullToEmpty(final Integer[] array) {
+ return nullTo(array, EMPTY_INTEGER_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static long[] nullToEmpty(final long[] array) {
+ return isEmpty(array) ? EMPTY_LONG_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static Long[] nullToEmpty(final Long[] array) {
+ return nullTo(array, EMPTY_LONG_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static Object[] nullToEmpty(final Object[] array) {
+ return nullTo(array, EMPTY_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static short[] nullToEmpty(final short[] array) {
+ return isEmpty(array) ? EMPTY_SHORT_ARRAY : array;
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static Short[] nullToEmpty(final Short[] array) {
+ return nullTo(array, EMPTY_SHORT_OBJECT_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * As a memory optimizing technique an empty array passed in will be overridden with
+ * the empty {@code public static} references in this class.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @return the same array, {@code public static} empty array if {@code null} or empty input
+ * @since 2.5
+ */
+ public static String[] nullToEmpty(final String[] array) {
+ return nullTo(array, EMPTY_STRING_ARRAY);
+ }
+
+ /**
+ * Defensive programming technique to change a {@code null}
+ * reference to an empty one.
+ *
+ * This method returns an empty array for a {@code null} input array.
+ *
+ *
+ * @param array the array to check for {@code null} or empty
+ * @param type the class representation of the desired array
+ * @param the class type
+ * @return the same array, {@code public static} empty array if {@code null}
+ * @throws IllegalArgumentException if the type argument is null
+ * @since 3.5
+ */
+ public static T[] nullToEmpty(final T[] array, final Class type) {
+ if (type == null) {
+ throw new IllegalArgumentException("The type must not be null");
+ }
+ if (array == null) {
+ return type.cast(Array.newInstance(type.getComponentType(), 0));
+ }
+ return array;
+ }
+
+ /**
+ * Gets the {@link ThreadLocalRandom} for {@code shuffle} methods that don't take a {@link Random} argument.
+ *
+ * @return the current ThreadLocalRandom.
+ */
+ private static ThreadLocalRandom random() {
+ return ThreadLocalRandom.current();
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array.
+ * All subsequent elements are shifted to the left (subtracts one from
+ * their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException
+ * will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}
+ * @param index the position of the element to be removed
+ * @return A new array containing the existing elements except the element
+ * at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static boolean[] remove(final boolean[] array, final int index) {
+ return (boolean[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array.
+ * All subsequent elements are shifted to the left (subtracts one from
+ * their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException
+ * will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}
+ * @param index the position of the element to be removed
+ * @return A new array containing the existing elements except the element
+ * at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static byte[] remove(final byte[] array, final int index) {
+ return (byte[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array.
+ * All subsequent elements are shifted to the left (subtracts one from
+ * their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException
+ * will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}
+ * @param index the position of the element to be removed
+ * @return A new array containing the existing elements except the element
+ * at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static char[] remove(final char[] array, final int index) {
+ return (char[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array.
+ * All subsequent elements are shifted to the left (subtracts one from
+ * their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException
+ * will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}
+ * @param index the position of the element to be removed
+ * @return A new array containing the existing elements except the element
+ * at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static double[] remove(final double[] array, final int index) {
+ return (double[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array.
+ * All subsequent elements are shifted to the left (subtracts one from
+ * their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException
+ * will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}
+ * @param index the position of the element to be removed
+ * @return A new array containing the existing elements except the element
+ * at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static float[] remove(final float[] array, final int index) {
+ return (float[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array.
+ * All subsequent elements are shifted to the left (subtracts one from
+ * their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException
+ * will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}
+ * @param index the position of the element to be removed
+ * @return A new array containing the existing elements except the element
+ * at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static int[] remove(final int[] array, final int index) {
+ return (int[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array.
+ * All subsequent elements are shifted to the left (subtracts one from
+ * their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException
+ * will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}
+ * @param index the position of the element to be removed
+ * @return A new array containing the existing elements except the element
+ * at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static long[] remove(final long[] array, final int index) {
+ return (long[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array.
+ * All subsequent elements are shifted to the left (subtracts one from
+ * their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException
+ * will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}
+ * @param index the position of the element to be removed
+ * @return A new array containing the existing elements except the element
+ * at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ private static Object remove(final Object array, final int index) {
+ final int length = getLength(array);
+ if (index < 0 || index >= length) {
+ throw new IndexOutOfBoundsException("Index: " + index + ", Length: " + length);
+ }
+ final Object result = Array.newInstance(array.getClass().getComponentType(), length - 1);
+ System.arraycopy(array, 0, result, 0, index);
+ if (index < length - 1) {
+ System.arraycopy(array, index + 1, result, index, length - index - 1);
+ }
+ return result;
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array.
+ * All subsequent elements are shifted to the left (subtracts one from
+ * their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException
+ * will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param array the array to remove the element from, may not be {@code null}
+ * @param index the position of the element to be removed
+ * @return A new array containing the existing elements except the element
+ * at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ public static short[] remove(final short[] array, final int index) {
+ return (short[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the element at the specified position from the specified array.
+ * All subsequent elements are shifted to the left (subtracts one from
+ * their indices).
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the element on the specified position. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * If the input array is {@code null}, an IndexOutOfBoundsException
+ * will be thrown, because in that case no valid index can be specified.
+ *
+ *
+ * @param the component type of the array
+ * @param array the array to remove the element from, may not be {@code null}
+ * @param index the position of the element to be removed
+ * @return A new array containing the existing elements except the element
+ * at the specified position.
+ * @throws IndexOutOfBoundsException if the index is out of range
+ * (index < 0 || index >= array.length), or if the array is {@code null}.
+ * @since 2.1
+ */
+ @SuppressWarnings("unchecked") // remove() always creates an array of the same type as its input
+ public static T[] remove(final T[] array, final int index) {
+ return (T[]) remove((Object) array, index);
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified boolean array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static boolean[] removeAllOccurrences(final boolean[] array, final boolean element) {
+ return (boolean[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified byte array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static byte[] removeAllOccurrences(final byte[] array, final byte element) {
+ return (byte[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified char array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static char[] removeAllOccurrences(final char[] array, final char element) {
+ return (char[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified double array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static double[] removeAllOccurrences(final double[] array, final double element) {
+ return (double[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified float array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static float[] removeAllOccurrences(final float[] array, final float element) {
+ return (float[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified int array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static int[] removeAllOccurrences(final int[] array, final int element) {
+ return (int[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified long array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static long[] removeAllOccurrences(final long[] array, final long element) {
+ return (long[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified short array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ public static short[] removeAllOccurrences(final short[] array, final short element) {
+ return (short[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes the occurrences of the specified element from the specified array.
+ *
+ * All subsequent elements are shifted to the left (subtracts one from their indices).
+ * If the array doesn't contain such an element, no elements are removed from the array.
+ * {@code null} will be returned if the input array is {@code null}.
+ *
+ *
+ * @param the type of object in the array, may be {@code null}.
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param element the element to remove, may be {@code null}.
+ * @return A new array containing the existing elements except the occurrences of the specified element.
+ * @since 3.10
+ */
+ @SuppressWarnings("unchecked")
+ public static T[] removeAllOccurrences(final T[] array, final T element) {
+ return (T[]) removeAt(array, indexesOf(array, element));
+ }
+
+ /**
+ * Removes multiple array elements specified by indices.
+ *
+ * @param array the input array, will not be modified, and may be {@code null}.
+ * @param indices to remove.
+ * @return new array of same type minus elements specified by the set bits in {@code indices}.
+ */
+ // package protected for access by unit tests
+ static Object removeAt(final Object array, final BitSet indices) {
+ if (array == null) {
+ return null;
+ }
+ final int srcLength = getLength(array);
+ // No need to check maxIndex here, because method only currently called from removeElements()
+ // which guarantee to generate only valid bit entries.
+// final int maxIndex = indices.length();
+// if (maxIndex > srcLength) {
+// throw new IndexOutOfBoundsException("Index: " + (maxIndex-1) + ", Length: " + srcLength);
+// }
+ final int removals = indices.cardinality(); // true bits are items to remove
+ final Object result = Array.newInstance(array.getClass().getComponentType(), srcLength - removals);
+ int srcIndex = 0;
+ int destIndex = 0;
+ int count;
+ int set;
+ while ((set = indices.nextSetBit(srcIndex)) != -1) {
+ count = set - srcIndex;
+ if (count > 0) {
+ System.arraycopy(array, srcIndex, result, destIndex, count);
+ destIndex += count;
+ }
+ srcIndex = indices.nextClearBit(set);
+ }
+ count = srcLength - srcIndex;
+ if (count > 0) {
+ System.arraycopy(array, srcIndex, result, destIndex, count);
+ }
+ return result;
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static boolean[] removeElement(final boolean[] array, final boolean element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static byte[] removeElement(final byte[] array, final byte element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static char[] removeElement(final char[] array, final char element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static double[] removeElement(final double[] array, final double element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static float[] removeElement(final float[] array, final float element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static int[] removeElement(final int[] array, final int element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static long[] removeElement(final long[] array, final long element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static short[] removeElement(final short[] array, final short element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Removes the first occurrence of the specified element from the
+ * specified array. All subsequent elements are shifted to the left
+ * (subtracts one from their indices). If the array doesn't contain
+ * such an element, no elements are removed from the array.
+ *
+ * This method returns a new array with the same elements of the input
+ * array except the first occurrence of the specified element. The component
+ * type of the returned array is always the same as that of the input
+ * array.
+ *
+ *
+ * @param the component type of the array
+ * @param array the input array, may be {@code null}.
+ * @param element the element to be removed, may be {@code null}.
+ * @return A new array containing the existing elements except the first
+ * occurrence of the specified element.
+ * @since 2.1
+ */
+ public static T[] removeElement(final T[] array, final Object element) {
+ final int index = indexOf(array, element);
+ return index == INDEX_NOT_FOUND ? clone(array) : remove(array, index);
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final boolean[] array) {
+ if (array == null) {
+ return;
+ }
+ reverse(array, 0, array.length);
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final boolean[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ boolean tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}
+ */
+ public static void reverse(final byte[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final byte[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ byte tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}
+ */
+ public static void reverse(final char[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final char[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ char tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}
+ */
+ public static void reverse(final double[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final double[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ double tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final float[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final float[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ float tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final int[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final int[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ int tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final long[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final long[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ long tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * There is no special handling for multi-dimensional arrays.
+ *
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final Object[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Under value (<0) is promoted to 0, over value (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Under value (< start index) results in no
+ * change. Over value (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final Object[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ Object tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Reverses the order of the given array.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array the array to reverse, may be {@code null}.
+ */
+ public static void reverse(final short[] array) {
+ if (array != null) {
+ reverse(array, 0, array.length);
+ }
+ }
+
+ /**
+ * Reverses the order of the given array in the given range.
+ *
+ * This method does nothing for a {@code null} input array.
+ *
+ *
+ * @param array
+ * the array to reverse, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are reversed in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @since 3.2
+ */
+ public static void reverse(final short[] array, final int startIndexInclusive, final int endIndexExclusive) {
+ if (array == null) {
+ return;
+ }
+ int i = Math.max(startIndexInclusive, 0);
+ int j = Math.min(array.length, endIndexExclusive) - 1;
+ short tmp;
+ while (j > i) {
+ tmp = array[j];
+ array[j] = array[i];
+ array[i] = tmp;
+ j--;
+ i++;
+ }
+ }
+
+ /**
+ * Sets all elements of the specified array, using the provided generator supplier to compute each element.
+ *
+ * If the generator supplier throws an exception, it is relayed to the caller and the array is left in an indeterminate
+ * state.
+ *
+ *
+ * @param type of elements of the array, may be {@code null}.
+ * @param array array to be initialized, may be {@code null}.
+ * @param generator a function accepting an index and producing the desired value for that position.
+ * @return the input array
+ * @since 3.13.0
+ */
+ public static T[] setAll(final T[] array, final IntFunction extends T> generator) {
+ if (array != null && generator != null) {
+ Arrays.setAll(array, generator);
+ }
+ return array;
+ }
+
+ /**
+ * Sets all elements of the specified array, using the provided generator supplier to compute each element.
+ *
+ * If the generator supplier throws an exception, it is relayed to the caller and the array is left in an indeterminate
+ * state.
+ *
+ *
+ * @param type of elements of the array, may be {@code null}.
+ * @param array array to be initialized, may be {@code null}.
+ * @param generator a function accepting an index and producing the desired value for that position.
+ * @return the input array
+ * @since 3.13.0
+ */
+ public static T[] setAll(final T[] array, final Supplier extends T> generator) {
+ if (array != null && generator != null) {
+ for (int i = 0; i < array.length; i++) {
+ array[i] = generator.get();
+ }
+ }
+ return array;
+ }
+
+ /**
+ * Shifts the order of the given boolean array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final boolean[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given boolean array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final boolean[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given byte array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final byte[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given byte array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final byte[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given char array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final char[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given char array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final char[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given double array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final double[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given double array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final double[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given float array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final float[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given float array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final float[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given int array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final int[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given int array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final int[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given long array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final long[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given long array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final long[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final Object[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final Object[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shifts the order of the given short array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array the array to shift, may be {@code null}.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final short[] array, final int offset) {
+ if (array != null) {
+ shift(array, 0, array.length, offset);
+ }
+ }
+
+ /**
+ * Shifts the order of a series of elements in the given short array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for {@code null} or empty input arrays.
+ *
+ * @param array
+ * the array to shift, may be {@code null}.
+ * @param startIndexInclusive
+ * the starting index. Undervalue (<0) is promoted to 0, overvalue (>array.length) results in no
+ * change.
+ * @param endIndexExclusive
+ * elements up to endIndex-1 are shifted in the array. Undervalue (< start index) results in no
+ * change. Overvalue (>array.length) is demoted to array length.
+ * @param offset
+ * The number of positions to rotate the elements. If the offset is larger than the number of elements to
+ * rotate, than the effective offset is modulo the number of elements to rotate.
+ * @since 3.5
+ */
+ public static void shift(final short[] array, int startIndexInclusive, int endIndexExclusive, int offset) {
+ if (array == null || startIndexInclusive >= array.length - 1 || endIndexExclusive <= 0) {
+ return;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ int n = endIndexExclusive - startIndexInclusive;
+ if (n <= 1) {
+ return;
+ }
+ offset %= n;
+ if (offset < 0) {
+ offset += n;
+ }
+ // For algorithm explanations and proof of O(n) time complexity and O(1) space complexity
+ // see https://beradrian.wordpress.com/2015/04/07/shift-an-array-in-on-in-place/
+ while (n > 1 && offset > 0) {
+ final int nOffset = n - offset;
+ if (offset > nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + n - nOffset, nOffset);
+ n = offset;
+ offset -= nOffset;
+ } else if (offset < nOffset) {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ startIndexInclusive += offset;
+ n = nOffset;
+ } else {
+ swap(array, startIndexInclusive, startIndexInclusive + nOffset, offset);
+ break;
+ }
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final boolean[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle
+ * @param random the source of randomness used to permute the elements
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final boolean[] array, final Random random) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final byte[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle
+ * @param random the source of randomness used to permute the elements
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final byte[] array, final Random random) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final char[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle
+ * @param random the source of randomness used to permute the elements
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final char[] array, final Random random) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final double[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle
+ * @param random the source of randomness used to permute the elements
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final double[] array, final Random random) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final float[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle
+ * @param random the source of randomness used to permute the elements
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final float[] array, final Random random) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final int[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle
+ * @param random the source of randomness used to permute the elements
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final int[] array, final Random random) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final long[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle
+ * @param random the source of randomness used to permute the elements
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final long[] array, final Random random) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final Object[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle
+ * @param random the source of randomness used to permute the elements
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final Object[] array, final Random random) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * This method uses the current {@link ThreadLocalRandom} as its random number generator.
+ *
+ *
+ * Instances of {@link ThreadLocalRandom} are not cryptographically secure. For security-sensitive applications, consider using a {@code shuffle} method
+ * with a {@link SecureRandom} argument.
+ *
+ *
+ * @param array the array to shuffle.
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final short[] array) {
+ shuffle(array, random());
+ }
+
+ /**
+ * Shuffles randomly the elements of the specified array using the Fisher-Yates shuffle
+ * algorithm.
+ *
+ * @param array the array to shuffle
+ * @param random the source of randomness used to permute the elements
+ * @see Fisher-Yates shuffle algorithm
+ * @since 3.6
+ */
+ public static void shuffle(final short[] array, final Random random) {
+ for (int i = array.length; i > 1; i--) {
+ swap(array, i - 1, random.nextInt(i), 1);
+ }
+ }
+
+ /**
+ * Tests whether the given data array starts with an expected array, for example, signature bytes.
+ *
+ * If both arrays are null, the method returns true. The method return false when one array is null and the other not.
+ *
+ *
+ * @param data The data to search, maybe larger than the expected data.
+ * @param expected The expected data to find.
+ * @return whether a match was found.
+ * @since 3.18.0
+ */
+ public static boolean startsWith(final byte[] data, final byte[] expected) {
+ if (data == expected) {
+ return true;
+ }
+ if (data == null || expected == null) {
+ return false;
+ }
+ final int dataLen = data.length;
+ if (expected.length > dataLen) {
+ return false;
+ }
+ if (expected.length == dataLen) {
+ // delegate to Arrays.equals() which has optimizations on Java > 8
+ return Arrays.equals(data, expected);
+ }
+ // Once we are on Java 9+ we can delegate to Arrays here as well (or not).
+ for (int i = 0; i < expected.length; i++) {
+ if (data[i] != expected[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Produces a new {@code boolean} array containing the elements
+ * between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive.
+ * Null array input produces null output.
+ *
+ *
+ * @param array the array
+ * @param startIndexInclusive the starting index. Undervalue (<0)
+ * is promoted to 0, overvalue (>array.length) results
+ * in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the
+ * returned subarray. Undervalue (< startIndex) produces
+ * empty array, overvalue (>array.length) is demoted to
+ * array length.
+ * @return a new array containing the elements between
+ * the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(boolean[], int, int)
+ */
+ public static boolean[] subarray(final boolean[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_BOOLEAN_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, boolean[]::new);
+ }
+
+ /**
+ * Produces a new {@code byte} array containing the elements
+ * between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive.
+ * Null array input produces null output.
+ *
+ *
+ * @param array the array
+ * @param startIndexInclusive the starting index. Undervalue (<0)
+ * is promoted to 0, overvalue (>array.length) results
+ * in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the
+ * returned subarray. Undervalue (< startIndex) produces
+ * empty array, overvalue (>array.length) is demoted to
+ * array length.
+ * @return a new array containing the elements between
+ * the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(byte[], int, int)
+ */
+ public static byte[] subarray(final byte[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_BYTE_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, byte[]::new);
+ }
+
+ /**
+ * Produces a new {@code char} array containing the elements
+ * between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive.
+ * Null array input produces null output.
+ *
+ *
+ * @param array the array
+ * @param startIndexInclusive the starting index. Undervalue (<0)
+ * is promoted to 0, overvalue (>array.length) results
+ * in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the
+ * returned subarray. Undervalue (< startIndex) produces
+ * empty array, overvalue (>array.length) is demoted to
+ * array length.
+ * @return a new array containing the elements between
+ * the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(char[], int, int)
+ */
+ public static char[] subarray(final char[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_CHAR_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, char[]::new);
+ }
+
+ /**
+ * Produces a new {@code double} array containing the elements
+ * between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive.
+ * Null array input produces null output.
+ *
+ *
+ * @param array the array
+ * @param startIndexInclusive the starting index. Undervalue (<0)
+ * is promoted to 0, overvalue (>array.length) results
+ * in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the
+ * returned subarray. Undervalue (< startIndex) produces
+ * empty array, overvalue (>array.length) is demoted to
+ * array length.
+ * @return a new array containing the elements between
+ * the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(double[], int, int)
+ */
+ public static double[] subarray(final double[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_DOUBLE_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, double[]::new);
+ }
+
+ /**
+ * Produces a new {@code float} array containing the elements
+ * between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive.
+ * Null array input produces null output.
+ *
+ *
+ * @param array the array
+ * @param startIndexInclusive the starting index. Undervalue (<0)
+ * is promoted to 0, overvalue (>array.length) results
+ * in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the
+ * returned subarray. Undervalue (< startIndex) produces
+ * empty array, overvalue (>array.length) is demoted to
+ * array length.
+ * @return a new array containing the elements between
+ * the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(float[], int, int)
+ */
+ public static float[] subarray(final float[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_FLOAT_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, float[]::new);
+ }
+
+ /**
+ * Produces a new {@code int} array containing the elements
+ * between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive.
+ * Null array input produces null output.
+ *
+ *
+ * @param array the array
+ * @param startIndexInclusive the starting index. Undervalue (<0)
+ * is promoted to 0, overvalue (>array.length) results
+ * in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the
+ * returned subarray. Undervalue (< startIndex) produces
+ * empty array, overvalue (>array.length) is demoted to
+ * array length.
+ * @return a new array containing the elements between
+ * the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(int[], int, int)
+ */
+ public static int[] subarray(final int[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_INT_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, int[]::new);
+ }
+
+ /**
+ * Produces a new {@code long} array containing the elements
+ * between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive.
+ * Null array input produces null output.
+ *
+ *
+ * @param array the array
+ * @param startIndexInclusive the starting index. Undervalue (<0)
+ * is promoted to 0, overvalue (>array.length) results
+ * in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the
+ * returned subarray. Undervalue (< startIndex) produces
+ * empty array, overvalue (>array.length) is demoted to
+ * array length.
+ * @return a new array containing the elements between
+ * the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(long[], int, int)
+ */
+ public static long[] subarray(final long[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_LONG_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, long[]::new);
+ }
+
+ /**
+ * Produces a new {@code short} array containing the elements
+ * between the start and end indices.
+ *
+ * The start index is inclusive, the end index exclusive.
+ * Null array input produces null output.
+ *
+ *
+ * @param array the array
+ * @param startIndexInclusive the starting index. Undervalue (<0)
+ * is promoted to 0, overvalue (>array.length) results
+ * in an empty array.
+ * @param endIndexExclusive elements up to endIndex-1 are present in the
+ * returned subarray. Undervalue (< startIndex) produces
+ * empty array, overvalue (>array.length) is demoted to
+ * array length.
+ * @return a new array containing the elements between
+ * the start and end indices.
+ * @since 2.1
+ * @see Arrays#copyOfRange(short[], int, int)
+ */
+ public static short[] subarray(final short[] array, int startIndexInclusive, int endIndexExclusive) {
+ if (array == null) {
+ return null;
+ }
+ startIndexInclusive = max0(startIndexInclusive);
+ endIndexExclusive = Math.min(endIndexExclusive, array.length);
+ final int newSize = endIndexExclusive - startIndexInclusive;
+ if (newSize <= 0) {
+ return EMPTY_SHORT_ARRAY;
+ }
+ return arraycopy(array, startIndexInclusive, 0, newSize, short[]::new);
+ }
+
+ /**
+ * Swaps two elements in the given boolean array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap
+ * @param offset2 the index of the second element to swap
+ * @since 3.5
+ */
+ public static void swap(final boolean[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given boolean array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap
+ * @param offset2 the index of the second element in the series to swap
+ * @param len the number of elements to swap starting with the given indices
+ * @since 3.5
+ */
+ public static void swap(final boolean[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final boolean aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given byte array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap
+ * @param offset2 the index of the second element to swap
+ * @since 3.5
+ */
+ public static void swap(final byte[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given byte array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap
+ * @param offset2 the index of the second element in the series to swap
+ * @param len the number of elements to swap starting with the given indices
+ * @since 3.5
+ */
+ public static void swap(final byte[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final byte aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given char array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap
+ * @param offset2 the index of the second element to swap
+ * @since 3.5
+ */
+ public static void swap(final char[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given char array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap
+ * @param offset2 the index of the second element in the series to swap
+ * @param len the number of elements to swap starting with the given indices
+ * @since 3.5
+ */
+ public static void swap(final char[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final char aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given double array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap
+ * @param offset2 the index of the second element to swap
+ * @since 3.5
+ */
+ public static void swap(final double[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given double array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap
+ * @param offset2 the index of the second element in the series to swap
+ * @param len the number of elements to swap starting with the given indices
+ * @since 3.5
+ */
+ public static void swap(final double[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final double aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given float array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element to swap
+ * @param offset2 the index of the second element to swap
+ * @since 3.5
+ */
+ public static void swap(final float[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given float array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}.
+ * @param offset1 the index of the first element in the series to swap
+ * @param offset2 the index of the second element in the series to swap
+ * @param len the number of elements to swap starting with the given indices
+ * @since 3.5
+ */
+ public static void swap(final float[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final float aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+
+ }
+
+ /**
+ * Swaps two elements in the given int array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}
+ * @param offset1 the index of the first element to swap
+ * @param offset2 the index of the second element to swap
+ * @since 3.5
+ */
+ public static void swap(final int[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given int array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}
+ * @param offset1 the index of the first element in the series to swap
+ * @param offset2 the index of the second element in the series to swap
+ * @param len the number of elements to swap starting with the given indices
+ * @since 3.5
+ */
+ public static void swap(final int[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final int aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given long array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * @param array the array to swap, may be {@code null}
+ * @param offset1 the index of the first element to swap
+ * @param offset2 the index of the second element to swap
+ * @since 3.5
+ */
+ public static void swap(final long[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given long array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}
+ * @param offset1 the index of the first element in the series to swap
+ * @param offset2 the index of the second element in the series to swap
+ * @param len the number of elements to swap starting with the given indices
+ * @since 3.5
+ */
+ public static void swap(final long[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final long aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * @param array the array to swap, may be {@code null}
+ * @param offset1 the index of the first element to swap
+ * @param offset2 the index of the second element to swap
+ * @since 3.5
+ */
+ public static void swap(final Object[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}
+ * @param offset1 the index of the first element in the series to swap
+ * @param offset2 the index of the second element in the series to swap
+ * @param len the number of elements to swap starting with the given indices
+ * @since 3.5
+ */
+ public static void swap(final Object[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final Object aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Swaps two elements in the given short array.
+ *
+ *
There is no special handling for multi-dimensional arrays. This method
+ * does nothing for a {@code null} or empty input array or for overflow indices.
+ * Negative indices are promoted to 0(zero).
+ *
+ * Examples:
+ *
+ *
ArrayUtils.swap([1, 2, 3], 0, 2) -> [3, 2, 1]
+ *
ArrayUtils.swap([1, 2, 3], 0, 0) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], 1, 0) -> [2, 1, 3]
+ *
ArrayUtils.swap([1, 2, 3], 0, 5) -> [1, 2, 3]
+ *
ArrayUtils.swap([1, 2, 3], -1, 1) -> [2, 1, 3]
+ *
+ *
+ * @param array the array to swap, may be {@code null}
+ * @param offset1 the index of the first element to swap
+ * @param offset2 the index of the second element to swap
+ * @since 3.5
+ */
+ public static void swap(final short[] array, final int offset1, final int offset2) {
+ swap(array, offset1, offset2, 1);
+ }
+
+ /**
+ * Swaps a series of elements in the given short array.
+ *
+ *
This method does nothing for a {@code null} or empty input array or
+ * for overflow indices. Negative indices are promoted to 0(zero). If any
+ * of the sub-arrays to swap falls outside of the given array, then the
+ * swap is stopped at the end of the array and as many as possible elements
+ * are swapped.
+ *
+ * @param array the array to swap, may be {@code null}
+ * @param offset1 the index of the first element in the series to swap
+ * @param offset2 the index of the second element in the series to swap
+ * @param len the number of elements to swap starting with the given indices
+ * @since 3.5
+ */
+ public static void swap(final short[] array, int offset1, int offset2, int len) {
+ if (isEmpty(array) || offset1 >= array.length || offset2 >= array.length) {
+ return;
+ }
+ offset1 = max0(offset1);
+ offset2 = max0(offset2);
+ if (offset1 == offset2) {
+ return;
+ }
+ len = Math.min(Math.min(len, array.length - offset1), array.length - offset2);
+ for (int i = 0; i < len; i++, offset1++, offset2++) {
+ final short aux = array[offset1];
+ array[offset1] = array[offset2];
+ array[offset2] = aux;
+ }
+ }
+
+ /**
+ * Create a type-safe generic array.
+ *
+ * The Java language does not allow an array to be created from a generic type:
+ *
+ *
+ public static <T> T[] createAnArray(int size) {
+ return new T[size]; // compiler error here
+ }
+ public static <T> T[] createAnArray(int size) {
+ return (T[]) new Object[size]; // ClassCastException at runtime
+ }
+ *
+ *
+ * Therefore new arrays of generic types can be created with this method.
+ * For example, an array of Strings can be created:
+ *
+ * The method is typically used in scenarios, where the caller itself uses generic types
+ * that have to be combined into an array.
+ *
+ *
+ * Note, this method makes only sense to provide arguments of the same type so that the
+ * compiler can deduce the type of the array itself. While it is possible to select the
+ * type explicitly like in
+ * {@code Number[] array = ArrayUtils.toArray(Integer.valueOf(42), Double.valueOf(Math.PI))},
+ * there is no real advantage when compared to
+ * {@code new Number[] {Integer.valueOf(42), Double.valueOf(Math.PI)}}.
+ *
+ *
+ * @param the array's element type
+ * @param items the varargs array items, null allowed
+ * @return the array, not null unless a null array is passed in
+ * @since 3.0
+ */
+ @SuppressWarnings("unchecked")
+ public static T[] toArray(final T... items) {
+ return items;
+ }
+
+ /**
+ * Converts the given array into a {@link java.util.Map}. Each element of the array
+ * must be either a {@link java.util.Map.Entry} or an Array, containing at least two
+ * elements, where the first element is used as key and the second as
+ * value.
+ *
+ * This method returns {@code null} for a {@code null} input array.
+ *
+ *
+ * @param array an array whose elements are either a {@link java.util.Map.Entry} or
+ * an Array containing at least two elements, may be {@code null}
+ * @return a {@link Map} that was created from the array
+ * @throws IllegalArgumentException if one element of this Array is
+ * itself an Array containing less than two elements
+ * @throws IllegalArgumentException if the array contains elements other
+ * than {@link java.util.Map.Entry} and an Array
+ */
+ public static Map
*
* @since 2.5
*/
public class MethodUtils {
+ private static final Comparator METHOD_BY_SIGNATURE = Comparator.comparing(Method::toString);
+
+ /**
+ * Computes the aggregate number of inheritance hops between assignable argument class types. Returns -1
+ * if the arguments aren't assignable. Fills a specific purpose for getMatchingMethod and is not generalized.
+ *
+ * @param fromClassArray the Class array to calculate the distance from.
+ * @param toClassArray the Class array to calculate the distance to.
+ * @return the aggregate number of inheritance hops between assignable argument class types.
+ */
+ private static int distance(final Class>[] fromClassArray, final Class>[] toClassArray) {
+ int answer = 0;
+ if (!ClassUtils.isAssignable(fromClassArray, toClassArray, true)) {
+ return -1;
+ }
+ for (int offset = 0; offset < fromClassArray.length; offset++) {
+ // Note InheritanceUtils.distance() uses different scoring system.
+ final Class> aClass = fromClassArray[offset];
+ final Class> toClass = toClassArray[offset];
+ if (aClass == null || aClass.equals(toClass)) {
+ continue;
+ }
+ if (ClassUtils.isAssignable(aClass, toClass, true) && !ClassUtils.isAssignable(aClass, toClass, false)) {
+ answer++;
+ } else {
+ answer += 2;
+ }
+ }
+ return answer;
+ }
+
+ /**
+ * Gets an accessible method (that is, one that can be invoked via reflection) that implements the specified Method. If no such method can be found, return
+ * {@code null}.
+ *
+ * @param cls The implementing class, may be null.
+ * @param method The method that we wish to call, may be null.
+ * @return The accessible method or null.
+ * @since 3.19.0
+ */
+ public static Method getAccessibleMethod(final Class> cls, final Method method) {
+ if (!MemberUtils.isPublic(method)) {
+ return null;
+ }
+ // If the declaring class is public, we are done
+ if (ClassUtils.isPublic(cls)) {
+ return method;
+ }
+ final String methodName = method.getName();
+ final Class>[] parameterTypes = method.getParameterTypes();
+ // Check the implemented interfaces and subinterfaces
+ final Method method2 = getAccessibleMethodFromInterfaceNest(cls, methodName, parameterTypes);
+ // Check the superclass chain
+ return method2 != null ? method2 : getAccessibleMethodFromSuperclass(cls, methodName, parameterTypes);
+ }
+
+ /**
+ * Gets an accessible method (that is, one that can be invoked via reflection) with given name and parameters. If no such method can be found, return
+ * {@code null}. This is just a convenience wrapper for {@link #getAccessibleMethod(Method)}.
+ *
+ * @param cls get method from this class.
+ * @param methodName get method with this name.
+ * @param parameterTypes with these parameters types.
+ * @return The accessible method.
+ */
+ public static Method getAccessibleMethod(final Class> cls, final String methodName, final Class>... parameterTypes) {
+ return getAccessibleMethod(getMethodObject(cls, methodName, parameterTypes));
+ }
+
+ /**
+ * Gets an accessible method (that is, one that can be invoked via reflection) that implements the specified Method. If no such method can be found, return
+ * {@code null}.
+ *
+ * @param method The method that we wish to call, may be null.
+ * @return The accessible method
+ */
+ public static Method getAccessibleMethod(final Method method) {
+ return method != null ? getAccessibleMethod(method.getDeclaringClass(), method) : null;
+ }
+
/**
- *
Given an arguments array passed to a varargs method, return an array of arguments in the canonical form,
- * i.e. an array with the declared number of parameters, and whose last parameter is an array of the varargs type.
+ * Gets an accessible method (that is, one that can be invoked via
+ * reflection) that implements the specified method, by scanning through
+ * all implemented interfaces and subinterfaces. If no such method
+ * can be found, return {@code null}.
+ *
+ *
+ * There isn't any good reason why this method must be {@code private}.
+ * It is because there doesn't seem any reason why other classes should
+ * call this rather than the higher level methods.
*
*
+ * @param cls Parent class for the interfaces to be checked
+ * @param methodName Method name of the method we wish to call
+ * @param parameterTypes The parameter type signatures
+ * @return the accessible method or {@code null} if not found
+ */
+ private static Method getAccessibleMethodFromInterfaceNest(Class> cls, final String methodName, final Class>... parameterTypes) {
+ // Search up the superclass chain
+ for (; cls != null; cls = cls.getSuperclass()) {
+ // Check the implemented interfaces of the parent class
+ final Class>[] interfaces = cls.getInterfaces();
+ for (final Class> anInterface : interfaces) {
+ // Is this interface public?
+ if (!ClassUtils.isPublic(anInterface)) {
+ continue;
+ }
+ // Does the method exist on this interface?
+ try {
+ return anInterface.getDeclaredMethod(methodName, parameterTypes);
+ } catch (final NoSuchMethodException ignored) {
+ /*
+ * Swallow, if no method is found after the loop then this method returns null.
+ */
+ }
+ // Recursively check our parent interfaces
+ final Method method = getAccessibleMethodFromInterfaceNest(anInterface, methodName, parameterTypes);
+ if (method != null) {
+ return method;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets an accessible method (that is, one that can be invoked via
+ * reflection) by scanning through the superclasses. If no such method
+ * can be found, return {@code null}.
+ *
+ * @param cls Class to be checked.
+ * @param methodName Method name of the method we wish to call.
+ * @param parameterTypes The parameter type signatures.
+ * @return the accessible method or {@code null} if not found.
+ */
+ private static Method getAccessibleMethodFromSuperclass(final Class> cls, final String methodName, final Class>... parameterTypes) {
+ Class> parentClass = cls.getSuperclass();
+ while (parentClass != null) {
+ if (ClassUtils.isPublic(parentClass)) {
+ return getMethodObject(parentClass, methodName, parameterTypes);
+ }
+ parentClass = parentClass.getSuperclass();
+ }
+ return null;
+ }
+
+ /**
+ * Gets a combination of {@link ClassUtils#getAllSuperclasses(Class)} and
+ * {@link ClassUtils#getAllInterfaces(Class)}, one from superclasses, one
+ * from interfaces, and so on in a breadth first way.
+ *
+ * @param cls the class to look up, may be {@code null}
+ * @return the combined {@link List} of superclasses and interfaces in order
+ * going up from this one
+ * {@code null} if null input
+ */
+ private static List> getAllSuperclassesAndInterfaces(final Class> cls) {
+ if (cls == null) {
+ return null;
+ }
+ final List> allSuperClassesAndInterfaces = new ArrayList<>();
+ final List> allSuperclasses = ClassUtils.getAllSuperclasses(cls);
+ int superClassIndex = 0;
+ final List> allInterfaces = ClassUtils.getAllInterfaces(cls);
+ int interfaceIndex = 0;
+ while (interfaceIndex < allInterfaces.size() || superClassIndex < allSuperclasses.size()) {
+ final Class> acls;
+ if (interfaceIndex >= allInterfaces.size() || superClassIndex < allSuperclasses.size() && superClassIndex < interfaceIndex) {
+ acls = allSuperclasses.get(superClassIndex++);
+ } else {
+ acls = allInterfaces.get(interfaceIndex++);
+ }
+ allSuperClassesAndInterfaces.add(acls);
+ }
+ return allSuperClassesAndInterfaces;
+ }
+
+ /**
+ * Gets an accessible method that matches the given name and has compatible parameters. Compatible parameters mean that every method parameter is assignable
+ * from the given parameters. In other words, it finds a method with the given name that will take the parameters given.
+ *
+ *
+ * This method is used by {@link #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}.
+ *
+ *
+ * This method can match primitive parameter by passing in wrapper classes. For example, a {@link Boolean} will match a primitive {@code boolean} parameter.
+ *
+ *
+ * @param cls find method in this class.
+ * @param methodName find method with this name.
+ * @param parameterTypes find method with most compatible parameters.
+ * @return The accessible method or null.
+ * @throws SecurityException if an underlying accessible object's method denies the request.
+ * @see SecurityManager#checkPermission
+ */
+ public static Method getMatchingAccessibleMethod(final Class> cls, final String methodName, final Class>... parameterTypes) {
+ final Method candidate = getMethodObject(cls, methodName, parameterTypes);
+ if (candidate != null) {
+ return MemberUtils.setAccessibleWorkaround(candidate);
+ }
+ // search through all methods
+ final Method[] methods = cls.getMethods();
+ final List matchingMethods = Stream.of(methods)
+ .filter(method -> method.getName().equals(methodName) && MemberUtils.isMatchingMethod(method, parameterTypes)).collect(Collectors.toList());
+ // Sort methods by signature to force deterministic result
+ matchingMethods.sort(METHOD_BY_SIGNATURE);
+ Method bestMatch = null;
+ for (final Method method : matchingMethods) {
+ // get accessible version of method
+ final Method accessibleMethod = getAccessibleMethod(method);
+ if (accessibleMethod != null && (bestMatch == null || MemberUtils.compareMethodFit(accessibleMethod, bestMatch, parameterTypes) < 0)) {
+ bestMatch = accessibleMethod;
+ }
+ }
+ if (bestMatch != null) {
+ MemberUtils.setAccessibleWorkaround(bestMatch);
+ }
+ if (bestMatch != null && bestMatch.isVarArgs() && bestMatch.getParameterTypes().length > 0 && parameterTypes.length > 0) {
+ final Class>[] methodParameterTypes = bestMatch.getParameterTypes();
+ final Class> methodParameterComponentType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType();
+ final String methodParameterComponentTypeName = ClassUtils.primitiveToWrapper(methodParameterComponentType).getName();
+ final Class> lastParameterType = parameterTypes[parameterTypes.length - 1];
+ final String parameterTypeName = lastParameterType == null ? null : lastParameterType.getName();
+ final String parameterTypeSuperClassName = lastParameterType == null ? null
+ : lastParameterType.getSuperclass() != null ? lastParameterType.getSuperclass().getName() : null;
+ if (parameterTypeName != null && parameterTypeSuperClassName != null && !methodParameterComponentTypeName.equals(parameterTypeName)
+ && !methodParameterComponentTypeName.equals(parameterTypeSuperClassName)) {
+ return null;
+ }
+ }
+ return bestMatch;
+ }
+
+ /**
+ * Gets a Method, or {@code null} if a documented {@link Class#getMethod(String, Class...) } exception is thrown.
+ *
+ * @param cls Receiver for {@link Class#getMethod(String, Class...)}.
+ * @param name the name of the method.
+ * @param parameterTypes the list of parameters.
+ * @return a Method or {@code null}.
+ * @see SecurityManager#checkPermission
+ * @see Class#getMethod(String, Class...)
+ * @since 3.15.0
+ */
+ public static Method getMethodObject(final Class> cls, final String name, final Class>... parameterTypes) {
+ try {
+ return name != null && cls != null ? cls.getMethod(name, parameterTypes) : null;
+ } catch (final NoSuchMethodException | SecurityException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets all class level public methods of the given class that are annotated with the given annotation.
+ * @param cls
+ * the {@link Class} to query
+ * @param annotationCls
+ * the {@link Annotation} that must be present on a method to be matched
+ * @return a list of Methods (possibly empty).
+ * @throws NullPointerException
+ * if the class or annotation are {@code null}
+ * @since 3.4
+ */
+ public static List getMethodsListWithAnnotation(final Class> cls, final Class extends Annotation> annotationCls) {
+ return getMethodsListWithAnnotation(cls, annotationCls, false, false);
+ }
+
+ /**
+ * Gets all methods of the given class that are annotated with the given annotation.
+ *
+ * @param cls
+ * the {@link Class} to query
+ * @param annotationCls
+ * the {@link Annotation} that must be present on a method to be matched
+ * @param searchSupers
+ * determines if a lookup in the entire inheritance hierarchy of the given class should be performed
+ * @param ignoreAccess
+ * determines if non-public methods should be considered
+ * @return a list of Methods (possibly empty).
+ * @throws NullPointerException if either the class or annotation class is {@code null}
+ * @since 3.6
+ */
+ public static List getMethodsListWithAnnotation(final Class> cls, final Class extends Annotation> annotationCls, final boolean searchSupers,
+ final boolean ignoreAccess) {
+ Objects.requireNonNull(cls, "cls");
+ Objects.requireNonNull(annotationCls, "annotationCls");
+ final List> classes = searchSupers ? getAllSuperclassesAndInterfaces(cls) : new ArrayList<>();
+ classes.add(0, cls);
+ final List annotatedMethods = new ArrayList<>();
+ classes.forEach(acls -> {
+ final Method[] methods = ignoreAccess ? acls.getDeclaredMethods() : acls.getMethods();
+ Stream.of(methods).filter(method -> method.isAnnotationPresent(annotationCls)).forEachOrdered(annotatedMethods::add);
+ });
+ return annotatedMethods;
+ }
+
+ /**
+ * Gets all class level public methods of the given class that are annotated with the given annotation.
+ *
+ * @param cls
+ * the {@link Class} to query
+ * @param annotationCls
+ * the {@link java.lang.annotation.Annotation} that must be present on a method to be matched
+ * @return an array of Methods (possibly empty).
+ * @throws NullPointerException if the class or annotation are {@code null}
+ * @since 3.4
+ */
+ public static Method[] getMethodsWithAnnotation(final Class> cls, final Class extends Annotation> annotationCls) {
+ return getMethodsWithAnnotation(cls, annotationCls, false, false);
+ }
+
+ /**
+ * Gets all methods of the given class that are annotated with the given annotation.
+ *
+ * @param cls
+ * the {@link Class} to query
+ * @param annotationCls
+ * the {@link java.lang.annotation.Annotation} that must be present on a method to be matched
+ * @param searchSupers
+ * determines if a lookup in the entire inheritance hierarchy of the given class should be performed
+ * @param ignoreAccess
+ * determines if non-public methods should be considered
+ * @return an array of Methods (possibly empty).
+ * @throws NullPointerException if the class or annotation are {@code null}
+ * @since 3.6
+ */
+ public static Method[] getMethodsWithAnnotation(final Class> cls, final Class extends Annotation> annotationCls, final boolean searchSupers,
+ final boolean ignoreAccess) {
+ return getMethodsListWithAnnotation(cls, annotationCls, searchSupers, ignoreAccess).toArray(ArrayUtils.EMPTY_METHOD_ARRAY);
+ }
+
+ /**
+ * Gets an array of arguments in the canonical form, given an arguments array passed to a varargs method,
+ * for example an array with the declared number of parameters, and whose last parameter is an array of the varargs type.
+ *
* @param args the array of arguments passed to the varags method
* @param methodParameterTypes the declared array of method parameter types
* @return an array of the variadic arguments passed to the method
* @since 3.5
*/
static Object[] getVarArgs(final Object[] args, final Class>[] methodParameterTypes) {
- if (args.length == methodParameterTypes.length
- && args[args.length - 1].getClass().equals(methodParameterTypes[methodParameterTypes.length - 1])) {
- // The args array is already in the canonical form for the method.
- return args;
+ final int mptLength = methodParameterTypes.length;
+ if (args.length == mptLength) {
+ final Object lastArg = args[args.length - 1];
+ if (lastArg == null || lastArg.getClass().equals(methodParameterTypes[mptLength - 1])) {
+ // The args array is already in the canonical form for the method.
+ return args;
+ }
}
-
// Construct a new array matching the method's declared parameter types.
- final Object[] newArgs = new Object[methodParameterTypes.length];
-
// Copy the normal (non-varargs) parameters
- System.arraycopy(args, 0, newArgs, 0, methodParameterTypes.length - 1);
-
+ final Object[] newArgs = ArrayUtils.arraycopy(args, 0, 0, mptLength - 1, () -> new Object[mptLength]);
// Construct a new array for the variadic parameters
- final Class> varArgComponentType = methodParameterTypes[methodParameterTypes.length - 1].getComponentType();
- final int varArgLength = args.length - methodParameterTypes.length + 1;
-
- Object varArgsArray = Array.newInstance(ClassUtils.primitiveToWrapper(varArgComponentType), varArgLength);
+ final Class> varArgComponentType = methodParameterTypes[mptLength - 1].getComponentType();
+ final int varArgLength = args.length - mptLength + 1;
// Copy the variadic arguments into the varargs array.
- System.arraycopy(args, methodParameterTypes.length - 1, varArgsArray, 0, varArgLength);
-
- if(varArgComponentType.isPrimitive()) {
+ Object varArgsArray = ArrayUtils.arraycopy(args, mptLength - 1, 0, varArgLength,
+ s -> Array.newInstance(ClassUtils.primitiveToWrapper(varArgComponentType), varArgLength));
+ if (varArgComponentType.isPrimitive()) {
// unbox from wrapper type to primitive type
varArgsArray = ArrayUtils.toPrimitive(varArgsArray);
}
-
// Store the varargs array in the last position of the array to return
- newArgs[methodParameterTypes.length - 1] = varArgsArray;
-
+ newArgs[mptLength - 1] = varArgsArray;
// Return the canonical varargs array.
return newArgs;
}
-}
+ /**
+ * Invokes a method whose parameter types match exactly the object type.
+ *
+ *
+ * This uses reflection to invoke the method obtained from a call to {@link #getAccessibleMethod(Class, String, Class[])}.
+ *
+ *
+ * @param object invoke method on this object.
+ * @param methodName get method with this name.
+ * @return The value returned by the invoked method.
+ * @throws NoSuchMethodException Thrown if there is no such accessible method.
+ * @throws IllegalAccessException Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+ * inaccessible.
+ * @throws IllegalArgumentException Thrown if:
+ *
+ *
the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+ * the class or interface declaring the underlying method (or of a subclass or interface implementor);
+ *
the number of actual and formal parameters differ;
+ *
+ * @throws InvocationTargetException Thrown if the underlying method throws an exception.
+ * @throws NullPointerException Thrown if the specified {@code object} is null.
+ * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+ * @since 3.4
+ */
+ public static Object invokeExactMethod(final Object object, final String methodName)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ return invokeExactMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null);
+ }
+
+ /**
+ * Invokes a method whose parameter types match exactly the object types.
+ *
+ *
+ * This uses reflection to invoke the method obtained from a call to {@link #getAccessibleMethod(Class, String, Class[])}.
+ *
+ *
+ * @param object invoke method on this object.
+ * @param methodName get method with this name.
+ * @param args use these arguments - treat null as empty array.
+ * @return The value returned by the invoked method.
+ * @throws NoSuchMethodException Thrown if there is no such accessible method.
+ * @throws IllegalAccessException Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+ * inaccessible.
+ * @throws IllegalArgumentException Thrown if:
+ *
+ *
the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+ * the class or interface declaring the underlying method (or of a subclass or interface implementor);
+ *
the number of actual and formal parameters differ;
+ *
an unwrapping conversion for primitive arguments fails; or
+ *
after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+ * method invocation conversion.
+ *
+ * @throws InvocationTargetException Thrown if the underlying method throws an exception.
+ * @throws NullPointerException Thrown if the specified {@code object} is null.
+ * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+ */
+ public static Object invokeExactMethod(final Object object, final String methodName, final Object... args)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ final Object[] actuals = ArrayUtils.nullToEmpty(args);
+ return invokeExactMethod(object, methodName, actuals, ClassUtils.toClass(actuals));
+ }
+
+ /**
+ * Invokes a method whose parameter types match exactly the parameter types given.
+ *
+ *
+ * This uses reflection to invoke the method obtained from a call to {@link #getAccessibleMethod(Class, String, Class[])}.
+ *
+ *
+ * @param object Invokes a method on this object.
+ * @param methodName Gets a method with this name.
+ * @param args Method arguments - treat null as empty array.
+ * @param parameterTypes Match these parameters - treat {@code null} as empty array.
+ * @return The value returned by the invoked method.
+ * @throws NoSuchMethodException Thrown if there is no such accessible method.
+ * @throws IllegalAccessException Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+ * inaccessible.
+ * @throws IllegalArgumentException Thrown if:
+ *
+ *
the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+ * the class or interface declaring the underlying method (or of a subclass or interface implementor);
+ *
the number of actual and formal parameters differ;
+ *
an unwrapping conversion for primitive arguments fails; or
+ *
after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+ * method invocation conversion.
+ *
+ * @throws InvocationTargetException Thrown if the underlying method throws an exception.
+ * @throws NullPointerException Thrown if the specified {@code object} is null.
+ * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+ */
+ public static Object invokeExactMethod(final Object object, final String methodName, final Object[] args, final Class>[] parameterTypes)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ final Class> cls = Objects.requireNonNull(object, "object").getClass();
+ final Method method = getAccessibleMethod(cls, methodName, ArrayUtils.nullToEmpty(parameterTypes));
+ if (method == null) {
+ throw new NoSuchMethodException("No such accessible method: " + methodName + "() on object: " + cls.getName());
+ }
+ return method.invoke(object, ArrayUtils.nullToEmpty(args));
+ }
+
+ /**
+ * Invokes a {@code static} method whose parameter types match exactly the object types.
+ *
+ *
+ * This uses reflection to invoke the method obtained from a call to {@link #getAccessibleMethod(Class, String, Class[])}.
+ *
+ *
+ * @param cls invoke static method on this class
+ * @param methodName get method with this name
+ * @param args use these arguments - treat {@code null} as empty array
+ * @return The value returned by the invoked method
+ * @throws NoSuchMethodException Thrown if there is no such accessible method.
+ * @throws IllegalAccessException Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+ * inaccessible.
+ * @throws IllegalArgumentException Thrown if:
+ *
+ *
the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+ * the class or interface declaring the underlying method (or of a subclass or interface implementor);
+ *
the number of actual and formal parameters differ;
+ *
an unwrapping conversion for primitive arguments fails; or
+ *
after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+ * method invocation conversion.
+ *
+ * @throws InvocationTargetException Thrown if the underlying method throws an exception.
+ * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+ */
+ public static Object invokeExactStaticMethod(final Class> cls, final String methodName, final Object... args)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ final Object[] actuals = ArrayUtils.nullToEmpty(args);
+ return invokeExactStaticMethod(cls, methodName, actuals, ClassUtils.toClass(actuals));
+ }
+
+ /**
+ * Invokes a {@code static} method whose parameter types match exactly the parameter types given.
+ *
+ *
+ * This uses reflection to invoke the method obtained from a call to {@link #getAccessibleMethod(Class, String, Class[])}.
+ *
+ *
+ * @param cls invoke static method on this class
+ * @param methodName get method with this name
+ * @param args use these arguments - treat {@code null} as empty array
+ * @param parameterTypes match these parameters - treat {@code null} as empty array
+ * @return The value returned by the invoked method
+ * @throws NoSuchMethodException Thrown if there is no such accessible method.
+ * @throws IllegalAccessException Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+ * inaccessible.
+ * @throws IllegalArgumentException Thrown if:
+ *
+ *
the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+ * the class or interface declaring the underlying method (or of a subclass or interface implementor);
+ *
the number of actual and formal parameters differ;
+ *
an unwrapping conversion for primitive arguments fails; or
+ *
after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+ * method invocation conversion.
+ *
+ * @throws InvocationTargetException Thrown if the underlying method throws an exception.
+ * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+ */
+ public static Object invokeExactStaticMethod(final Class> cls, final String methodName, final Object[] args, final Class>[] parameterTypes)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ final Method method = getAccessibleMethod(cls, methodName, ArrayUtils.nullToEmpty(parameterTypes));
+ if (method == null) {
+ throw new NoSuchMethodException("No such accessible method: " + methodName + "() on class: " + cls.getName());
+ }
+ return method.invoke(null, ArrayUtils.nullToEmpty(args));
+ }
+
+ /**
+ * Invokes a named method without parameters.
+ *
+ *
+ * This is a convenient wrapper for
+ * {@link #invokeMethod(Object object, boolean forceAccess, String methodName, Object[] args, Class[] parameterTypes)}.
+ *
+ *
+ * @param object invoke method on this object
+ * @param forceAccess force access to invoke method even if it's not accessible
+ * @param methodName get method with this name
+ * @return The value returned by the invoked method
+ * @throws NoSuchMethodException Thrown if there is no such accessible method.
+ * @throws IllegalAccessException Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+ * inaccessible.
+ * @throws IllegalArgumentException Thrown if:
+ *
+ *
the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+ * the class or interface declaring the underlying method (or of a subclass or interface implementor);
+ *
the number of actual and formal parameters differ;
+ *
an unwrapping conversion for primitive arguments fails; or
+ *
after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+ * method invocation conversion.
+ *
+ * @throws InvocationTargetException Thrown if the underlying method throws an exception.
+ * @throws NullPointerException Thrown if the specified {@code object} is null.
+ * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+ * @see SecurityManager#checkPermission
+ * @since 3.5
+ */
+ public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ return invokeMethod(object, forceAccess, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null);
+ }
+
+ /**
+ * Invokes a named method whose parameter type matches the object type.
+ *
+ *
+ * This method supports calls to methods taking primitive parameters
+ * via passing in wrapping classes. So, for example, a {@link Boolean} object
+ * would match a {@code boolean} primitive.
+ *
+ *
+ * This is a convenient wrapper for
+ * {@link #invokeMethod(Object object, boolean forceAccess, String methodName, Object[] args, Class[] parameterTypes)}.
+ *
+ *
+ * @param object invoke method on this object
+ * @param forceAccess force access to invoke method even if it's not accessible
+ * @param methodName get method with this name
+ * @param args use these arguments - treat null as empty array
+ * @return The value returned by the invoked method
+ * @throws NoSuchMethodException Thrown if there is no such accessible method.
+ * @throws IllegalAccessException Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+ * inaccessible.
+ * @throws IllegalArgumentException Thrown if:
+ *
+ *
the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+ * the class or interface declaring the underlying method (or of a subclass or interface implementor);
+ *
the number of actual and formal parameters differ;
+ *
an unwrapping conversion for primitive arguments fails; or
+ *
after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+ * method invocation conversion.
+ *
+ * @throws InvocationTargetException Thrown if the underlying method throws an exception.
+ * @throws NullPointerException Thrown if the specified {@code object} is null.
+ * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+ * @see SecurityManager#checkPermission
+ * @since 3.5
+ */
+ public static Object invokeMethod(final Object object, final boolean forceAccess, final String methodName, final Object... args)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ final Object[] actuals = ArrayUtils.nullToEmpty(args);
+ return invokeMethod(object, forceAccess, methodName, actuals, ClassUtils.toClass(actuals));
+ }
+
+ /**
+ * Invokes a named method without parameters.
+ *
+ *
+ * This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.
+ *
+ *
+ * This is a convenient wrapper for
+ * {@link #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}.
+ *
+ *
+ * @param object invoke method on this object
+ * @param methodName get method with this name
+ * @return The value returned by the invoked method
+ * @throws NoSuchMethodException if there is no such accessible method
+ * @throws InvocationTargetException wraps an exception thrown by the method invoked
+ * @throws IllegalAccessException if the requested method is not accessible via reflection
+ * @throws SecurityException if an underlying accessible object's method denies the request.
+ * @see SecurityManager#checkPermission
+ * @since 3.4
+ */
+ public static Object invokeMethod(final Object object, final String methodName) throws NoSuchMethodException,
+ IllegalAccessException, InvocationTargetException {
+ return invokeMethod(object, methodName, ArrayUtils.EMPTY_OBJECT_ARRAY, null);
+ }
+
+ /**
+ * Invokes a named method whose parameter type matches the object type.
+ *
+ *
+ * This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.
+ *
+ *
+ * This method supports calls to methods taking primitive parameters
+ * via passing in wrapping classes. So, for example, a {@link Boolean} object
+ * would match a {@code boolean} primitive.
+ *
+ *
+ * This is a convenient wrapper for
+ * {@link #invokeMethod(Object object, String methodName, Object[] args, Class[] parameterTypes)}.
+ *
+ *
+ * @param object invoke method on this object
+ * @param methodName get method with this name
+ * @param args use these arguments - treat null as empty array
+ * @return The value returned by the invoked method
+ * @throws NoSuchMethodException if there is no such accessible method
+ * @throws InvocationTargetException wraps an exception thrown by the method invoked
+ * @throws IllegalAccessException if the requested method is not accessible via reflection
+ * @throws NullPointerException if the object or method name are {@code null}
+ * @throws SecurityException if an underlying accessible object's method denies the request.
+ * @see SecurityManager#checkPermission
+ */
+ public static Object invokeMethod(final Object object, final String methodName, final Object... args)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ final Object[] actuals = ArrayUtils.nullToEmpty(args);
+ return invokeMethod(object, methodName, actuals, ClassUtils.toClass(actuals));
+ }
+
+ /**
+ * Invokes a named method whose parameter type matches the object type.
+ *
+ *
+ * This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.
+ *
+ *
+ * This method supports calls to methods taking primitive parameters
+ * via passing in wrapping classes. So, for example, a {@link Boolean} object
+ * would match a {@code boolean} primitive.
+ *
+ *
+ * @param object invoke method on this object
+ * @param methodName get method with this name
+ * @param args use these arguments - treat null as empty array
+ * @param parameterTypes match these parameters - treat null as empty array
+ * @return The value returned by the invoked method
+ * @throws NoSuchMethodException Thrown if there is no such accessible method.
+ * @throws IllegalAccessException Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+ * inaccessible.
+ * @throws IllegalArgumentException Thrown if:
+ *
+ *
the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+ * the class or interface declaring the underlying method (or of a subclass or interface implementor);
+ *
the number of actual and formal parameters differ;
+ *
an unwrapping conversion for primitive arguments fails; or
+ *
after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+ * method invocation conversion.
+ *
+ * @throws InvocationTargetException Thrown if the underlying method throws an exception.
+ * @throws NullPointerException Thrown if the specified {@code object} is null.
+ * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+ * @see SecurityManager#checkPermission
+ */
+ public static Object invokeMethod(final Object object, final String methodName, final Object[] args, final Class>[] parameterTypes)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ return invokeMethod(object, false, methodName, args, parameterTypes);
+ }
+
+ /**
+ * Invokes a named {@code static} method whose parameter type matches the object type.
+ *
+ *
+ * This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.
+ *
+ *
+ * This method supports calls to methods taking primitive parameters
+ * via passing in wrapping classes. So, for example, a {@link Boolean} class
+ * would match a {@code boolean} primitive.
+ *
+ *
+ * This is a convenient wrapper for
+ * {@link #invokeStaticMethod(Class, String, Object[], Class[])}.
+ *
+ *
+ * @param cls invoke static method on this class
+ * @param methodName get method with this name
+ * @param args use these arguments - treat {@code null} as empty array
+ * @return The value returned by the invoked method
+ * @throws NoSuchMethodException Thrown if there is no such accessible method.
+ * @throws IllegalAccessException Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+ * inaccessible.
+ * @throws IllegalArgumentException Thrown if:
+ *
+ *
the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+ * the class or interface declaring the underlying method (or of a subclass or interface implementor);
+ *
the number of actual and formal parameters differ;
+ *
an unwrapping conversion for primitive arguments fails; or
+ *
after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+ * method invocation conversion.
+ *
+ * @throws InvocationTargetException Thrown if the underlying method throws an exception.
+ * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+ * @see SecurityManager#checkPermission
+ */
+ public static Object invokeStaticMethod(final Class> cls, final String methodName, final Object... args)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ final Object[] actuals = ArrayUtils.nullToEmpty(args);
+ return invokeStaticMethod(cls, methodName, actuals, ClassUtils.toClass(actuals));
+ }
+
+ /**
+ * Invokes a named {@code static} method whose parameter type matches the object type.
+ *
+ *
+ * This method delegates the method search to {@link #getMatchingAccessibleMethod(Class, String, Class[])}.
+ *
+ *
+ * This method supports calls to methods taking primitive parameters
+ * via passing in wrapping classes. So, for example, a {@link Boolean} class
+ * would match a {@code boolean} primitive.
+ *
+ *
+ * @param cls invoke static method on this class
+ * @param methodName get method with this name
+ * @param args use these arguments - treat {@code null} as empty array
+ * @param parameterTypes match these parameters - treat {@code null} as empty array
+ * @return The value returned by the invoked method
+ * @throws NoSuchMethodException Thrown if there is no such accessible method.
+ * @throws IllegalAccessException Thrown if this found {@code Method} is enforcing Java language access control and the underlying method is
+ * inaccessible.
+ * @throws IllegalArgumentException Thrown if:
+ *
+ *
the found {@code Method} is an instance method and the specified {@code object} argument is not an instance of
+ * the class or interface declaring the underlying method (or of a subclass or interface implementor);
+ *
the number of actual and formal parameters differ;
+ *
an unwrapping conversion for primitive arguments fails; or
+ *
after possible unwrapping, a parameter value can't be converted to the corresponding formal parameter type by a
+ * method invocation conversion.
+ *
+ * @throws InvocationTargetException Thrown if the underlying method throws an exception.
+ * @throws ExceptionInInitializerError Thrown if the initialization provoked by this method fails.
+ * @see SecurityManager#checkPermission
+ */
+ public static Object invokeStaticMethod(final Class> cls, final String methodName, final Object[] args, final Class>[] parameterTypes)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ final Method method = getMatchingAccessibleMethod(cls, methodName, ArrayUtils.nullToEmpty(parameterTypes));
+ if (method == null) {
+ throw new NoSuchMethodException("No such accessible method: " + methodName + "() on class: " + cls.getName());
+ }
+ return method.invoke(null, toVarArgs(method, ArrayUtils.nullToEmpty(args)));
+ }
+
+ private static Object[] toVarArgs(final Method method, final Object[] args) {
+ return method.isVarArgs() ? getVarArgs(args, method.getParameterTypes()) : args;
+ }
+}
\ No newline at end of file
diff --git a/ehcache-impl/src/main/java/org/ehcache/impl/serialization/PlainJavaSerializer.java b/ehcache-impl/src/main/java/org/ehcache/impl/serialization/PlainJavaSerializer.java
index 54d60a9e3a..c5ebfdeaa7 100644
--- a/ehcache-impl/src/main/java/org/ehcache/impl/serialization/PlainJavaSerializer.java
+++ b/ehcache-impl/src/main/java/org/ehcache/impl/serialization/PlainJavaSerializer.java
@@ -101,12 +101,14 @@ protected Class> resolveClass(ObjectStreamClass desc) throws ClassNotFoundExce
}
@Override
+ @SuppressWarnings("deprecation")
protected Class> resolveProxyClass(String[] interfaces) throws ClassNotFoundException {
Class>[] interfaceClasses = new Class>[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
interfaceClasses[i] = Class.forName(interfaces[i], false, classLoader);
}
+ // WARNING: Proxy classes generated in a named module with deprecated getProxyClass() are encapsulated and not accessible to code outside its module. Constructor.newInstance will throw IllegalAccessException when it is called on an inaccessible proxy class.
return Proxy.getProxyClass(classLoader, interfaceClasses);
}
diff --git a/ehcache-impl/src/main/resources/META-INF/services/org.ehcache.core.spi.service.ServiceFactory b/ehcache-impl/src/main/resources/META-INF/services/org.ehcache.core.spi.service.ServiceFactory
index 82e5621139..4c47439759 100644
--- a/ehcache-impl/src/main/resources/META-INF/services/org.ehcache.core.spi.service.ServiceFactory
+++ b/ehcache-impl/src/main/resources/META-INF/services/org.ehcache.core.spi.service.ServiceFactory
@@ -11,7 +11,6 @@ org.ehcache.impl.internal.store.shared.authoritative.SharedAuthoritativeTierProv
org.ehcache.impl.internal.store.shared.caching.SharedCachingTierProviderFactory
org.ehcache.impl.internal.store.shared.caching.lower.SharedLowerCachingTierProviderFactory
org.ehcache.impl.internal.store.shared.caching.higher.SharedHigherCachingTierProviderFactory
-
org.ehcache.impl.internal.TimeSourceServiceFactory
org.ehcache.impl.internal.spi.serialization.DefaultSerializationProviderFactory
org.ehcache.impl.internal.spi.loaderwriter.DefaultCacheLoaderWriterProviderFactory
diff --git a/ehcache-impl/src/test/java/org/ehcache/config/builders/CacheConfigurationBuilderTest.java b/ehcache-impl/src/test/java/org/ehcache/config/builders/CacheConfigurationBuilderTest.java
index 3402a4a863..607d997e06 100644
--- a/ehcache-impl/src/test/java/org/ehcache/config/builders/CacheConfigurationBuilderTest.java
+++ b/ehcache-impl/src/test/java/org/ehcache/config/builders/CacheConfigurationBuilderTest.java
@@ -391,8 +391,10 @@ public void testIncompatibleServiceRemovesExistingConfiguration() {
CacheConfigurationBuilder newBuilder = oldBuilder.withService(newConfig);
- assertThat(oldBuilder.build().getServiceConfigurations(), both(hasItem(sameInstance(oldConfig))).and(not(hasItem(sameInstance(newConfig)))));
- assertThat(newBuilder.build().getServiceConfigurations(), both(hasItem(sameInstance(newConfig))).and(not(hasItem(sameInstance(oldConfig)))));
+ assertThat(oldBuilder.build().getServiceConfigurations(), hasItem(sameInstance(oldConfig)));
+ assertThat(oldBuilder.build().getServiceConfigurations(), not(hasItem(sameInstance(newConfig))));
+ assertThat(newBuilder.build().getServiceConfigurations(), hasItem(sameInstance(newConfig)));
+ assertThat(newBuilder.build().getServiceConfigurations(), not(hasItem(sameInstance(oldConfig))));
}
@Test
@@ -400,12 +402,14 @@ public void testCompatibleServiceJoinsExistingConfiguration() {
ServiceConfiguration, ?> oldConfig = new CompatibleServiceConfig();
ServiceConfiguration, ?> newConfig = new CompatibleServiceConfig();
- CacheConfigurationBuilder oldBuilder = newCacheConfigurationBuilder(Object.class, Object.class, heap(10)).withService(oldConfig);
+ CacheConfigurationBuilder, ?> oldBuilder = newCacheConfigurationBuilder(Object.class, Object.class, heap(10)).withService(oldConfig);
- CacheConfigurationBuilder newBuilder = oldBuilder.withService(newConfig);
+ CacheConfigurationBuilder, ?> newBuilder = oldBuilder.withService(newConfig);
- assertThat(oldBuilder.build().getServiceConfigurations(), both(hasItem(sameInstance(oldConfig))).and(not(hasItem(sameInstance(newConfig)))));
- assertThat(newBuilder.build().getServiceConfigurations(), both(hasItem(sameInstance(oldConfig))).and(hasItem(sameInstance(newConfig))));
+ assertThat(oldBuilder.build().getServiceConfigurations(), hasItem(sameInstance(oldConfig)));
+ assertThat(oldBuilder.build().getServiceConfigurations(), not(hasItem(sameInstance(newConfig))));
+ assertThat(newBuilder.build().getServiceConfigurations(), hasItem(sameInstance(oldConfig)));
+ assertThat(newBuilder.build().getServiceConfigurations(), hasItem(sameInstance(newConfig)));
}
@Test
diff --git a/ehcache-impl/src/test/java/org/ehcache/docs/ConfigurationDerivation.java b/ehcache-impl/src/test/java/org/ehcache/docs/ConfigurationDerivation.java
index 6b38682668..bcfaaff5d7 100644
--- a/ehcache-impl/src/test/java/org/ehcache/docs/ConfigurationDerivation.java
+++ b/ehcache-impl/src/test/java/org/ehcache/docs/ConfigurationDerivation.java
@@ -207,7 +207,7 @@ public OptimizedDateSerializer(ClassLoader classLoader) {}
@Override
public ByteBuffer serialize(Date object) throws SerializerException {
ByteBuffer buffer = ByteBuffer.allocate(8);
- return (ByteBuffer) buffer.putLong(object.getTime()).flip();
+ return buffer.putLong(object.getTime()).flip();
}
@Override
diff --git a/ehcache-impl/src/test/java/org/ehcache/impl/internal/store/offheap/AssertingOffHeapValueHolder.java b/ehcache-impl/src/test/java/org/ehcache/impl/internal/store/offheap/AssertingOffHeapValueHolder.java
index ba74892607..8ebc1f03ee 100644
--- a/ehcache-impl/src/test/java/org/ehcache/impl/internal/store/offheap/AssertingOffHeapValueHolder.java
+++ b/ehcache-impl/src/test/java/org/ehcache/impl/internal/store/offheap/AssertingOffHeapValueHolder.java
@@ -41,7 +41,7 @@
import static java.util.Arrays.stream;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
-import static org.objectweb.asm.Opcodes.ASM6;
+import static org.objectweb.asm.Opcodes.ASM7;
import static org.objectweb.asm.Type.getObjectType;
import static org.objectweb.asm.Type.getType;
import static org.objectweb.asm.commons.Method.getMethod;
@@ -136,11 +136,11 @@ private static boolean isLockedInFrame(StackTraceElement ste) {
NavigableMap lockLevels = new TreeMap<>();
- reader.accept(new ClassVisitor(ASM6) {
+ reader.accept(new ClassVisitor(ASM7) {
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
if (ste.getMethodName().equals(name)) {
- return new InstructionAdapter(ASM6, new MethodVisitor(ASM6) {}) {
+ return new InstructionAdapter(ASM7, new MethodVisitor(ASM7) {}) {
private final Map