/* * 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.collection; import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.AbstractList; import java.util.AbstractMap; import java.util.AbstractQueue; import java.util.AbstractSet; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Queue; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import org.apache.commons.lang.ObjectUtils; import com.google.common.base.Function; import com.google.common.base.Objects; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Collections2; import com.google.common.collect.Multimap; import jef.common.wrapper.ArrayIterator; import jef.tools.ArrayUtils; import jef.tools.Assert; import jef.tools.reflect.ClassEx; import jef.tools.reflect.FieldEx; import jef.tools.reflect.GenericUtils; /** * 集合操作工具类 v2.0 * * @author Joe */ public class CollectionUtils { /** * 常量,用于获得一个空的SortedMap */ @SuppressWarnings({ "rawtypes", "unchecked" }) private static final SortedMap EMPTY_SORTEDMAP = Collections.unmodifiableSortedMap(new TreeMap()); private CollectionUtils() { } public static final class C extends CollectionUtils{ } /** * 将数组转换为Map。(Map不保证顺序) * * @param array * 数组 * @param keyExtractor * 键值提取函数 * @return 在每个元素中提取键值后,形成Map,如果多个对象返回相同的key,那么会互相覆盖。如果不希望互相覆盖,请使用 * {@linkplain #group(Collection, Function)} */ public static <K, V> Map<K, V> toMap(V[] array, Function<V, K> keyExtractor) { if (array == null || array.length == 0) return Collections.emptyMap(); Map<K, V> result = new HashMap<K, V>(array.length); for (V value : array) { K key = keyExtractor.apply(value); result.put(key, value); } return result; } /** * 将数组转换为Map。(Map按Key排序) * @param array 数组 * @param keyExtractor 键值提取函数 * @param comp 键值比较器 * @return 在每个元素中提取键值后,形成Map,如果多个对象返回相同的key,那么会互相覆盖。如果不希望互相覆盖,请使用 * {@linkplain #group(Collection, Function)} */ @SuppressWarnings("unchecked") public static <K, V> SortedMap<K, V> toSortedMap(V[] array, Function<V, K> keyExtractor, Comparator<K> comp) { if (array == null || array.length == 0) return EMPTY_SORTEDMAP; SortedMap<K, V> result = new TreeMap<K, V>(comp); for (V value : array) { K key = keyExtractor.apply(value); result.put(key, value); } return result; } /** * 将Collection转换为Map。(Map不保证顺序) * * @param collection * 集合 * @param keyExtractor * 键值提取函数 * @return 在每个元素中提取键值后,形成Map。相同键值的记录将发生叠加(仅保留最后的一个) */ public static <K, V> Map<K, V> toMap(Collection<V> collection, Function<V, K> keyExtractor) { if (collection == null || collection.isEmpty()) return Collections.emptyMap(); Map<K, V> result = new HashMap<K, V>(collection.size()); for (V value : collection) { K key = keyExtractor.apply(value); result.put(key, value); } return result; } /** * 将集合转换为Map。(Map按Key排序) * @param collection 集合 * @param keyExtractor 键值提取函数 * @param comp 键值比较器 * @return 在每个元素中提取键值后,形成Map,如果多个对象返回相同的key,那么会互相覆盖。如果不希望互相覆盖,请使用 * {@linkplain #group(Collection, Function)} */ @SuppressWarnings("unchecked") public static <K, V> SortedMap<K, V> toSortedMap(Collection<V> collection, Function<V, K> keyExtractor, Comparator<K> comp) { if (collection == null || collection.size() == 0) return EMPTY_SORTEDMAP; SortedMap<K, V> result = new TreeMap<K, V>(comp); for (V value : collection) { K key = keyExtractor.apply(value); result.put(key, value); } return result; } /** * 将一个数组的每个元素进行函数处理后重新组成一个集合 * * @param array * 数组 * @param extractor * 提取函数 * @param ignoreNull * 如果为true,那么提出后的null值会被忽略 * @return 提取后形成的列表 */ public static <T, A> List<T> extract(A[] array, Function<A, T> extractor) { return extract(array, extractor, false); } /** * 将一个数组的每个元素进行函数处理后重新组成一个集合 * * @param array * 数组 * @param extractor * 提取函数 * @param ignoreNull * 如果为true,那么提出后的null值会被忽略 * @return 提取后形成的列表 */ public static <T, A> List<T> extract(A[] array, Function<A, T> extractor, boolean ignoreNull) { List<T> result = new ArrayList<T>(array.length); if (array != null) { for (A a : array) { T t = extractor.apply(a); if (ignoreNull && t == null) { continue; } result.add(t); } } return result; } /** * 将一个集合对象的每个元素进行函数处理后重新组成一个集合 * * @param collection * 集合对象 * @param extractor * 提取函数 * @return 提取后形成的列表 */ public static <T, A> List<T> extract(Collection<A> collection, Function<A, T> extractor) { return extract(collection, extractor, false); } /** * 将一个集合对象的每个元素进行函数处理后重新组成一个集合 * * @param collection * 集合对象 * @param extractor * 提取函数 * @param ignoreNull * 如果为true,那么提出后的null值会被忽略 * @return 提取后形成的列表 */ public static <T, A> List<T> extract(Collection<A> collection, Function<A, T> extractor, boolean ignoreNull) { List<T> result = new ArrayList<T>(collection.size()); if (collection != null) { for (A a : collection) { T t = extractor.apply(a); if (ignoreNull && t == null) { continue; } result.add(t); } } return result; } /** * 转换,和{@link #extract(Collection, Function)} * 基本一样,区别在于extract是立即计算,transform是延迟计算的。 * * @param collection * 集合对象 * @param extractor * 提取函数 * @return 提取后形成的集合 */ public static <T, A> Collection<T> transform(Collection<A> collection, Function<A, T> extractor) { return Collections2.transform(collection, extractor); } /** * 转换,和{@link #extract(Collection, Function)} * 基本一样,区别在于extract是立即计算,transform是延迟计算的。 * * @param array * 数组 * @param extractor * 提取函数 * @return 提取后形成的集合 */ public static <T, A> Collection<T> transform(A[] array, Function<A, T> extractor) { return Collections2.transform(Arrays.asList(array), extractor); } /** * 对Map对象进行翻转(键值互换),Key变为Value,Value变为key。 * 由于value值不能保证唯一,因此转换后的是一个{@link Multimap}。 * * 比如 有一个记录学生考试成绩的Map * * <pre> * <tt>{tom: 100},{jack: 95},{king: 88}, {mar: 77}, {jim: 88}</tt> * </pre> * * 分组后,得到的新的map为 * * <pre> * <tt>{100:[tom]}, {95:[jack]}, {88: [king,jim]}, {77:[mar]}</tt> * </pre> * * @param <K> * @param <V> * @param map * 要反转的Map * @return A new Multimap that reverse key and value */ public static <K, V> Multimap<V, K> inverse(Map<K, V> map) { Multimap<V, K> result = ArrayListMultimap.create(); for (Entry<K, V> e : map.entrySet()) { result.put(e.getValue(), e.getKey()); } return result; } /** * 对集合进行分组 * * @param collection * 要分组的集合 * @param function * 获取分组Key的函数 * @return 分组后的集合,每个Key可对应多个Value值。 */ public static <T, A> Multimap<A, T> group(Collection<T> collection, Function<T, A> function) { Assert.notNull(collection); Multimap<A, T> result = ArrayListMultimap.create(); for (T value : collection) { A attrib = function.apply(value); result.put(attrib, value); } return result; } /** * 在集合中查找符合条件的首个元素 * * @param collection * 集合 * @param filter * 过滤器 * @return */ public static <T> T findFirst(Collection<T> collection, Function<T, Boolean> filter) { if (collection == null || collection.isEmpty()) return null; for (T obj : collection) { if (filter.apply(obj)) { return obj; } } return null; } /** * 根据字段名称和字段值查找第一个记录 * * @param collection * 集合 * @param fieldname * 字段名 * @param value * 查找值 * @return 查找到的元素 */ public static <T> T findFirst(Collection<T> collection, String fieldname, Object value) { if (collection == null || collection.isEmpty()) return null; Class<?> clz = collection.iterator().next().getClass(); FieldValueFilter<T> f = new FieldValueFilter<T>(clz, fieldname, value); return findFirst(collection, f); } /** * 根据字段名称和字段值查找所有记录 * * @param <T> * 泛型 * @param collection * 集合 * @param fieldname * 字段 * @param value * 值 * @return 过滤后的集合 */ public static <T> List<T> getFiltered(Collection<T> collection, String fieldname, Object value) { if(collection.isEmpty())return Collections.emptyList(); Class<?> clz = collection.iterator().next().getClass(); return getFiltered(collection, new FieldValueFilter<T>(clz, fieldname, value)); } /** * 在集合中查找符合条件的元素 * * @param <T> * 泛型 * @param collection * 集合 * @param filter * 过滤器 * @return */ public static <T> List<T> getFiltered(Collection<T> collection, Function<T, Boolean> filter) { List<T> list = new ArrayList<T>(); if (collection == null || collection.isEmpty()) return list; for (T obj : collection) { if (filter.apply(obj)) { list.add(obj); } } return list; } /** * 在集合中查找符合条件的元素 * * @param <T> * 泛型 * @param collection * 集合 * @param filter * 过滤器 * @return */ public static <T> void filter(Collection<T> collection, Function<T, Boolean> filter) { for (Iterator<T> iter = collection.iterator(); iter.hasNext();) { T e = iter.next(); if (!Boolean.TRUE.equals(filter.apply(e))) { iter.remove(); } } } /** * 对Map进行过滤,获得一个新的Map. 如果传入的是有序Map,新Map会保留原来的顺序。 * * @param map * 要处理的Map * @param filter * 过滤器 * @return 过滤后的新Map */ public static <K, V> Map<K, V> getFiltered(Map<K, V> map, Function<Map.Entry<K, V>, Boolean> filter) { Map<K, V> result; if (map instanceof SortedMap) { result = new TreeMap<K, V>(((SortedMap<K, V>) map).comparator()); } else { result = new HashMap<K, V>(map.size()); } for (Map.Entry<K, V> e : map.entrySet()) { Boolean b = filter.apply(e); if (Boolean.TRUE.equals(b)) { result.put(e.getKey(), e.getValue()); } } return result; } /** * 对Map进行过滤,当filter返回true时,元素被保留。反之被删除。<br> * 注意,如果传入的Map类型不支持Iterator.remove()方式移除元素,将抛出异常。( * 一般是UnsupportedOperationException) * * @param map * 要处理的Map * @param filter * Function,用于指定哪些元素要保留 * @throws UnsupportedOperationException */ public static <K, V> void filter(Map<K, V> map, Function<Map.Entry<K, V>, Boolean> filter) { for (Iterator<Map.Entry<K, V>> iter = map.entrySet().iterator(); iter.hasNext();) { Map.Entry<K, V> e = iter.next(); if (!Boolean.TRUE.equals(filter.apply(e))) { iter.remove(); } } } /** * 将数组或Enumation转换为Collection * * @param data * @param type * @return */ @SuppressWarnings("unchecked") public static <T> Collection<T> toCollection(Object data, Class<T> type) { if (data == null) return null; if (data instanceof Collection) { return ((Collection<T>) data); } else if (data.getClass().isArray()) { if (data.getClass().getComponentType().isPrimitive()) { int len = Array.getLength(data); List<T> result = new ArrayList<T>(len); for (int i = 0; i < len; i++) { result.add((T) Array.get(data, i)); } } else { return Arrays.asList((T[]) data); } } else if (data instanceof Enumeration) { Enumeration<T> e = (Enumeration<T>) data; List<T> result = new ArrayList<T>(); for (; e.hasMoreElements();) { result.add(e.nextElement()); } return result; } throw new IllegalArgumentException("The input type " + data.getClass() + " can not convert to Collection."); } /** * 检查传入的对象类型,并尝试获取其遍历器句柄 * * @param data * 要判断的对象 * @param clz * @return */ @SuppressWarnings("unchecked") public static <T> Iterator<T> iterator(Object data, Class<T> clz) { if (data == null) return null; if (data instanceof Collection) { return ((Collection<T>) data).iterator(); } else if (data.getClass().isArray()) { return new ArrayIterator<T>(data); } else if (data instanceof Enumeration) { return new EnumerationIterator<T>((Enumeration<T>) data); } return null; } /** * 将Enumeration转换为一个新的List * @param data * @return 转换后的List */ public static <E> List<E> toList(Enumeration<E> data){ List<E> result=new ArrayList<E>(); for(;data.hasMoreElements();){ result.add(data.nextElement()); } return result; } /** * 将Iterable转换为List * @param data * @return 转换后的List */ public static <E> List<E> toList(Iterable<E> data){ List<E> result=new ArrayList<E>(); for(Iterator<E> iter=data.iterator();iter.hasNext();){ result.add(iter.next()); } return result; } /** * 将传入的对象转换为可遍历的对象。 * * @param data * @return */ public static <E> Iterator<E> iterator(Enumeration<E> data) { return new EnumerationIterator<E>(data); } /** * 判断指定的类型是否为数组或集合类型 * * @param type * @return true if type is a collection type. */ public static boolean isArrayOrCollection(Type type) { if (type instanceof GenericArrayType) { return true; } else if (type instanceof Class) { Class<?> rawType = (Class<?>) type; return rawType.isArray() || Collection.class.isAssignableFrom(rawType); } else { return Collection.class.isAssignableFrom(GenericUtils.getRawClass(type)); } } /** * 判断一个类型是否为Collection * * @param type * @return true if type is a collection type. */ public static boolean isCollection(Type type) { if (type instanceof GenericArrayType) { return false; } else if (type instanceof Class) { Class<?> rawType = (Class<?>) type; return Collection.class.isAssignableFrom(rawType); } else { return Collection.class.isAssignableFrom(GenericUtils.getRawClass(type)); } } /** * 得到指定的数组或集合类型的原始类型 * * @param type * @return 如果给定的类型不是数组或集合,返回null,否则返回数组或集合的单体类型 */ public static Type getComponentType(Type type) { if (type instanceof GenericArrayType) { return ((GenericArrayType) type).getGenericComponentType(); } else if (type instanceof Class) { Class<?> rawType = (Class<?>) type; if (rawType.isArray()) { return rawType.getComponentType(); } else if (Collection.class.isAssignableFrom(rawType)) { // 此时泛型类型已经丢失,只能返Object return Object.class; } } else if (type instanceof ParameterizedType) { ParameterizedType pType = (ParameterizedType) type; Type rawType = pType.getRawType(); if (isCollection(rawType)) { return pType.getActualTypeArguments()[0]; } } return null; } /** * 得到指定类型(或泛型)的集合元素类型 。如果这个类型还是泛型,那么就丢弃参数得到原始的class * * @param type * @return */ public static Class<?> getSimpleComponentType(Type type) { Type result = getComponentType(type); if (result instanceof Class<?>) { return (Class<?>) result; } // 不是集合/数组。或者集合数组内的泛型参数不是Class而是泛型变量、泛型边界等其他复杂泛型 return null; } /** * 得到数组或集合类型的长度 * * @param obj * @return */ @SuppressWarnings("rawtypes") public static int length(Object obj) { if (obj.getClass().isArray()) { return Array.getLength(obj); } Assert.isTrue(obj instanceof Collection); return ((Collection) obj).size(); } /** * 将根据传入的集合对象创建合适的集合容器 */ @SuppressWarnings("rawtypes") public static Object createContainerInstance(ClassEx collectionType, int size) { Class raw = collectionType.getWrappered(); try { if (collectionType.isArray()) { if (size < 0) size = 0; Object array = Array.newInstance(GenericUtils.getRawClass(collectionType.getComponentType()), size); return array; } else if (!Modifier.isAbstract(collectionType.getModifiers())) {// 非抽象集合 Object c = raw.newInstance(); return c; } else if (Object.class == raw || raw == List.class || raw == AbstractList.class) { return new ArrayList(); } else if (raw == Set.class || raw == AbstractSet.class) { return new HashSet(); } else if (raw == Map.class || raw == AbstractMap.class) { return new HashMap(); } else if (raw == Queue.class || raw == AbstractQueue.class) { return new LinkedList(); } else { throw new IllegalArgumentException("Unknown collection class for create:" + collectionType.getName()); } } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } /** * 两个集合对象的合并 * * @param <T> * @param a * 集合A * @param b * 集合B * @return */ public static <T> Collection<T> union(Collection<T> a, Collection<T> b) { HashSet<T> s = new HashSet<T>(a.size() + b.size()); s.addAll(a); s.addAll(b); return s; } /** * Return <code>true</code> if the supplied Collection is <code>null</code> * or empty. Otherwise, return <code>false</code>. * * @param collection * the Collection to check * @return whether the given Collection is empty */ public static boolean isEmpty(Collection<?> collection) { return (collection == null || collection.isEmpty()); } /** * Return <code>true</code> if the supplied Map is <code>null</code> or * empty. Otherwise, return <code>false</code>. * * @param map * the Map to check * @return whether the given Map is empty */ public static boolean isEmpty(Map<?, ?> map) { return (map == null || map.isEmpty()); } /** * Convert the supplied array into a List. A primitive array gets converted * into a List of the appropriate wrapper type. * <p> * A <code>null</code> source value will be converted to an empty List. * * @param source * the (potentially primitive) array * @return the converted List result * @see ObjectUtils#toObjectArray(Object) */ public static List<?> arrayToList(Object source) { return Arrays.asList(ArrayUtils.toObject(source)); } /** * Check whether the given Iterator contains the given element. * * @param iterator * the Iterator to check * @param element * the element to look for * @return <code>true</code> if found, <code>false</code> else */ public static boolean contains(Iterable<?> iterable, Object element) { if (iterable != null) { Iterator<?> iterator = iterable.iterator(); while (iterator.hasNext()) { Object candidate = iterator.next(); if (Objects.equal(candidate, element)) { return true; } } } return false; } /** * Check whether the given Enumeration contains the given element. * * @param enumeration * the Enumeration to check * @param element * the element to look for * @return <code>true</code> if found, <code>false</code> else */ public static boolean contains(Enumeration<?> enumeration, Object element) { if (enumeration != null) { while (enumeration.hasMoreElements()) { Object candidate = enumeration.nextElement(); if (Objects.equal(candidate, element)) { return true; } } } return false; } /** * Check whether the given Collection contains the given element instance. * <p> * Enforces the given instance to be present, rather than returning * <code>true</code> for an equal element as well. * * @param collection * the Collection to check * @param element * the element to look for * @return <code>true</code> if found, <code>false</code> else */ public static boolean fastContains(Collection<?> collection, Object element) { if (collection != null) { for (Object candidate : collection) { if (candidate == element) { return true; } } } return false; } /** * Return <code>true</code> if any element in '<code>candidates</code>' is * contained in '<code>source</code>'; otherwise returns <code>false</code>. * * @param source * the source Collection * @param candidates * the candidates to search for * @return whether any of the candidates has been found */ public static boolean containsAny(Collection<?> source, Collection<?> candidates) { if (isEmpty(source) || isEmpty(candidates)) { return false; } for (Object candidate : candidates) { if (source.contains(candidate)) { return true; } } return false; } /** * Find the common element type of the given Collection, if any.<br> * 如果集合中的元素都是同一类型,返回这个类型。如果集合中数据类型不同,返回null * * @param collection * the Collection to check * @return the common element type, or <code>null</code> if no clear common * type has been found (or the collection was empty) * */ public static Class<?> findCommonElementType(Collection<?> collection) { if (isEmpty(collection)) { return null; } Class<?> candidate = null; for (Object val : collection) { if (val != null) { if (candidate == null) { candidate = val.getClass(); } else if (candidate != val.getClass()) { return null; } } } return candidate; } /** * * Create a new identityHashSet. * * @return */ public static <E> Set<E> identityHashSet() { return Collections.newSetFromMap(new IdentityHashMap<E, Boolean>()); } /** * Iterator wrapping an Enumeration. */ private static class EnumerationIterator<E> implements Iterator<E> { private Enumeration<E> enumeration; public EnumerationIterator(Enumeration<E> enumeration) { this.enumeration = enumeration; } public boolean hasNext() { return this.enumeration.hasMoreElements(); } public E next() { return this.enumeration.nextElement(); } public void remove() throws UnsupportedOperationException { throw new UnsupportedOperationException("Not supported"); } } /** * 给定字段名称和值,比较目标的字段值 * * @author Administrator * @Date 2011-6-15 * @param <T> */ private static class FieldValueFilter<T> implements Function<T, Boolean> { private FieldEx field; private Object value; public FieldValueFilter(Class<?> clz, String fieldname, Object value) { ClassEx cw = new ClassEx(clz); this.field = cw.getField(fieldname); Assert.notNull(this.field, "the field " + fieldname + " is not found in class " + cw.getName()); this.value = value; } public Boolean apply(T input) { try { Object v = field.get(input); return Objects.equal(v, value); } catch (IllegalArgumentException e) { throw new IllegalAccessError(e.getMessage()); } } } /** * 获得集合的最后一个元素 * * @param collection * @return */ public static <T> T last(List<T> collection) { if (collection == null || collection.isEmpty()) { return null; } return collection.get(collection.size() - 1); } /** * 在List中的指定位置插入元素。如果超出当前长度,则将list扩展到指定长度。 * * @param list * List * @param index * 序号 * @param value * 值 */ public static <T> void setElement(List<T> list, int index, T value) { if (index == list.size()) { list.add(value); } else if (index > list.size()) { for (int i = list.size(); i < index; i++) { list.add(null); } list.add(value); } else { list.set(index, value); } } }