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

Java tutorial

Introduction

Here is the source code for com.discovery.darchrow.util.MapUtil.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.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.collections.comparators.ReverseComparator;
import org.apache.commons.lang3.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.discovery.darchrow.bean.ConvertUtil;
import com.discovery.darchrow.util.comparator.PropertyComparator;

/**
 * {@link Map}.
 *
 * @author feilong
 * @version 1.0.0 Sep 8, 2012 8:02:44 PM
 * @see org.apache.commons.collections.MapUtils
 * @since 1.0.0
 */
public final class MapUtil {

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

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

    /**
     * ??map??map.
     * 
     * <p style="color:green">
     *  {@link LinkedHashMap},??? ? <code>singleValueMap</code>??
     * </p>
     * 
     * <p>
     * ?? {@link #toSingleValueMap(Map)}
     * </p>
     * 
     * <h3>:</h3>
     * <blockquote>
     * 
     * <pre class="code">
     * Map{@code <String, String>} singleValueMap = new LinkedHashMap{@code <String, String>}();
     * 
     * singleValueMap.put("province", "??");
     * singleValueMap.put("city", "?");
     * 
     * LOGGER.info(JsonUtil.format(ParamUtil.toArrayValueMap(singleValueMap)));
     * </pre>
     * 
     * :
     * 
     * <pre class="code">
     * {
     * "province": ["??"],
     * "city": ["?"]
     * }
     * </pre>
     * 
     * </blockquote>
     *
     * @param <K>
     *            the key type
     * @param singleValueMap
     *            the name and value map
     * @return ? <code>singleValueMap</code> nullempty, {@link Collections#emptyMap()}<br>
     *         ? <code>singleValueMap</code> value?, <code>arrayValueMap</code>
     * @since 1.6.2
     */
    public static <K> Map<K, String[]> toArrayValueMap(Map<K, String> singleValueMap) {
        if (Validator.isNullOrEmpty(singleValueMap)) {
            return Collections.emptyMap();
        }
        Map<K, String[]> arrayValueMap = newLinkedHashMap(singleValueMap.size());//????singleValueMap??
        for (Map.Entry<K, String> entry : singleValueMap.entrySet()) {
            arrayValueMap.put(entry.getKey(), ConvertUtil.toArray(entry.getValue()));//?Value???V,???Object
        }
        return arrayValueMap;
    }

    /**
     * ?keysvalue,?,valuenull or empty,??.
     *
     * @param map
     *            the map
     * @param includeKeys
     *            ?key
     * @return the mer data
     * @since 1.2.1
     */
    public static String joinKeysValue(Map<String, String> map, String[] includeKeys) {
        if (Validator.isNullOrEmpty(map)) {
            throw new NullPointerException("map can't be null/empty!");
        }
        StringBuilder sb = new StringBuilder();
        //??
        for (String key : includeKeys) {
            String value = map.get(key);

            //??,null?null
            if (Validator.isNotNullOrEmpty(value)) {
                sb.append(value);
            }
        }
        String merData = sb.toString();
        return merData;
    }

    /**
     *  map  key ??map.
     *
     * @param <K>
     *            the key type
     * @param <T>
     *            the generic type
     * @param map
     *            the map
     * @param keys
     *            key,key ?map key ? ,map key
     * @return the sub map<br>
     *         if (Validator.isNullOrEmpty(keys)) map<br>
     */
    public static <K, T> Map<K, T> getSubMap(Map<K, T> map, K[] keys) {
        if (Validator.isNullOrEmpty(map)) {
            throw new NullPointerException("the map is null or empty!");
        }
        if (Validator.isNullOrEmpty(keys)) {
            return map;
        }
        Map<K, T> returnMap = new HashMap<K, T>();

        for (K key : keys) {
            if (map.containsKey(key)) {
                returnMap.put(key, map.get(key));
            } else {
                LOGGER.warn("map don't contains key:[{}]", key);
            }
        }
        return returnMap;
    }

    /**
     *  sub map(??keys).
     *
     * @param <K>
     *            the key type
     * @param <T>
     *            the generic type
     * @param map
     *            the map
     * @param excludeKeys
     *            the keys
     * @return the sub map<br>
     *         if (Validator.isNullOrEmpty(keys)) map<br>
     * @since 1.0.9
     */
    public static <K, T> Map<K, T> getSubMapExcludeKeys(Map<K, T> map, K[] excludeKeys) {
        if (Validator.isNullOrEmpty(map)) {
            throw new NullPointerException("the map is null or empty!");
        }
        if (Validator.isNullOrEmpty(excludeKeys)) {
            return map;
        }

        Map<K, T> returnMap = new HashMap<K, T>(map);

        for (K key : excludeKeys) {
            if (map.containsKey(key)) {
                returnMap.remove(key);
            } else {
                LOGGER.warn("map don't contains key:[{}]", key);
            }
        }
        return returnMap;
    }

    //*******************************?****************************************************
    /**
     * Sort by key asc.
     *
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param map
     *            the map
     * @return the map< k, v>
     * @see java.util.TreeMap#TreeMap(Map)
     * @since 1.2.0
     */
    public static <K, V> Map<K, V> sortByKeyAsc(Map<K, V> map) {
        if (Validator.isNullOrEmpty(map)) {
            throw new NullPointerException("map can't be null/empty!");
        }
        return new TreeMap<K, V>(map);
    }

    /**
     * Sort by key desc.
     *
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param map
     *            the map
     * @return the map< k, v>
     * @see org.apache.commons.collections.comparators.ReverseComparator#ReverseComparator(Comparator)
     * @see PropertyComparator#PropertyComparator(String)
     * @since 1.2.0
     */
    @SuppressWarnings("unchecked")
    public static <K, V> Map<K, V> sortByKeyDesc(Map<K, V> map) {
        if (Validator.isNullOrEmpty(map)) {
            throw new NullPointerException("map can't be null/empty!");
        }
        return sort(map, new ReverseComparator(new PropertyComparator<Map.Entry<K, V>>("key")));
    }

    /**
     * ?value ???asc.
     *
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param map
     *            the map
     * @return the map< k, v>
     * @see PropertyComparator#PropertyComparator(String)
     * @see java.util.Map.Entry
     * @see #sortByValueDesc(Map)
     * @since 1.2.0
     */
    public static <K, V extends Comparable<V>> Map<K, V> sortByValueAsc(Map<K, V> map) {
        return sort(map, new PropertyComparator<Map.Entry<K, V>>("value"));
    }

    /**
     * ?value ???desc.
     *
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param map
     *            the map
     * @return the map< k, v>
     * @see org.apache.commons.collections.comparators.ReverseComparator#ReverseComparator(Comparator)
     * @see PropertyComparator#PropertyComparator(String)
     * @see java.util.Map.Entry
     * @see #sortByValueAsc(Map)
     * @since 1.2.0
     */
    @SuppressWarnings("unchecked")
    public static <K, V extends Comparable<V>> Map<K, V> sortByValueDesc(Map<K, V> map) {
        return sort(map, new ReverseComparator(new PropertyComparator<Map.Entry<K, V>>("value")));
    }

    /**
     *   {@link java.util.Map.Entry}  <code>mapEntryComparator</code> ? <code>map</code>?.
     * 
     * <p>
     * {@link java.util.Map.Entry}?, ?key??,?value??
     * </p>
     *
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param map
     *            the map
     * @param mapEntryComparator
     *             {@link java.util.Map.Entry}  {@link Comparator}
     * @return ??map
     * @since 1.2.0
     */
    public static <K, V> Map<K, V> sort(Map<K, V> map, Comparator<Map.Entry<K, V>> mapEntryComparator) {

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

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

        //**********************************************************

        final int size = map.size();
        List<Map.Entry<K, V>> mapEntryList = new ArrayList<Map.Entry<K, V>>(size);
        for (Map.Entry<K, V> entry : map.entrySet()) {
            mapEntryList.add(entry);
        }

        //**********************?************************************
        Collections.sort(mapEntryList, mapEntryComparator);

        //**********************************************************
        Map<K, V> returnMap = new LinkedHashMap<K, V>(size);

        for (Map.Entry<K, V> entry : mapEntryList) {
            K key = entry.getKey();
            V value = entry.getValue();
            returnMap.put(key, value);
        }

        return returnMap;
    }

    /**
     * Creates a {@code LinkedHashMap} instance, with a high enough "initial capacity" that it <i>should</i> hold {@code expectedSize}
     * elements without growth. This behavior cannot be broadly guaranteed, but it is observed to be true for OpenJDK 1.7. <br>
     * It also can't be guaranteed that the method isn't inadvertently <i>oversizing</i> the returned map.
     *
     * @param <K>
     *            the key type
     * @param <V>
     *            the value type
     * @param expectedSize
     *            the number of entries you expect to add to the returned map
     * @return a new, empty {@code LinkedHashMap} with enough capacity to hold {@code expectedSize} entries without resizing
     * @see "com.google.common.collect.Maps#newLinkedHashMapWithExpectedSize(int)"
     * @see java.util.LinkedHashMap#LinkedHashMap(int)
     * @since 1.7.1
     */
    public static <K, V> LinkedHashMap<K, V> newLinkedHashMap(int expectedSize) {
        return new LinkedHashMap<K, V>(toInitialCapacity(expectedSize));
    }

    /**
     * <code>size</code>? <code>initialCapacity</code> (for {@link java.util.HashMap}).
     * 
     * <p>
     * ?? hashmap size,??
     * </p>
     *
     * @param size
     *            map size
     * @return the int
     * @see <a href="http://www.iteye.com/topic/1134016">java hashmap?100new HashMap(?)why </a>
     * @see <a href=
     *      "http://stackoverflow.com/questions/30220820/difference-between-new-hashmapint-and-guava-maps-newhashmapwithexpectedsizein">
     *      Difference between new HashMap(int) and guava Maps.newHashMapWithExpectedSize(int)</a>
     * @see <a href="http://stackoverflow.com/questions/15844035/best-hashmap-initial-capacity-while-indexing-a-list">Best HashMap initial
     *      capacity while indexing a List</a>
     * @see java.util.HashMap#HashMap(Map)
     * @see "com.google.common.collect.Maps#capacity(int)"
     * @see java.util.HashMap#inflateTable(int)
     * @see org.apache.commons.collections4.map.AbstractHashedMap#calculateNewCapacity(int)
     * @since 1.7.1
     */
    private static int toInitialCapacity(int size) {
        Validate.isTrue(size >= 0, "size :[%s] must >=0", size);

        // google guava ,? guava ????
        //guava 19 (int) (expectedSize / 0.75F + 1.0F)
        //guava 18  expectedSize + expectedSize / 3
        //google-collections 1.0  Math.max(expectedSize * 2, 16)

        //This is the calculation used in JDK8 to resize when a putAll happens it seems to be the most conservative calculation we can make.  
        return (int) (size / 0.75f) + 1;//0.75 is the default load factor
    }
}