com.feilong.commons.core.util.CollectionsUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.feilong.commons.core.util.CollectionsUtil.java

Source

/*
 * Copyright (C) 2008 feilong (venusdrogon@163.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 com.feilong.commons.core.util;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.Predicate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.feilong.commons.core.bean.BeanUtilException;
import com.feilong.commons.core.bean.PropertyUtil;
import com.feilong.commons.core.entity.JoinStringEntity;
import com.feilong.commons.core.lang.ObjectUtil;

/**
 * {@link Collection} , {@link Collections} .<br>
 * 
 * <h3>{@link <a href="http://stamen.iteye.com/blog/2003458">SET-MAP</a>}</h3>
 * 
 * <blockquote>
 * <p>
 * <ul>
 * <li>?SetMap???</li>
 * <li>80%?hashCode,equals??</li>
 * <li>40%?Set???</li>
 * <li>20%?Map???</li>
 * </ul>
 * </p>
 * </blockquote>
 * 
 * @author <a href="mailto:venusdrogon@163.com"></a>
 * @version 1.0 Sep 2, 2010 8:08:40 PM
 * @since 1.0.0
 * @since jdk1.5
 */
public final class CollectionsUtil {

    /** The Constant log. */
    private static final Logger log = LoggerFactory.getLogger(CollectionsUtil.class);

    /** Don't let anyone instantiate this class. */
    private CollectionsUtil() {
        //AssertionError?. ?????. ???.
        //see Effective Java 2nd
        throw new AssertionError("No " + getClass().getName() + " instances for you!");
    }

    /**
     * ???.
     * 
     * @param <T>
     *            the generic type , {@link Serializable} ?
     * @param collection
     *            ?, ?,collection 
     * @param joinStringEntity
     *             
     * @return  collection isNullOrEmpty,null<br>
     *          joinStringEntity null, {@link JoinStringEntity#DEFAULT_CONNECTOR} <br>
     *         ?null,,joinStringEntity.getConnector()
     */
    // XXX ?
    public static final <T extends Serializable> String toString(final Collection<T> collection,
            final JoinStringEntity joinStringEntity) {

        if (Validator.isNotNullOrEmpty(collection)) {

            String connector = JoinStringEntity.DEFAULT_CONNECTOR;
            if (Validator.isNotNullOrEmpty(joinStringEntity)) {
                connector = joinStringEntity.getConnector();
            }

            StringBuilder sb = new StringBuilder();
            int i = 0;
            for (T t : collection) {
                sb.append(t);
                // 
                if (i < collection.size() - 1) {
                    sb.append(connector);
                }
                i++;
            }
            return sb.toString();
        }
        return null;
    }

    /**
     * ??.
     * 
     * @param <T>
     *            the generic type
     * @param collection
     *            ?
     * @return Enumeration
     * @see Collections#enumeration(Collection)
     */
    public static final <T> Enumeration<T> toEnumeration(final Collection<T> collection) {
        return Collections.enumeration(collection);
    }

    /**
     * ??.
     * 
     * @param <T>
     *            the generic type
     * @param enumeration
     *            the enumeration
     * @return if Validator.isNullOrEmpty(enumeration), return {@link Collections#emptyList()},emptyList???<br>
     *         else return {@link Collections#list(Enumeration)}
     * @see Collections#emptyList()
     * @see Collections#EMPTY_LIST
     * @see Collections#list(Enumeration)
     * @see org.apache.commons.collections.EnumerationUtils#toList(Enumeration)
     * @since 1.0.7
     * @since JDK 1.5
     */
    public static final <T> List<T> toList(final Enumeration<T> enumeration) {
        if (Validator.isNullOrEmpty(enumeration)) {
            return Collections.emptyList();
        }
        ArrayList<T> list = Collections.list(enumeration);
        return list;
    }

    /**
     * ??<br>
     * note:T , ??,???null.
     * 
     * @param <T>
     *            the generic type
     * @param collection
     *            collection
     * @return ,if Validator.isNullOrEmpty(collection),return null
     * @throws IllegalArgumentException
     *             list isNullOrEmpty
     * @see java.lang.reflect.Array#newInstance(Class, int)
     * @see java.lang.reflect.Array#newInstance(Class, int...)
     * @see java.util.Collection#toArray()
     * @see java.util.Collection#toArray(Object[])
     * @see java.util.List#toArray()
     * @see java.util.List#toArray(Object[])
     * @see java.util.Vector#toArray()
     * @see java.util.Vector#toArray(Object[])
     * @see java.util.LinkedList#toArray()
     * @see java.util.LinkedList#toArray(Object[])
     * @see java.util.ArrayList#toArray()
     * @see java.util.ArrayList#toArray(Object[])
     */
    public static <T> T[] toArray(Collection<T> collection) throws IllegalArgumentException {
        if (Validator.isNullOrEmpty(collection)) {
            return null;
        }

        //**********************************************************************
        Iterator<T> iterator = collection.iterator();

        T firstT = iterator.next();
        //list.get(0);
        //TODO ??
        if (Validator.isNullOrEmpty(firstT)) {
            throw new IllegalArgumentException("list's first item can't be null/empty!");
        }
        //**********************************************************************
        Class<?> compontType = firstT.getClass();

        int size = collection.size();

        @SuppressWarnings("unchecked")
        T[] tArray = (T[]) Array.newInstance(compontType, size);

        // alength0,???API??size,?.
        // ?alengthCollectionsize????API?.

        //?toArray(new Object[0])  toArray() ?. 
        return collection.toArray(tArray);
    }

    /**
     * ??, {@link com.feilong.commons.core.bean.PropertyUtil#getProperty(Object, String)}?,?List(ArrayList). <br>
     * ???,?,?,map,bean
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre>
     * List&lt;User&gt; testList = new ArrayList&lt;User&gt;();
     * 
     * User user;
     * UserInfo userInfo;
     * 
     * //*******************************************************
     * List&lt;UserAddress&gt; userAddresseList = new ArrayList&lt;UserAddress&gt;();
     * UserAddress userAddress = new UserAddress();
     * userAddress.setAddress(&quot;?&quot;);
     * userAddresseList.add(userAddress);
     * 
     * //*******************************************************
     * Map&lt;String, String&gt; attrMap = new HashMap&lt;String, String&gt;();
     * attrMap.put(&quot;&quot;, &quot;?&quot;);
     * attrMap.put(&quot;?&quot;, &quot;&quot;);
     * attrMap.put(&quot;?&quot;, &quot;&quot;);
     * 
     * //*******************************************************
     * String[] lovesStrings1 = { &quot;sanguo1&quot;, &quot;xiaoshuo1&quot; };
     * userInfo = new UserInfo();
     * userInfo.setAge(28);
     * 
     * user = new User(2L);
     * user.setLoves(lovesStrings1);
     * user.setUserInfo(userInfo);
     * user.setUserAddresseList(userAddresseList);
     * 
     * user.setAttrMap(attrMap);
     * testList.add(user);
     * 
     * //*****************************************************
     * String[] lovesStrings2 = { &quot;sanguo2&quot;, &quot;xiaoshuo2&quot; };
     * userInfo = new UserInfo();
     * userInfo.setAge(30);
     * 
     * user = new User(3L);
     * user.setLoves(lovesStrings2);
     * user.setUserInfo(userInfo);
     * user.setUserAddresseList(userAddresseList);
     * user.setAttrMap(attrMap);
     * testList.add(user);
     * 
     * //
     * List&lt;String&gt; fieldValueList1 = ListUtil.getFieldValueList(testList, &quot;loves[1]&quot;);
     * log.info(JsonUtil.format(fieldValueList1));
     * 
     * //?
     * List&lt;Integer&gt; fieldValueList2 = ListUtil.getFieldValueList(testList, &quot;userInfo.age&quot;);
     * log.info(JsonUtil.format(fieldValueList2));
     * 
     * //Map
     * List&lt;Integer&gt; attrList = ListUtil.getFieldValueList(testList, &quot;attrMap()&quot;);
     * log.info(JsonUtil.format(attrList));
     * 
     * //?
     * List&lt;String&gt; addressList = ListUtil.getFieldValueList(testList, &quot;userAddresseList[0]&quot;);
     * log.info(JsonUtil.format(addressList));
     * </pre>
     * 
     * </blockquote>
     * 
     * @param <T>
     *            ? generic type
     * @param <O>
     *            ? generic type
     * @param objectCollection
     *            ?
     * @param propertyName
     *            ??,Possibly indexed and/or nested name of the property to be extracted
     * @return ??,?,?List(ArrayList)
     * @throws NullPointerException
     *             if Validator.isNullOrEmpty(objectCollection) or Validator.isNullOrEmpty(propertyName)
     * @see com.feilong.commons.core.bean.BeanUtil#getProperty(Object, String)
     * @see org.apache.commons.beanutils.PropertyUtils#getProperty(Object, String)
     * @see #getPropertyValueCollection(Collection, String, Collection)
     * @since jdk1.5
     */
    public static <T, O> List<T> getPropertyValueList(Collection<O> objectCollection, String propertyName)
            throws NullPointerException {
        List<T> list = new ArrayList<T>();
        return getPropertyValueCollection(objectCollection, propertyName, list);
    }

    /**
     *  property value set.
     *
     * @param <T>
     *            the generic type
     * @param <O>
     *            the generic type
     * @param objectCollection
     *            the object collection
     * @param propertyName
     *            the property name
     * @return the property value set
     * @throws NullPointerException
     *             the null pointer exception
     * @see #getPropertyValueCollection(Collection, String, Collection)
     * @since 1.0.8
     */
    public static <T, O> Set<T> getPropertyValueSet(Collection<O> objectCollection, String propertyName)
            throws NullPointerException {
        Set<T> set = new LinkedHashSet<T>();
        return getPropertyValueCollection(objectCollection, propertyName, set);
    }

    /**
     * objectCollection, {@link PropertyUtil#getProperty(Object, String)}  propertyName <code>returnCollection</code> .
     *
     * @param <T>
     *            the generic type
     * @param <O>
     *            the generic type
     * @param <K>
     *            the key type
     * @param objectCollection
     *            the object collection
     * @param propertyName
     *            the property name
     * @param returnCollection
     *            the return collection
     * @return the property value collection
     * @throws NullPointerException
     *             if Validator.isNullOrEmpty(objectCollection) or Validator.isNullOrEmpty(propertyName) or (null == returnCollection)
     * @see com.feilong.commons.core.bean.PropertyUtil#getProperty(Object, String)
     * @since 1.0.8
     */
    private static <T, O, K extends Collection<T>> K getPropertyValueCollection(Collection<O> objectCollection,
            String propertyName, K returnCollection) throws NullPointerException {
        if (Validator.isNullOrEmpty(objectCollection)) {
            throw new NullPointerException("objectCollection is null or empty!");
        }

        if (Validator.isNullOrEmpty(propertyName)) {
            throw new NullPointerException("propertyName is null or empty!");
        }

        if (null == returnCollection) {
            throw new NullPointerException("returnCollection is null!");
        }

        try {
            for (O bean : objectCollection) {
                @SuppressWarnings("unchecked")
                T property = (T) PropertyUtil.getProperty(bean, propertyName);
                returnCollection.add(property);
            }
        } catch (BeanUtilException e) {
            log.error(e.getClass().getName(), e);
        }
        return returnCollection;
    }

    /**
     * Finds the first element in the given collection which matches the given predicate.
     * <p>
     * If the input collection or predicate is null, or no element of the collection matches the predicate, null is returned.
     * </p>
     *
     * @param <O>
     *            the generic type
     * @param <V>
     *            the value type
     * @param objectCollection
     *            the object collection
     * @param propertyName
     *            the property name
     * @param value
     *            the value
     * @return the first element of the collection which matches the predicate or null if none could be found
     * @throws NullPointerException
     *             the null pointer exception
     * @see org.apache.commons.collections.CollectionUtils#find(Collection, Predicate)
     */
    @SuppressWarnings("unchecked")
    public static <O, V> O find(Collection<O> objectCollection, String propertyName, V value)
            throws NullPointerException {
        Predicate predicate = getObjectEqualsPredicate(propertyName, value);
        return (O) org.apache.commons.collections.CollectionUtils.find(objectCollection, predicate);
    }

    /**
     * ?? <code>objectCollection</code>, bean propertyName  equals value list.
     *
     * @param <O>
     *            the generic type
     * @param <V>
     *            the value type
     * @param objectCollection
     *            the object list
     * @param propertyName
     *            the property name
     * @param value
     *            the value
     * @return the property value list
     * @throws NullPointerException
     *             if Validator.isNullOrEmpty(objectCollection) || Validator.isNullOrEmpty(propertyName)
     * @see org.apache.commons.collections.CollectionUtils#select(Collection, org.apache.commons.collections.Predicate)
     */
    public static <O, V> List<O> select(Collection<O> objectCollection, String propertyName, V value)
            throws NullPointerException {
        Object[] values = { value };
        return select(objectCollection, propertyName, values);
    }

    /**
     *  {@link PropertyUtil#getProperty(Object, String)}  <code>propertyName</code>? {@link ArrayUtil#isContain(Object[], Object)}
     *  <code>values</code>,list.
     *
     * @param <O>
     *            the generic type
     * @param <V>
     *            the value type
     * @param objectCollection
     *            the object collection
     * @param propertyName
     *            the property name
     * @param values
     *            the values
     * @return  {@link PropertyUtil#getProperty(Object, String)}  <code>propertyName</code>?
     *         {@link ArrayUtil#isContain(Object[], Object)}  <code>values</code>,list
     * @throws NullPointerException
     *             if Validator.isNullOrEmpty(objectCollection) || Validator.isNullOrEmpty(propertyName)
     */
    @SuppressWarnings("unchecked")
    public static <O, V> List<O> select(Collection<O> objectCollection, String propertyName, V... values)
            throws NullPointerException {
        if (Validator.isNullOrEmpty(objectCollection)) {
            throw new NullPointerException("objectCollection is null or empty!");
        }

        if (Validator.isNullOrEmpty(propertyName)) {
            throw new NullPointerException("propertyName is null or empty!");
        }
        Predicate predicate = getArrayContainsPredicate(propertyName, values);
        return (List<O>) org.apache.commons.collections.CollectionUtils.select(objectCollection, predicate);
    }

    /**
     *  {@link PropertyUtil#getProperty(Object, String)}  <code>propertyName</code>? {@link ArrayUtil#isContain(V[], V)} 
     * <code>values</code>.
     *
     * @param <V>
     *            the value type
     * @param propertyName
     *            the property name
     * @param values
     *            the values
     * @return the array predicate
     * @see com.feilong.commons.core.bean.PropertyUtil#getProperty(Object, String)
     * @see com.feilong.commons.core.util.ArrayUtil#isContain(V[], V)
     * @since 1.0.9
     */
    //@SafeVarargs
    private static <V> Predicate getArrayContainsPredicate(final String propertyName, final V... values) {
        Predicate predicate = new Predicate() {

            @Override
            public boolean evaluate(Object object) {
                V property = PropertyUtil.getProperty(object, propertyName);
                return ArrayUtil.isContain(values, property);
            }
        };
        return predicate;
    }

    /**
     *  object equals predicate.
     *
     * @param <V>
     *            the value type
     * @param propertyName
     *            the property name
     * @param value
     *            the value
     * @return the object equals predicate
     * @since 1.0.9
     */
    private static <V> Predicate getObjectEqualsPredicate(final String propertyName, final V value) {
        Predicate predicate = new Predicate() {

            @Override
            public boolean evaluate(Object object) {
                V property = PropertyUtil.getProperty(object, propertyName);
                return ObjectUtil.equals(property, value, true);
            }
        };
        return predicate;
    }

    /**
     * Select.
     *
     * @param <O>
     *            the generic type
     * @param objectCollection
     *            the object collection
     * @param predicate
     *            the predicate
     * @return the list< o>
     * @throws NullPointerException
     *             the null pointer exception
     */
    @SuppressWarnings("unchecked")
    public static <O> List<O> select(Collection<O> objectCollection, Predicate predicate)
            throws NullPointerException {
        if (Validator.isNullOrEmpty(objectCollection)) {
            throw new NullPointerException("objectCollection is null or empty!");
        }

        return (List<O>) org.apache.commons.collections.CollectionUtils.select(objectCollection, predicate);
    }

    /**
     * ?? <code>objectCollection</code> , bean propertyName ? equals value list.
     *
     * @param <O>
     *            the generic type
     * @param <V>
     *            the value type
     * @param objectCollection
     *            the object list
     * @param propertyName
     *            the property name
     * @param value
     *            the value
     * @return the property value list
     * @throws NullPointerException
     *             the null pointer exception
     * @see org.apache.commons.collections.CollectionUtils#selectRejected(Collection, org.apache.commons.collections.Predicate)
     */
    public static <O, V> List<O> selectRejected(Collection<O> objectCollection, String propertyName, V value)
            throws NullPointerException {
        Object[] values = { value };
        return selectRejected(objectCollection, propertyName, values);
    }

    /**
     * ?? <code>objectCollection</code> , bean propertyName  ?values list.
     *
     * @param <O>
     *            the generic type
     * @param <V>
     *            the value type
     * @param objectCollection
     *            the object collection
     * @param propertyName
     *            the property name
     * @param values
     *            the values
     * @return the list< o>
     * @throws NullPointerException
     *             the null pointer exception
     */
    @SuppressWarnings("unchecked")
    public static <O, V> List<O> selectRejected(Collection<O> objectCollection, String propertyName, V... values)
            throws NullPointerException {
        if (Validator.isNullOrEmpty(objectCollection)) {
            throw new NullPointerException("objectCollection is null or empty!");
        }

        if (Validator.isNullOrEmpty(propertyName)) {
            throw new NullPointerException("propertyName is null or empty!");
        }
        Predicate predicate = getArrayContainsPredicate(propertyName, values);
        return (List<O>) org.apache.commons.collections.CollectionUtils.selectRejected(objectCollection, predicate);
    }

    /**
     * ??, <code>keyPropertyName</code>key <code>valuePropertyName</code>?map
     * 
     * <br>
     *  {@link com.feilong.commons.core.bean.PropertyUtil#getProperty(Object, String)}?. <br>
     * ???,?,?,map,bean
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre>
     * List&lt;User&gt; testList = new ArrayList&lt;User&gt;();
     * testList.add(new User(&quot;&quot;, 23));
     * testList.add(new User(&quot;&quot;, 24));
     * testList.add(new User(&quot;&quot;, 25));
     * 
     * Map&lt;String, Integer&gt; map = CollectionsUtil.getFieldValueMap(testList, &quot;name&quot;, &quot;age&quot;);
     * 
     *  :
     * 
     * "": 24,
     * "": 23,
     * "": 25
     * </pre>
     * 
     * </blockquote>
     *
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param <O>
     *            ? generic type
     * @param objectCollection
     *            ?
     * @param keyPropertyName
     *            the key property name
     * @param valuePropertyName
     *            the value property name
     * @return ??,?,?List(ArrayList)
     * @throws NullPointerException
     *             if Validator.isNullOrEmpty(objectCollection) or Validator.isNullOrEmpty(propertyName) or
     *             Validator.isNullOrEmpty(valuePropertyName)
     * @see com.feilong.commons.core.bean.BeanUtil#getProperty(Object, String)
     * @see org.apache.commons.beanutils.PropertyUtils#getProperty(Object, String)
     * @since jdk1.5
     */
    public static <K, V, O> Map<K, V> getPropertyValueMap(Collection<O> objectCollection, String keyPropertyName,
            String valuePropertyName) throws NullPointerException {
        if (Validator.isNullOrEmpty(objectCollection)) {
            throw new NullPointerException("objectCollection is null or empty!");
        }

        if (Validator.isNullOrEmpty(keyPropertyName)) {
            throw new NullPointerException("keyPropertyName is null or empty!");
        }

        if (Validator.isNullOrEmpty(valuePropertyName)) {
            throw new NullPointerException("valuePropertyName is null or empty!");
        }

        Map<K, V> map = new LinkedHashMap<K, V>();

        try {
            for (O bean : objectCollection) {
                @SuppressWarnings("unchecked")
                K key = (K) PropertyUtil.getProperty(bean, keyPropertyName);
                @SuppressWarnings("unchecked")
                V value = (V) PropertyUtil.getProperty(bean, valuePropertyName);

                map.put(key, value);
            }
        } catch (BeanUtilException e) {
            log.error(e.getClass().getName(), e);
        }
        return map;
    }

    /**
     * Group (propertyName ?list? putmap).
     *
     * @param <T>
     *            ?T Object  ?excel?String???Integer? ??
     * @param <O>
     *            the generic type
     * @param objectCollection
     *            the object list
     * @param propertyName
     *            ????
     * @return the map< t, list< o>>
     * @throws BeanUtilException
     *             the bean util exception
     * @throws NullPointerException
     *             if Validator.isNullOrEmpty(propertyName)
     * @see com.feilong.commons.core.bean.PropertyUtil#getProperty(Object, String)
     * @see com.feilong.commons.core.util.ArrayUtil#group(O[], String)
     * @see #groupOne(Collection, String)
     * @since 1.0.8
     */
    public static <T, O> Map<T, List<O>> group(Collection<O> objectCollection, String propertyName)
            throws BeanUtilException, NullPointerException {

        if (Validator.isNullOrEmpty(objectCollection)) {
            throw new NullPointerException("objectCollection can't be null/empty!");
        }

        if (Validator.isNullOrEmpty(propertyName)) {
            throw new NullPointerException("the propertyName is null or empty!");
        }

        //  ??? HashMap TreeMap
        Map<T, List<O>> map = new LinkedHashMap<T, List<O>>(objectCollection.size());

        for (O o : objectCollection) {
            T t = PropertyUtil.getProperty(o, propertyName);
            List<O> valueList = map.get(t);
            if (null == valueList) {
                valueList = new ArrayList<O>();
            }
            valueList.add(o);
            map.put(t, valueList);
        }
        return map;
    }

    /**
     * Group count.
     *
     * @param <T>
     *            the generic type
     * @param <O>
     *            the generic type
     * @param objectCollection
     *            the object collection
     * @param propertyName
     *            the property name
     * @return the map< t, integer>
     * @throws BeanUtilException
     *             the bean util exception
     * @throws NullPointerException
     *             the null pointer exception
     */
    public static <T, O> Map<T, Integer> groupCount(Collection<O> objectCollection, String propertyName)
            throws BeanUtilException, NullPointerException {

        if (Validator.isNullOrEmpty(objectCollection)) {
            throw new NullPointerException("objectCollection can't be null/empty!");
        }

        if (Validator.isNullOrEmpty(propertyName)) {
            throw new NullPointerException("the propertyName is null or empty!");
        }

        Map<T, Integer> map = new LinkedHashMap<T, Integer>();

        for (O o : objectCollection) {
            T t = PropertyUtil.getProperty(o, propertyName);
            Integer count = map.get(t);
            if (null == count) {
                count = 0;
            }
            count = count + 1;
            map.put(t, count);
        }
        return map;
    }

    /**
     * Group one(map?put?).
     *
     * @param <T>
     *            the generic type
     * @param <O>
     *            the generic type
     * @param objectCollection
     *            the object collection
     * @param propertyName
     *            the property name
     * @return the map< t, o>
     * @throws BeanUtilException
     *             the bean util exception
     * @throws NullPointerException
     *             the null pointer exception
     * @see #group(Collection, String)
     * @since 1.0.8
     */
    public static <T, O> Map<T, O> groupOne(Collection<O> objectCollection, String propertyName)
            throws BeanUtilException, NullPointerException {

        if (Validator.isNullOrEmpty(objectCollection)) {
            throw new NullPointerException("objectCollection can't be null/empty!");
        }

        if (Validator.isNullOrEmpty(propertyName)) {
            throw new NullPointerException("the propertyName is null or empty!");
        }

        //  ??? HashMap TreeMap
        Map<T, O> map = new LinkedHashMap<T, O>(objectCollection.size());

        for (O o : objectCollection) {
            T t = PropertyUtil.getProperty(o, propertyName);
            O valueList = map.get(t);
            if (null == valueList) {
                map.put(t, o);
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("when propertyName:{},multiple value:{},Abandoned except the first value outside.",
                            propertyName, valueList);
                }
            }
        }
        return map;
    }

    /**
     * ?.
     *
     * @param <O>
     *            the generic type
     * @param objectCollection
     *            the object collection
     * @param scale
     *            ?
     * @param propertyNames
     *            ????
     * @return the map< string, list< o>>
     * @throws BeanUtilException
     *             the bean util exception
     * @throws NullPointerException
     *             the null pointer exception
     * @see #sum(Collection, String...)
     */
    public static <O> Map<String, Number> avg(Collection<O> objectCollection, int scale, String... propertyNames)
            throws BeanUtilException, NullPointerException {

        //
        Map<String, Number> sumMap = sum(objectCollection, propertyNames);

        int size = objectCollection.size();

        //  ??? HashMap TreeMap
        Map<String, Number> map = new LinkedHashMap<String, Number>(size);

        for (Map.Entry<String, Number> entry : sumMap.entrySet()) {
            String key = entry.getKey();
            Number value = entry.getValue();

            map.put(key, NumberUtil.getDivideValue(new BigDecimal(value.toString()), size, scale));
        }

        return map;
    }

    /**
     * ?.
     *
     * @param <O>
     *            the generic type
     * @param objectCollection
     *            the object collection
     * @param propertyNames
     *            the property names
     * @return the map< string, list< o>>
     * @throws BeanUtilException
     *             the bean util exception
     * @throws NullPointerException
     *             the null pointer exception
     */
    public static <O> Map<String, Number> sum(Collection<O> objectCollection, String... propertyNames)
            throws BeanUtilException, NullPointerException {

        if (Validator.isNullOrEmpty(objectCollection)) {
            throw new NullPointerException("objectCollection can't be null/empty!");
        }

        if (Validator.isNullOrEmpty(propertyNames)) {
            throw new NullPointerException("propertyNames is null or empty!");
        }

        //**************************************************************************
        int size = objectCollection.size();

        //
        Map<String, Number> sumMap = new LinkedHashMap<String, Number>(size);

        for (O o : objectCollection) {
            for (String propertyName : propertyNames) {

                //??
                Number propertyValue = PropertyUtil.getProperty(o, propertyName);

                //map
                Number mapPropertyNameValue = sumMap.get(propertyName);
                if (null == mapPropertyNameValue) {
                    mapPropertyNameValue = 0;
                }
                sumMap.put(propertyName, NumberUtil.getAddValue(mapPropertyNameValue, propertyValue));
            }
        }

        //**************************************************************************
        return sumMap;
    }
}