jef.tools.ArrayUtils.java Source code

Java tutorial

Introduction

Here is the source code for jef.tools.ArrayUtils.java

Source

/*
 * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com)
 *
 * 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.
 */
package jef.tools;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import com.google.common.base.Function;
import com.google.common.base.Objects;

import jef.common.BooleanList;
import jef.common.ByteList;
import jef.common.CharList;
import jef.common.DoubleList;
import jef.common.EnumerationWrapper;
import jef.common.IntList;
import jef.common.LongList;

/**
 * 
 * 
 * @author Administrator
 * 
 */
public class ArrayUtils extends org.apache.commons.lang.ArrayUtils {
    /**
     * ??toStringString
     * 
     * @param list
     * @return
     */
    public static String[] toStringArray(List<? extends Object> list) {
        List<String> result = new ArrayList<String>();
        for (Object f : list) {
            result.add(f.toString());
        }
        return result.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    }

    /**
     * Enumeration??Iterable
     * 
     * @param <T>
     * @param e
     * @return
     */
    public static <T> Iterable<T> toIterable(Enumeration<T> e) {
        return new EnumerationWrapper<T>(e);
    }

    /**
     * ?
     * @param source
     * @param function
     * @return
     */
    public static <K, V> List<V> convert(K[] source, Function<K, V> function) {
        List<V> result = new ArrayList<V>(source.length);
        for (int i = 0; i < source.length; i++) {
            result.add(function.apply(source[i]));
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    public static <T> T[] toArray(Enumeration<T> e, Class<T> type) {
        List<T> result = new ArrayList<T>();
        for (; e.hasMoreElements();) {
            result.add(e.nextElement());
        }
        return result.toArray((T[]) Array.newInstance(type, result.size()));
    }

    /**
     * CharSequence????char
     * ?CharBuffer,StringBuilder,StringbufferIterator???
     * 
     * @param e
     * @return
     */
    public static Iterable<Character> toIterable(final CharSequence e) {
        return new Iterable<Character>() {
            public Iterator<Character> iterator() {
                return new Iterator<Character>() {
                    int n = 0;

                    public boolean hasNext() {
                        return n < e.length();
                    }

                    public Character next() {
                        return e.charAt(n++);
                    }

                    public void remove() {
                        throw new UnsupportedOperationException();
                    }
                };
            }
        };
    }

    /**
     * ??
     * 
     * @param from
     * @param to
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <S, T> T[] cast(S[] from, Class<T> to) {
        T[] result = (T[]) Array.newInstance(to, from.length);
        for (int i = 0; i < result.length; i++) {
            result[i] = (T) from[i];
        }
        return result;
    }

    /**
     * null
     * 
     * @param <T>
     * @param arr1
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] removeNull(T[] arr1) {
        List<T> list = new ArrayList<T>(arr1.length);
        for (T e : arr1) {
            if (e != null) {
                list.add(e);
            }
        }
        if (list.size() == arr1.length)
            return arr1;
        // ? list.toArray(arr1);
        // ArrayList.toArray[]List?Listnull.
        // ?null
        T[] t = (T[]) Array.newInstance(arr1.getClass().getComponentType(), list.size());
        return list.toArray(t);
    }

    /**
     * ?
     * 
     * @param obj
     * @return
     */
    public static Object[] toObject(Object obj) {
        Class<?> c = obj.getClass();
        Assert.isTrue(c.isArray());
        Class<?> priType = c.getComponentType();
        if (!priType.isPrimitive())
            return (Object[]) obj;
        if (priType == Boolean.TYPE) {
            return toObject((boolean[]) obj);
        } else if (priType == Byte.TYPE) {
            return toObject((byte[]) obj);
        } else if (priType == Character.TYPE) {
            return toObject((char[]) obj);
        } else if (priType == Integer.TYPE) {
            return toObject((int[]) obj);
        } else if (priType == Long.TYPE) {
            return toObject((long[]) obj);
        } else if (priType == Float.TYPE) {
            return toObject((float[]) obj);
        } else if (priType == Double.TYPE) {
            return toObject((double[]) obj);
        } else if (priType == Short.TYPE) {
            return toObject((short[]) obj);
        }
        throw new IllegalArgumentException();
    }

    /**
     * ?
     * 
     * @param obj
     * @param containerType
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] toObject(Object obj, Class<T> containerType) {
        Class<?> c = obj.getClass();
        Assert.isTrue(c.isArray());
        Class<?> priType = c.getComponentType();
        if (priType == containerType) {
            return (T[]) obj;
        }
        return cast(toObject(obj), containerType);
    }

    /**
     * ??
     * 
     * @param objs
     * @return
     */
    public static Object toPrimitive(Object[] obj) {
        Class<?> c = obj.getClass();
        Assert.isTrue(c.isArray());
        Class<?> objType = c.getComponentType();
        if (objType == Boolean.class) {
            return toPrimitive((Boolean[]) obj);
        } else if (objType == Byte.class) {
            return toPrimitive((Byte[]) obj);
        } else if (objType == Character.class) {
            return toPrimitive((Character[]) obj);
        } else if (objType == Integer.class) {
            return toPrimitive((Integer[]) obj);
        } else if (objType == Long.class) {
            return toPrimitive((Long[]) obj);
        } else if (objType == Float.class) {
            return toPrimitive((Float[]) obj);
        } else if (objType == Double.class) {
            return toPrimitive((Double[]) obj);
        } else if (objType == Short.class) {
            return toPrimitive((Short[]) obj);
        } else {
            throw new IllegalArgumentException();
        }
    }

    /**
     * ???
     * 
     * @param <T>
     * @param array1
     * @param array2
     * @return
     */
    public static <T> T[] merge(T[] array1, T[] array2) {
        List<T> list = new ArrayList<T>();
        for (T str : array1) {
            list.add(str);
        }
        for (T str : array2) {
            if (!list.contains(str)) {
                list.add(str);
            }
        }
        return list.toArray(array1);
    }

    /**
     * ???
     */
    public static int[] merge(int[] array1, int[] array2) {
        IntList list = new IntList();
        for (int str : array1) {
            list.add(str);
        }
        for (int str : array2) {
            if (!list.contains(str)) {
                list.add(str);
            }
        }
        return list.toArrayUnsafe();
    }

    /**
     * ???
     */
    public static char[] merge(char[] array1, char[] array2) {
        CharList list = new CharList();
        for (char str : array1) {
            list.add(str);
        }

        for (char str : array2) {
            if (!list.contains(str)) {
                list.add(str);
            }
        }
        return list.toArrayUnsafe();
    }

    /**
     * ???
     */
    public static double[] merge(double[] array1, double[] array2) {
        List<Double> list = new ArrayList<Double>();
        for (double str : array1) {
            list.add(str);
        }

        for (double str : array2) {
            if (!list.contains(str)) {
                list.add(str);
            }
        }
        return toPrimitive(list.toArray(new Double[] {}));
    }

    /**
     * ???
     */
    public static boolean[] merge(boolean[] array1, boolean[] array2) {
        BooleanList list = new BooleanList();
        for (boolean str : array1) {
            list.add(str);
        }

        for (boolean str : array2) {
            if (!list.contains(str)) {
                list.add(str);
            }
        }
        return list.toArrayUnsafe();
    }

    /**
     * ???
     */
    public static long[] merge(long[] array1, long[] array2) {
        LongList list = new LongList();
        for (long str : array1) {
            list.add(str);
        }

        for (long str : array2) {
            if (!list.contains(str)) {
                list.add(str);
            }
        }
        return list.toArrayUnsafe();
    }

    /**
     * ???
     */
    public static byte[] merge(byte[] array1, byte[] array2) {
        ByteList list = new ByteList();
        for (byte str : array1) {
            list.add(str);
        }

        for (byte str : array2) {
            if (!list.contains(str)) {
                list.add(str);
            }
        }
        return list.toArrayUnsafe();
    }

    /**
     * ???
     */
    public static int[] removeDups(int[] array) {
        IntList list = new IntList(array.length);
        for (int str : array) {
            if (!list.contains(str))
                list.add(str);
        }
        return list.toArrayUnsafe();

    }

    /**
     * ???
     */
    public static char[] removeDups(char[] array) {
        CharList list = new CharList();
        for (char str : array) {
            if (!list.contains(str))
                list.add(str);
        }
        return list.toArrayUnsafe();
    }

    /**
     * ???
     */
    public static byte[] removeDups(byte[] array) {
        ByteList list = new ByteList();
        for (byte str : array) {
            if (!list.contains(str))
                list.add(str);
        }
        return list.toArrayUnsafe();
    }

    /**
     * ???
     */
    public static double[] removeDups(double[] array) {
        DoubleList list = new DoubleList();
        for (double str : array) {
            if (!list.contains(str))
                list.add(str);
        }
        return list.toArrayUnsafe();

    }

    /**
     * ???
     */
    public static boolean[] removeDups(boolean[] array) {
        BooleanList list = new BooleanList();
        for (boolean str : array) {
            if (!list.contains(str))
                list.add(str);
        }
        return list.toArrayUnsafe();
    }

    /**
     * ?????? 1?????? List<T> list=new ArrayList<T>();
     * for (T obj : array) { if (!list.contains(obj)) list.add(obj); } return
     * list.toArray();
     * 
     * 2??hashset?? Set<T> set=new LinkedHashSet<T>();
     * //?????linkedhashset for (T obj : array) {
     * set.add(obj); } return set.toArray();
     * ??50?????? ? ???
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] removeDups(T[] array) {
        List<T> list = new ArrayList<T>();
        for (T obj : array) {
            if (!list.contains(obj))
                list.add(obj);
        }
        if (list.size() == array.length)
            return array;
        return list.toArray((T[]) Array.newInstance(array.getClass().getComponentType(), list.size()));
    }

    /**
     * ??
     */
    public static <T> boolean containsAny(T[] otherContains, T[] formats) {
        for (T obj1 : otherContains) {
            for (T obj2 : formats) {
                if (obj1.equals(obj2))
                    return true;
            }
        }
        return false;
    }

    public static <T> boolean notContains(T[] array, T obj) {
        return !contains(array, obj);
    }

    public static boolean notContains(long[] array, long obj) {
        return !contains(array, obj);
    }

    public static boolean notContains(short[] array, short obj) {
        return !contains(array, obj);
    }

    public static boolean notContains(char[] array, char obj) {
        return !contains(array, obj);
    }

    public static boolean notContains(double[] array, double obj) {
        return !contains(array, obj);
    }

    public static boolean notContains(float[] array, float obj) {
        return !contains(array, obj);
    }

    public static boolean notContains(byte[] array, byte obj) {
        return !contains(array, obj);
    }

    public static boolean notContains(int[] array, int obj) {
        return !contains(array, obj);
    }

    /**
     * addArray apacheadd??......
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] addElement(T[] array, T data, Class<T> componentType) {
        if (data == null)
            return array;
        T[] newArray;
        if (array == null) {
            Assert.notNull(componentType, "The componentType shoule be assigned when the array is null.");
            newArray = (T[]) Array.newInstance(componentType, 1);
            newArray[0] = data;
        } else {
            Class<?> containerType = array.getClass().getComponentType();
            if (!containerType.isAssignableFrom(data.getClass())) {// prompt the
                // type
                // error.
                throw new ArrayStoreException("The new element which typed " + data.getClass().getName()
                        + " can not be put into a array whoes type is " + containerType.getName());
            }
            newArray = (T[]) Array.newInstance(containerType, array.length + 1);
            System.arraycopy(array, 0, newArray, 0, array.length);
            newArray[array.length] = data;
        }
        return newArray;
    }

    @SuppressWarnings("unchecked")
    public static <T> T[] addElement(T[] array, T element) {
        if (element == null)
            return array;
        return addElement(array, element, (Class<T>) element.getClass());
    }

    @SuppressWarnings("unchecked")
    public static <T> T[] addAllElement(T[] array, T[] data) {
        if (data == null || data.length == 0)
            return array;
        T[] newArray;
        if (array == null) {
            return data;
        } else {
            newArray = (T[]) Array.newInstance(data.getClass().getComponentType(), array.length + data.length);
            System.arraycopy(array, 0, newArray, 0, array.length);
            System.arraycopy(data, 0, newArray, array.length, data.length);
        }
        return newArray;
    }

    /**
     * ??
     * 
     * @param array
     * @param len
     * @return
     */
    public static byte[] subArray(byte[] array, int len) {
        if (array.length == len) {
            return array;
        } else if (len > array.length) {
            len = array.length;
        }
        byte[] data = new byte[len];
        System.arraycopy(array, 0, data, 0, len);
        return data;
    }

    /**
     * subArray.?a?
     * 
     * @param <T>
     * @param array
     * @param startIndexInclusive
     * @param endIndexExclusive
     * @return
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <T> T[] subArray(T[] array, int startIndexInclusive, int endIndexExclusive) {
        if (array == null) {
            return null;
        }
        if (startIndexInclusive < 0) {
            startIndexInclusive = 0;
        }
        if (endIndexExclusive > array.length) {
            endIndexExclusive = array.length;
        }
        int newSize = endIndexExclusive - startIndexInclusive;
        Class type = array.getClass().getComponentType();
        if (newSize <= 0) {
            return (T[]) Array.newInstance(type, 0);
        }
        T[] subarray = (T[]) Array.newInstance(type, newSize);
        System.arraycopy(array, startIndexInclusive, subarray, 0, newSize);
        return subarray;
    }

    /**
     * ?????
     */
    public static <T> List<T> subByIndex(List<T> list, int[] indexes) {
        List<T> newList = new ArrayList<T>();
        for (int i : indexes) {
            newList.add(list.get(i));
        }
        return newList;
    }

    /**
     * ??,Collection.contains??obj1.equals(obj2)
     * ==?<B>?</B>???
     * 
     * @param <T>
     * @param list
     * @param obj
     * @return
     */
    public static <T> boolean fastContains(T[] list, T obj) {
        if (list == null)
            return false;
        for (T e : list) {
            if (e == obj)
                return true;
        }
        return false;
    }

    /**
     * ??,Collection.contains??obj1.equals(obj2)
     * ==?<B>?</B>???
     * 
     * @param <T>
     * @param list
     * @param obj
     * @return
     */
    public static <T> boolean fastContains(Collection<T> list, T obj) {
        for (T e : list) {
            if (e == obj)
                return true;
        }
        return false;
    }

    /**
     * ??,Collection.contains??obj1.equals(obj2)
     * ==?<B>?</B>???
     * 
     * @param list
     * @param keys
     * @return
     */
    public static <T> boolean fastContainsAny(Collection<T> list, T[] keys) {
        for (T e : list) {
            for (T obj : keys) {
                if (e == obj)
                    return true;
            }
        }
        return false;
    }

    /**
     * ??,Collection.contains??obj1.equals(obj2)
     * ==?<B>?</B>???
     * 
     * @param list
     * @param keys
     * @return
     */
    public static <T> boolean fastContainsAny(T[] list, T[] keys) {
        if (list == null)
            return false;
        for (T e : list) {
            for (T obj : keys) {
                if (e == obj)
                    return true;
            }
        }
        return false;
    }

    /**
     * ?Arrays.asList(),ArrayList
     * ????
     */
    public static <T> List<T> asList(T... args) {
        ArrayList<T> list = new ArrayList<T>(args.length + 16);
        list.addAll(Arrays.asList(args));
        return list;
    }

    /**
     * ? ???
     * 
     * @param values
     * @param str
     * @return
     */
    public static boolean containsIgnoreCase(String[] values, String str) {
        for (String v : values) {
            if (v == null) {
                if (str == null) {
                    return true;
                } else {
                    continue;
                }
            }
            if (v.equalsIgnoreCase(str)) {
                return true;
            }
        }
        return false;
    }

    /**
     * ?,?null
     * 
     * @param text
     * @param i
     * @return
     */
    public static Object toFixLength(Object obj, int len) {
        int length = length(obj);
        if (length == len)
            return obj;
        Object result = Array.newInstance(obj.getClass().getComponentType(), len);
        System.arraycopy(obj, 0, result, 0, Math.min(length, len));
        return result;
    }

    /**
     * 
     * 
     * @param source
     * @param filter
     * @return
     */
    public static <T> List<T> filter(T[] source, Predicate<T> filter) {
        if (source == null)
            return Collections.emptyList();
        if (filter == null)
            return Arrays.asList(source);
        List<T> result = new ArrayList<T>(source.length);
        for (T t : source) {
            if (filter.test(t)) {
                result.add(t);
            }
        }
        return result;
    }

    /**
     * ???List
     * 
     * @param <T>
     * @param list
     * @param filter
     * @return
     */
    public static <T> List<T> doSelect(Iterable<T> list, Predicate<T> filter) {
        ArrayList<T> result = new ArrayList<T>();
        for (T o : list) {
            if (filter.test(o)) {
                result.add(o);
            }
        }
        return result;
    }

    /**
     * @since JDK 1.6
     */
    public final static byte[] copyOf(byte[] original, int newLength) {
        byte[] copy = new byte[newLength];
        System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
        return copy;
    }

    /**
     * @since JDK 1.6
     */
    public final static char[] copyOf(char[] original, int newLength) {
        char[] copy = new char[newLength];
        System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
        return copy;
    }

    /**
     * @since JDK 1.6
     */
    @SuppressWarnings("unchecked")
    public final static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }

    /**
     * @since JDK 1.6
     */
    @SuppressWarnings("unchecked")
    public final static <T, U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        T[] copy = ((Object) newType == (Object) Object[].class) ? (T[]) new Object[newLength]
                : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
        return copy;
    }

    /**
     * 
     */
    public static boolean equals(Object[] a1, Object[] a2) {
        if (a1 == null && a2 == null)
            return true;
        if (a1 == null || a2 == null)
            return false;
        if (a1.length != a2.length)
            return false;
        for (int n = 0; n < a1.length; n++) {
            if (!Objects.equal(a1[n], a2[n])) {
                return false;
            }
        }
        return true;
    }

    /**
     * ?
     * 
     * @param a1
     * @param a2
     * @return
     */
    public static <T> boolean equalsIgnoreOrder(T[] a1, T[] a2) {
        if (a1 == null && a2 == null)
            return true;
        if (a1 == null || a2 == null)
            return false;
        if (a1.length != a2.length)
            return false;
        for (int n = 0; n < a1.length; n++) {
            T o = a1[n];
            if (!contains(a2, o)) {
                return false;
            }
        }
        return true;
    }

    /**
     * ??
     * 
     * @param array1
     * @param array2
     * @return
     * 
     */
    public static boolean equalsIgnoreOrder(Object array1, Object array2) {
        Object[] obj1 = toObject(array1);
        Object[] obj2 = toObject(array2);
        HashSet<Object> set1 = new HashSet<Object>(Arrays.asList(obj1));
        HashSet<Object> set2 = new HashSet<Object>(Arrays.asList(obj2));
        return set1.equals(set2);
    }

    /**
     * ??
     * java.util.Arrays??????9???
     * 
     * @param a1
     *            Object
     * @param a2
     *            Object,
     * @return
     * @see java.util.Arrays#equals(boolean[], boolean[])
     * @see java.util.Arrays#equals(byte[], byte[])
     * @see java.util.Arrays#equals(char[], char[])
     * @see java.util.Arrays#equals(double[], double[])
     * @see java.util.Arrays#equals(float[], float[])
     * @see java.util.Arrays#equals(int[], int[])
     * @see java.util.Arrays#equals(long[], long[])
     * @see java.util.Arrays#equals(short[], short[])
     * @see java.util.Arrays#equals(Object[], Object[])
     * @throws IllegalArgumentException
     *             ?
     */
    public static boolean equals(Object a1, Object a2) {
        if (a1 == a2)
            return true;
        if (a1 == null || a2 == null)
            return false;
        Class<?> clz1 = a1.getClass();
        Class<?> clz2 = a2.getClass();
        if (!clz1.isArray() || !clz2.isArray()) {
            throw new IllegalArgumentException("must comapre between two Array.");
        }
        clz1 = clz1.getComponentType();
        clz2 = clz2.getComponentType();
        if (clz1.isPrimitive() != clz2.isPrimitive()) {
            return false;
        }
        if (clz1 == int.class) {
            return Arrays.equals((int[]) a1, (int[]) a2);
        } else if (clz1 == short.class) {
            return Arrays.equals((short[]) a1, (short[]) a2);
        } else if (clz1 == long.class) {
            return Arrays.equals((long[]) a1, (long[]) a2);
        } else if (clz1 == float.class) {
            return Arrays.equals((float[]) a1, (float[]) a2);
        } else if (clz1 == double.class) {
            return Arrays.equals((double[]) a1, (double[]) a2);
        } else if (clz1 == boolean.class) {
            return Arrays.equals((boolean[]) a1, (boolean[]) a2);
        } else if (clz1 == byte.class) {
            return Arrays.equals((byte[]) a1, (byte[]) a2);
        } else if (clz1 == char.class) {
            return Arrays.equals((char[]) a1, (char[]) a2);
        } else {
            return Arrays.equals((Object[]) a1, (Object[]) a2);
        }
    }

    /**
     * ?:?
     * 
     * @deprecated please use the method in JDK {@link Array#getLength(Object)}
     */
    public static int length(Object obj) {
        return Array.getLength(obj);
    }

    /**
     * ?:set ??-1?-2
     * set???
     */
    public static Object setValueAndExpandArray(Object obj, int index, Object value) {
        int length = Array.getLength(obj);
        Object result = obj;
        if (index < 0 && index + length >= 0) {
            index += length;
        } else if (index < 0) {// ?
            result = toFixLength(obj, -index);
        } else if (index >= length) {// 
            result = toFixLength(obj, index + 1);
        }
        set(result, index, value);
        return result;
    }

    /**
     * ? ??-1?-2
     */
    public static boolean isIndexValid(Object obj, int index) {
        int length = length(obj);
        if (index < 0)
            index += length;
        return index >= 0 && index < length;
    }

    /**
     * ?:get
     * 
     * @param obj
     *            
     * @param index
     *            ?? ??-1?-2
     */
    public final static Object get(Object obj, int index) {
        if (index >= 0) {
            return Array.get(obj, index);
        } else {
            return Array.get(obj, Array.getLength(obj) + index);
        }
    }

    /**
     * ?:set
     * 
     * @param: index
     *             ??-1?-2
     */
    public final static void set(Object obj, int index, Object value) {
        if (index >= 0) {
            Array.set(obj, index, value);
        } else {
            Array.set(obj, Array.getLength(obj) + index, value);
        }
    }

    /**
     * ?
     * 
     * @param ls
     * @param ls2
     * @return
     */
    public static Object[] intersect(Object[] ls, Object[] ls2) {
        HashSet<Object> set = new HashSet<Object>(Arrays.asList(ls));
        set.retainAll(Arrays.asList(ls2));
        return set.toArray();
    }

    /**
     * ?
     * 
     * @param ls
     * @param ls2
     * @return
     */
    public static Object[] union(Object[] ls, Object[] ls2) {
        HashSet<Object> set = new HashSet<Object>(Arrays.asList(ls));
        for (Object o : ls2) {
            set.add(o);
        }
        return set.toArray();
    }

    /**
     * ?(??ls??ls2) ???ls??ls2
     * 
     * @param ls
     * @param ls2
     * @return
     */
    public static Object[] minus(Object[] ls, Object[] ls2) {
        HashSet<Object> set = new HashSet<Object>(Arrays.asList(ls));
        set.removeAll(Arrays.asList(ls2));
        return set.toArray();
    }

    /**
     * ????? ? 
     * 
     * @param ls
     * @param ls2
     * @return
     */
    public static Object[] xor(Object[] ls, Object[] ls2) {
        // 
        Set<Object> setAll = new HashSet<Object>(Arrays.asList(ls));
        for (Object o : ls2) {
            setAll.add(o);
        }
        // 
        HashSet<Object> setInter = new HashSet<Object>(Arrays.asList(ls));
        setInter.retainAll(Arrays.asList(ls2));
        // ?
        setAll.removeAll(setInter);
        return setAll.toArray();
    }

    public static final ToStringStyle ARRAY_SIMPLE_STYLE = new ToStringStyle() {
        private static final long serialVersionUID = 1L;

        {
            this.setUseClassName(false);
            this.setUseIdentityHashCode(false);
            this.setUseFieldNames(false);
            this.setContentStart("");
            this.setContentEnd("");
            this.setArrayStart("");
            this.setArrayEnd("");
        }
    };

    /**
     * Outputs an array as a String with {} surrounded or not, treating null as
     * an empty array.
     * 
     * @param array
     * @param trimStartAndEnd
     *            ?{}
     * @return
     */
    public static String toString(Object array, boolean trimStartAndEnd) {
        if (trimStartAndEnd) {
            return new ToStringBuilder(array, ARRAY_SIMPLE_STYLE).append(array).toString();
        }
        return org.apache.commons.lang.ArrayUtils.toString(array);
    }

}