fr.landel.utils.commons.ArrayUtils.java Source code

Java tutorial

Introduction

Here is the source code for fr.landel.utils.commons.ArrayUtils.java

Source

/*-
 * #%L
 * utils-commons
 * %%
 * Copyright (C) 2016 - 2018 Gilles Landel
 * %%
 * 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
 * 
 *      http://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.
 * #L%
 */
package fr.landel.utils.commons;

import java.util.Objects;

/**
 * Operations on arrays, primitive arrays (like {@code int[]}) and primitive
 * wrapper arrays (like {@code Integer[]}).
 *
 * <p>
 * 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.
 * </p>
 *
 * <p>
 * #ThreadSafe#
 * </p>
 *
 * @since Aug 2, 2016
 * @author Gilles
 *
 */
public final class ArrayUtils extends org.apache.commons.lang3.ArrayUtils {

    /**
     * Hidden constructor
     */
    private ArrayUtils() {
        throw new UnsupportedOperationException();
    }

    /**
     * Search if {@code arrayToSearch} contains all {@code arraySearched}
     * entries.
     * 
     * @param arrayToSearch
     *            where to search array (required, not null)
     * @param arraySearched
     *            what to search array (required, not null)
     * @param <T>
     *            The type of element in array to search
     * @param <U>
     *            The type of element in searched array
     * @return true, if all elements were found
     */
    public static <T, U> boolean containsAll(final T[] arrayToSearch, final U[] arraySearched) {
        return containsAll(arrayToSearch, arraySearched, true);
    }

    /**
     * Search if {@code arrayToSearch} contains all {@code arraySearched}
     * entries.
     * 
     * @param arrayToSearch
     *            where to search array (required, not null)
     * @param arraySearched
     *            what to search array (required, not null)
     * @param checkType
     *            check if the type is identical from each array
     * @param <T>
     *            The type of element in array to search
     * @param <U>
     *            The type of element in searched array
     * @return true, if all elements were found
     */
    public static <T, U> boolean containsAll(final T[] arrayToSearch, final U[] arraySearched,
            final boolean checkType) {
        Objects.requireNonNull(arrayToSearch, "Array to search cannot be null");
        Objects.requireNonNull(arraySearched, "Searched array cannot be null");

        return has(arrayToSearch, arraySearched, true, checkType);
    }

    /**
     * Search if {@code arrayToSearch} contains any {@code arraySearched}
     * entries.
     * 
     * @param arrayToSearch
     *            where to search array (required, not null)
     * @param arraySearched
     *            what to search array (required, not null)
     * @param <T>
     *            The type of element in array to search
     * @param <U>
     *            The type of element in searched array
     * @return true, if at least one element was found
     */
    public static <T, U> boolean containsAny(final T[] arrayToSearch, final U[] arraySearched) {
        return containsAny(arrayToSearch, arraySearched, true);
    }

    /**
     * Search if {@code arrayToSearch} contains any {@code arraySearched}
     * entries.
     * 
     * @param arrayToSearch
     *            where to search array (required, not null)
     * @param arraySearched
     *            what to search array (required, not null)
     * @param checkType
     *            check if the type is identical from each array
     * @param <T>
     *            The type of element in array to search
     * @param <U>
     *            The type of element in searched array
     * @return true, if at least one element was found
     */
    public static <T, U> boolean containsAny(final T[] arrayToSearch, final U[] arraySearched,
            final boolean checkType) {
        Objects.requireNonNull(arrayToSearch, "Array to search cannot be null");
        Objects.requireNonNull(arraySearched, "Searched array cannot be null");

        return has(arrayToSearch, arraySearched, false, checkType);
    }

    /**
     * Replaces the searched value by the replacement one in the specified
     * array.
     * 
     * @param array
     *            the array where to replace (cannot be {@code null})
     * @param searchedValue
     *            the searched value
     * @param replacementValue
     *            the replacement value
     * @param <T>
     *            the array components type
     */
    public static <T> void replace(T[] array, final T searchedValue, final T replacementValue) {
        Objects.requireNonNull(array, "Array to search cannot be null");

        for (int i = 0; i < array.length; ++i) {
            if (Objects.equals(array[i], searchedValue)) {
                array[i] = replacementValue;
            }
        }
    }

    /**
     * Replaces the searched values by the replacements values in the specified
     * array.
     * 
     * @param array
     *            the array where to replace (cannot be {@code null})
     * @param searchedValues
     *            the searched values (cannot be {@code null})
     * @param replacementValues
     *            the replacement values (cannot be {@code null})
     * @param <T>
     *            the array components type
     * @throws NullPointerException
     *             if any parameter is {@code null}
     * @throws IllegalArgumentException
     *             if {@code searchedValues} and {@code replacementValues}
     *             haven't the same length
     */
    public static <T> void replace(T[] array, final T[] searchedValues, final T[] replacementValues) {
        Objects.requireNonNull(array, "Array to search cannot be null");
        Objects.requireNonNull(searchedValues, "Array of searched values cannot be null");
        Objects.requireNonNull(replacementValues, "Array of replacement values cannot be null");

        if (searchedValues.length != replacementValues.length) {
            throw new IllegalArgumentException(
                    "Searched values and replacement values arrays must have the same length");
        }

        for (int i = 0; i < array.length; ++i) {
            for (int j = 0; j < searchedValues.length; ++j) {
                if (Objects.equals(array[i], searchedValues[j])) {
                    array[i] = replacementValues[j];
                }
            }
        }
    }

    /**
     * Concatenates all the elements of the given arrays into a new array.
     * <p>
     * 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.
     * </p>
     * 
     * @param array1
     *            the first array
     * @param array2
     *            the second array
     * @param <T>
     *            the array components type
     * @return the new array
     */
    @SafeVarargs
    public static <T> T[] concat(final T[] array1, final T... array2) {
        return addAll(array1, array2);
    }

    /**
     * Concatenates two arrays in the output array
     * <p>
     * The output array contains all of the element of {@code array1} followed
     * by all of the elements {@code array2}.
     * </p>
     * 
     * @param outputArray
     *            the output array (cannot be {@code null} and length must be
     *            greater than array1 plus array2 length)
     * @param array1
     *            the first input array
     * @param array2
     *            the second input array
     * @param <T>
     *            the array components type
     * @return the {@code outputArray} instance
     * @throws NullPointerException
     *             if {@code outputArray} is {@code null}
     * @throws IllegalArgumentException
     *             if {@code array1} plus {@code array2} length is greater than
     *             {@code outputArray} length
     */
    @SafeVarargs
    public static <T> T[] concat(final T[] outputArray, final T[] array1, final T... array2) {
        Objects.requireNonNull(outputArray, "The output array cannot be null");

        final int array1Length = getLength(array1);
        final int array2Length = getLength(array2);

        if (outputArray.length < array1Length + array2Length) {
            throw new IllegalArgumentException("The output array cannot be smaller than array1 plus array2 length");
        }

        if (array1 != null) {
            System.arraycopy(array1, 0, outputArray, 0, array1Length);
        }

        if (array2 != null) {
            System.arraycopy(array2, 0, outputArray, array1Length, array2Length);
        }

        return outputArray;
    }

    /**
     * Count the number of {@code arraySearched} in {@code arrayToSearch}.
     * 
     * @param arrayToSearch
     *            where to search array (required, not null)
     * @param arraySearched
     *            what to search array (required, not null)
     * @param <T>
     *            The type of element in array to search
     * @param <U>
     *            The type of element in searched array
     * @return number, the count of elements found
     */
    public static <T, U> int count(final T[] arrayToSearch, final U[] arraySearched) {
        return count(arrayToSearch, arraySearched, true);
    }

    /**
     * Count the number of {@code arraySearched} in {@code arrayToSearch}.
     * 
     * @param arrayToSearch
     *            where to search array (required, not null)
     * @param arraySearched
     *            what to search array (required, not null)
     * @param checkType
     *            check if the type is identical from each array
     * @param <T>
     *            The type of element in array to search
     * @param <U>
     *            The type of element in searched array
     * @return number, the count of elements found
     */
    public static <T, U> int count(final T[] arrayToSearch, final U[] arraySearched, final boolean checkType) {
        Objects.requireNonNull(arrayToSearch, "Array to search cannot be null");
        Objects.requireNonNull(arraySearched, "Searched array cannot be null");

        return count(arrayToSearch, arraySearched, checkType, false);
    }

    /**
     * Count the number of object in {@code arrayToSearch}.
     * 
     * @param arrayToSearch
     *            where to search array (required, not null)
     * @param object
     *            what to search
     * @param <T>
     *            The type of element in array to search
     * @param <U>
     *            The type of element to search
     * @return the number of iterations
     */
    public static <T, U> int count(final T[] arrayToSearch, final U object) {
        return count(arrayToSearch, object, true);
    }

    /**
     * Count the number of object in {@code arrayToSearch}.
     * 
     * @param arrayToSearch
     *            where to search array (required, not null)
     * @param object
     *            what to search
     * @param checkType
     *            check if the type is identical from each array
     * @param <T>
     *            The type of element in array to search
     * @param <U>
     *            The type of element to search
     * @return the number of iterations
     */
    @SuppressWarnings("unlikely-arg-type")
    public static <T, U> int count(final T[] arrayToSearch, final U object, final boolean checkType) {
        Objects.requireNonNull(arrayToSearch, "Array to search cannot be null");

        int found = 0;
        if (object == null) {
            for (T objectArray : arrayToSearch) {
                if (objectArray == null) {
                    ++found;
                }
            }
        } else if (!checkType || arrayToSearch.getClass().getComponentType().isInstance(object)) {
            for (T objectArray : arrayToSearch) {
                if (object.equals(objectArray)) {
                    ++found;
                }
            }
        }
        return found;
    }

    private static <T, U> int count(final T[] arrayToSearch, final U[] arraySearched, final boolean checkType,
            final boolean stopOnFirst) {
        if (checkType && !arrayToSearch.getClass().getComponentType()
                .isAssignableFrom(arraySearched.getClass().getComponentType())) {
            return 0;
        }

        if (stopOnFirst) {
            for (U objectArray : arraySearched) {
                if (has(arrayToSearch, objectArray)) {
                    return 1;
                }
            }
            return 0;
        } else {
            int found = 0;
            for (U objectArray : arraySearched) {
                if (has(arrayToSearch, objectArray)) {
                    ++found;
                }
            }
            return found;
        }
    }

    @SuppressWarnings("unlikely-arg-type")
    private static <T, U> boolean has(final T[] array, final U object) {
        if (object == null) {
            for (T objectArray : array) {
                if (objectArray == null) {
                    return true;
                }
            }
        } else {
            for (T objectArray : array) {
                if (object.equals(objectArray)) {
                    return true;
                }
            }
        }
        return false;
    }

    private static <T, U> boolean has(final T[] arrayToSearch, final U[] arraySearched, final boolean all,
            final boolean checkType) {
        if (checkType && !arrayToSearch.getClass().getComponentType()
                .isAssignableFrom(arraySearched.getClass().getComponentType())) {
            return false;
        }

        if (all) {
            return count(arrayToSearch, arraySearched, false, false) == arraySearched.length;
        } else {
            return count(arrayToSearch, arraySearched, false, true) > 0;
        }
    }
}