com.discovery.darchrow.util.CollectionsUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.discovery.darchrow.util.CollectionsUtil.java

Source

/*
 * Copyright (C) 2008 feilong
 *
 * 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.discovery.darchrow.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.discovery.darchrow.bean.BeanUtilException;
import com.discovery.darchrow.bean.PropertyUtil;
import com.discovery.darchrow.lang.ArrayUtil;
import com.discovery.darchrow.lang.NumberUtil;
import com.discovery.darchrow.lang.ToStringConfig;
import com.discovery.darchrow.tools.jsonlib.JsonUtil;
import com.discovery.darchrow.util.predicate.ArrayContainsPredicate;
import com.discovery.darchrow.util.predicate.ObjectPropertyEqualsPredicate;

/**
 * {@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 feilong
 * @version 1.0 Sep 2, 2010 8:08:40 PM
 * @since 1.0.0
 * @since jdk1.5
 */
public final class CollectionsUtil {

    /** The Constant LOGGER. */
    private static final Logger LOGGER = 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!");
    }

    /**
     *  <code>collection</code>   <code>remove</code>. ?,?(???)
     * <p>
     * The cardinality of an element <code>e</code> in the returned collection is the same as the cardinality of <code>e</code> in
     * <code>collection</code> unless <code>remove</code> contains <code>e</code>, in which case the cardinality is zero.
     * </p>
     * <p>
     * ?,? <code>collection</code>?,? <code>collection.removeAll(remove);</code>.
     * </p>
     * <p>
     *  {@link org.apache.commons.collections.ListUtils#removeAll(Collection, Collection)},?<code>removeElement</code>
     * list.
     * </p>
     * 
     * @param <T>
     *            the generic type
     * @param collection
     *            the collection from which items are removed (in the returned collection)
     * @param remove
     *            the items to be removed from the returned <code>collection</code>
     * @return a <code>List</code> containing all the elements of <code>c</code> except
     *         any elements that also occur in <code>remove</code>.
     * @see org.apache.commons.collections.ListUtils#removeAll(Collection, Collection)
     * @since Commons Collections 3.2
     * @since 1.0.8
     */
    @SuppressWarnings("unchecked")
    public static <T> List<T> removeAll(Collection<T> collection, Collection<T> remove) {
        return org.apache.commons.collections.ListUtils.removeAll(collection, remove);
    }

    /**
     *  <code>collection</code>  <code>removeElement</code>,?(???).
     * <p>
     * ?,? <code>collection</code>?,? <code>collection.remove(removeElement);</code>.
     * </p>
     * <p>
     *  {@link org.apache.commons.collections.ListUtils#removeAll(Collection, Collection)},?<code>removeElement</code>
     * list.
     * </p>
     * 
     * @param <T>
     *            the generic type
     * @param collection
     *            the collection from which items are removed (in the returned collection)
     * @param removeElement
     *            the remove element
     * @return a <code>List</code> containing all the elements of <code>c</code> except
     *         any elements that also occur in <code>remove</code>.
     * @see org.apache.commons.collections.ListUtils#removeAll(Collection, Collection)
     * @since Commons Collections 3.2
     * @since 1.0.8
     */
    public static <T> List<T> remove(Collection<T> collection, T removeElement) {
        Collection<T> remove = new ArrayList<T>();
        remove.add(removeElement);
        return removeAll(collection, remove);
    }

    /**
     * ?(collection?,?collection?).
     * 
     * @param <T>
     *            the generic type
     * @param collection
     *            the item src list
     * @return if Validator.isNullOrEmpty(collection) null<br>
     *         else  {@link ArrayList}
     * @see ArrayList#ArrayList(java.util.Collection)
     * @see LinkedHashSet#LinkedHashSet(Collection)
     * @see <a
     *      href="http://www.oschina.net/code/snippet_117714_2991?p=2#comments">http://www.oschina.net/code/snippet_117714_2991?p=2#comments</a>
     */
    public static <T> List<T> removeDuplicate(Collection<T> collection) {
        if (Validator.isNullOrEmpty(collection)) {
            return null;
        }
        // contains??.
        // 100Wlist0.546contains?.10W2??.
        // [foo1] 100000 -> 50487 : 48610 ms.
        // [foo2] 100000 -> 50487 : 47 ms.
        return new ArrayList<T>(new LinkedHashSet<T>(collection));
    }

    /**
     * ???.
     * 
     * @param <T>
     *            the generic type , {@link Serializable} ?
     * @param collection
     *            ?, ?,collection 
     * @param toStringConfig
     *             
     * @return  collection isNullOrEmpty,null<br>
     *          toStringConfig null, {@link ToStringConfig#DEFAULT_CONNECTOR} <br>
     *         ?null,,toStringConfig.getConnector()
     * @see com.baozun.nebulaplus.lang.ArrayUtil#toString(ToStringConfig, T...)
     */
    public static final <T extends Serializable> String toString(final Collection<T> collection,
            ToStringConfig toStringConfig) {
        if (Validator.isNullOrEmpty(collection)) {
            return null;
        }
        return ArrayUtil.toString(toStringConfig, toArray(collection));
    }

    /**
     * ??.
     * 
     * @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;
    }

    /**
     * ??.
     * 
     * <p style="color:red">
     * note:T , ??,???null.
     * </p>
     *
     * @param <T>
     *            the generic type
     * @param collection
     *            collection
     * @return ,if Validator.isNullOrEmpty(collection),return null
     * @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) {
        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.baozun.nebulaplus.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;);
     * LOGGER.info(JsonUtil.format(fieldValueList1));
     * 
     * //?
     * List&lt;Integer&gt; fieldValueList2 = ListUtil.getFieldValueList(testList, &quot;userInfo.age&quot;);
     * LOGGER.info(JsonUtil.format(fieldValueList2));
     * 
     * //Map
     * List&lt;Integer&gt; attrList = ListUtil.getFieldValueList(testList, &quot;attrMap()&quot;);
     * LOGGER.info(JsonUtil.format(attrList));
     * 
     * //?
     * List&lt;String&gt; addressList = ListUtil.getFieldValueList(testList, &quot;userAddresseList[0]&quot;);
     * LOGGER.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)
     * @see com.baozun.nebulaplus.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) {
        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
     * @see #getPropertyValueCollection(Collection, String, Collection)
     * @since 1.0.8
     */
    public static <T, O> Set<T> getPropertyValueSet(Collection<O> objectCollection, String propertyName) {
        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
     * @see com.baozun.nebulaplus.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) {
        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) {
            LOGGER.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
     * @see org.apache.commons.collections.CollectionUtils#find(Collection, Predicate)
     */
    @SuppressWarnings("unchecked")
    public static <O, V> O find(Collection<O> objectCollection, String propertyName, V value) {
        Predicate predicate = new ObjectPropertyEqualsPredicate(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
     * @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) {
        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
     */
    @SuppressWarnings("unchecked")
    public static <O, V> List<O> select(Collection<O> objectCollection, String propertyName, V... values) {
        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 = new ArrayContainsPredicate(propertyName, values);
        return (List<O>) org.apache.commons.collections.CollectionUtils.select(objectCollection, predicate);
    }

    /**
     * Select.
     *
     * @param <O>
     *            the generic type
     * @param objectCollection
     *            the object collection
     * @param predicate
     *            the predicate
     * @return the list< o>
     */
    @SuppressWarnings("unchecked")
    public static <O> List<O> select(Collection<O> objectCollection, Predicate predicate) {
        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
     * @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) {
        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>
     */
    @SuppressWarnings("unchecked")
    public static <O, V> List<O> selectRejected(Collection<O> objectCollection, String propertyName, V... values) {
        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 = new ArrayContainsPredicate(propertyName, values);
        return (List<O>) org.apache.commons.collections.CollectionUtils.selectRejected(objectCollection, predicate);
    }

    /**
     * ??, <code>keyPropertyName</code>key <code>valuePropertyName</code>?map<br>
     * 
     * <p>
     * ?: {@link LinkedHashMap}
     * </p>
     * <br>
     *  {@link com.baozun.nebulaplus.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)
     * @see com.baozun.nebulaplus.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) {
        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>();

        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);
        }
        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>>
     * @see com.baozun.nebulaplus.bean.PropertyUtil#getProperty(Object, String)
     * @see com.baozun.nebulaplus.lang.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) {
        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;
    }

    /**
     *  <code>objectCollection</code> {@code propertyName}.
     *
     * @param <T>
     *            the generic type
     * @param <O>
     *            the generic type
     * @param objectCollection
     *            the object collection
     * @param propertyName
     *            the property name
     * @return  {@link LinkedHashMap}
     */
    public static <T, O> Map<T, Integer> groupCount(Collection<O> objectCollection, String propertyName) {
        return groupCount(objectCollection, null, propertyName);
    }

    /**
     *  <code>objectCollection</code>,? ? <code>includePredicate</code> {@code propertyName}.
     *
     * @param <T>
     *            the generic type
     * @param <O>
     *            the generic type
     * @param objectCollection
     *            the object collection
     * @param includePredicate
     *            ? ? <code>includePredicate</code>null ?Object
     * @param propertyName
     *            the property name
     * @return the map< t, integer>
     * @since 1.2.0
     */
    public static <T, O> Map<T, Integer> groupCount(Collection<O> objectCollection, Predicate includePredicate,
            String propertyName) {
        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) {
            if (null != includePredicate) {
                //
                boolean continueFlag = !includePredicate.evaluate(o);

                if (continueFlag) {
                    continue;
                }
            }

            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>
     * @see #group(Collection, String)
     * @since 1.0.8
     */
    public static <T, O> Map<T, O> groupOne(Collection<O> objectCollection, String propertyName) {

        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 key = PropertyUtil.getProperty(o, propertyName);

            if (!map.containsKey(key)) {
                map.put(key, o);
            } else {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Abandoned except the first value outside,map:{},containsKey key:[{}],",
                            JsonUtil.format(map.keySet()), key);
                }
            }
        }
        return map;
    }

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

        //
        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>>
     */
    public static <O> Map<String, Number> sum(Collection<O> objectCollection, String... propertyNames) {

        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;
    }
}