ArrayUtils.java
/*
* Copyright 2017-2020 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.core.util;
import io.micronaut.core.annotation.Nullable;
import io.micronaut.core.annotation.UsedByGeneratedCode;
import io.micronaut.core.reflect.ReflectionUtils;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.function.IntFunction;
/**
* Utility methods for working with arrays.
*
* @author Graeme Rocher
* @since 1.0
*/
public final class ArrayUtils {
/**
* An empty object array.
*/
@UsedByGeneratedCode
public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
/**
* An empty boolean array.
*/
public static final boolean[] EMPTY_BOOLEAN_ARRAY = new boolean[0];
/**
* An empty byte array.
*/
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
/**
* An empty char array.
*/
public static final char[] EMPTY_CHAR_ARRAY = new char[0];
/**
* An empty int array.
*/
public static final int[] EMPTY_INT_ARRAY = new int[0];
/**
* An empty double array.
*/
public static final double[] EMPTY_DOUBLE_ARRAY = new double[0];
/**
* An empty long array.
*/
public static final long[] EMPTY_LONG_ARRAY = new long[0];
/**
* An empty float array.
*/
public static final float[] EMPTY_FLOAT_ARRAY = new float[0];
/**
* An empty short array.
*/
public static final short[] EMPTY_SHORT_ARRAY = new short[0];
private ArrayUtils() {
}
/**
* Concatenate two arrays.
*
* @param a The first array
* @param b The second array
* @param <T> The array type
* @return The concatenated array
*/
public static <T> T[] concat(T[] a, T... b) {
int bLen = b.length;
if (bLen == 0) {
return a;
}
int aLen = a.length;
if (aLen == 0) {
return b;
}
@SuppressWarnings("unchecked")
T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen + bLen);
System.arraycopy(a, 0, c, 0, aLen);
System.arraycopy(b, 0, c, aLen, bLen);
return c;
}
/**
* Concatenate two byte arrays.
*
* @param a The first array
* @param b The second array
* @return The concatenated array
*/
public static byte[] concat(byte[] a, byte... b) {
int bLen = b.length;
if (bLen == 0) {
return a;
}
int aLen = a.length;
if (aLen == 0) {
return b;
}
byte[] c = new byte[aLen + bLen];
System.arraycopy(a, 0, c, 0, aLen);
System.arraycopy(b, 0, c, aLen, bLen);
return c;
}
/**
* Whether the given array is empty.
*
* @param array The array
* @return True if it is
*/
public static boolean isEmpty(Object[] array) {
return array == null || array.length == 0;
}
/**
* Whether the given array is not empty.
*
* @param array The array
* @return True if it is
*/
public static boolean isNotEmpty(Object[] array) {
return !isEmpty(array);
}
/**
* Produce a string representation of the given array.
*
* @param array The array
* @return The string representation
*/
public static String toString(@Nullable Object[] array) {
String delimiter = ",";
return toString(delimiter, array);
}
/**
* Produce a string representation of the given array.
*
* @param delimiter The delimiter
* @param array The array
* @return The string representation
*/
public static String toString(String delimiter, @Nullable Object[] array) {
if (isEmpty(array)) {
return "";
}
List<Object> list = Arrays.asList(array);
return CollectionUtils.toString(delimiter, list);
}
/**
* Produce an iterator for the given array.
* @param array The array
* @param <T> The array type
* @return The iterator
*/
public static <T> Iterator<T> iterator(T... array) {
if (isNotEmpty(array)) {
return new ArrayIterator<>(array);
} else {
return Collections.emptyIterator();
}
}
/**
* Produce an iterator for the given array.
* @param array The array
* @param <T> The array type
* @return The iterator
*/
public static <T> Iterator<T> reverseIterator(T... array) {
if (isNotEmpty(array)) {
return new ReverseArrayIterator<>(array);
} else {
return Collections.emptyIterator();
}
}
/**
* Returns an array containing all elements in this collection, using the provided generator function to allocate the returned array.
*
* @param collection The collection
* @param createArrayFn The function to create the array
* @param <T> The type of the array
* @return The array
*/
public static <T> T[] toArray(Collection<T> collection, IntFunction<T[]> createArrayFn) {
T[] array = createArrayFn.apply(collection.size());
return collection.toArray(array);
}
/**
* Returns an array containing all elements in this collection, using the item class.
*
* @param collection The collection
* @param arrayItemClass The array item class
* @param <T> The type of the array
* @return The array
* @since 3.0
*/
public static <T> T[] toArray(Collection<T> collection, Class<T> arrayItemClass) {
return (T[]) collection.toArray((Object[]) Array.newInstance(arrayItemClass, collection.size()));
}
/**
* Converts a primitive array to the equivalent wrapper such as int[] to Integer[].
* @param primitiveArray The primitive array
* @return The primitive array wrapper.
* @since 3.0.0
*/
public static Object[] toWrapperArray(final Object primitiveArray) {
Objects.requireNonNull(primitiveArray, "Primitive array cannot be null");
final Class<?> cls = primitiveArray.getClass();
Class<?> componentType = cls.getComponentType();
if (!cls.isArray() || !componentType.isPrimitive()) {
throw new IllegalArgumentException(
"Only primitive arrays are supported");
}
final int length = Array.getLength(primitiveArray);
Object[] arr = (Object[]) Array.newInstance(ReflectionUtils.getWrapperType(componentType), length);
for (int i = 0; i < length; i++) {
arr[i] = Array.get(primitiveArray, i);
}
return arr;
}
/**
* Converts a primitive wrapper array to the equivalent primitive array such as Integer[] to int[].
* @param wrapperArray The wrapper array
* @return The primitive array.
* @since 3.0.0
*/
public static Object toPrimitiveArray(final Object[] wrapperArray) {
Objects.requireNonNull(wrapperArray, "Wrapper array cannot be null");
final Class<?> cls = wrapperArray.getClass();
Class<?> ct = cls.getComponentType();
Class<?> componentType = ReflectionUtils.getPrimitiveType(ct);
if (componentType == ct) {
return wrapperArray;
} else {
if (!cls.isArray() || !componentType.isPrimitive()) {
throw new IllegalArgumentException(
"Only primitive arrays are supported");
}
final int length = wrapperArray.length;
Object arr = Array.newInstance(componentType, length);
for (int i = 0; i < length; i++) {
Array.set(arr, i, wrapperArray[i]);
}
return arr;
}
}
/**
* Mutates the passed array by reversing the order of the items in it.
*
* @param input The array
* @param <T> The array type
* @since 4.0.0
*/
public static <T> void reverse(T[] input) {
final int len = input.length;
if (len > 1) {
for (int i = 0; i < len / 2; i++) {
T temp = input[i];
final int pos = len - i - 1;
input[i] = input[pos];
input[pos] = temp;
}
}
}
/**
* Iterator implementation used to efficiently expose contents of an
* Array as read-only iterator.
*
* @param <T> the type
*/
private static final class ArrayIterator<T> implements Iterator<T>, Iterable<T> {
private final T[] array;
private int index;
private ArrayIterator(T[] a) {
array = a;
index = 0;
}
@Override
public boolean hasNext() {
return index < array.length;
}
@Override
public T next() {
if (index >= array.length) {
throw new NoSuchElementException();
}
return array[index++];
}
@Override public void remove() {
throw new UnsupportedOperationException();
}
@Override public Iterator<T> iterator() {
return new ArrayIterator<>(array);
}
}
/**
* Iterator implementation used to efficiently expose contents of an
* Array as read-only iterator.
*
* @param <T> the type
*/
private static final class ReverseArrayIterator<T> implements Iterator<T>, Iterable<T> {
private final T[] array;
private int index;
private ReverseArrayIterator(T[] a) {
array = a;
index = a.length > 0 ? a.length - 1 : -1;
}
@Override
public boolean hasNext() {
return index > -1;
}
@Override
public T next() {
if (index <= -1) {
throw new NoSuchElementException();
}
return array[index--];
}
@Override public void remove() {
throw new UnsupportedOperationException();
}
@Override public Iterator<T> iterator() {
return new ReverseArrayIterator<>(array);
}
}
}