/* * 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.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; 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; import org.apache.commons.lang.builder.ToStringBuilder; import org.apache.commons.lang.builder.ToStringStyle; import com.google.common.base.Objects; /** * 数组工具 * * @author Administrator * */ public class ArrayUtils extends org.apache.commons.lang.ArrayUtils { /** * 数组对象遍历执行toString方法,获得String数组对象。 * * @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); } @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,Stringbuffer等对象进行Iterator模式的遍历了。 * * @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元素拷贝到给出的容器中,如果容器大于List的空间,则在超出部分补上null. // 因此不能起到消除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 apache默认的add方法居然不支持泛型...怨念... */ @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; } public interface Filter<T> { boolean accept(T o); } /** * 从可枚举对象中选出需要的目标组成新的List * * @param <T> * @param list * @param filter * @return */ public static <T> List<T> doSelect(Iterable<T> list, Filter<T> filter) { ArrayList<T> result = new ArrayList<T>(); for (T o : list) { if (filter.accept(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); } }