Java tutorial
/* * 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.feilong.core.util; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.Validate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.feilong.core.bean.PropertyUtil; import com.feilong.tools.jsonlib.JsonUtil; import static com.feilong.core.Validator.isNotNullOrEmpty; import static com.feilong.core.Validator.isNullOrEmpty; import static com.feilong.core.bean.ConvertUtil.toArray; /** * {@link Map}. * * <h3>hashCodeequals:</h3> * <blockquote> * * <p> * hashCode???<br> * {@link java.util.List List}??,???,; <br> * {@link java.util.HashMap HashMap}?{@link java.util.HashSet HashSet}? {@link java.util.Hashtable Hashtable} ,???. * </p> * * <p> * JavahashCode??equals,??,?,?? * </p> * <p> * <img src="http://venusdrogon.github.io/feilong-platform/mysource/hashCode-and-equals.jpg"/> * </p> * * ??: * <ol> * <li>hashcode?,?,?,,,equals</li> * <li>equals?,??,?</li> * </ol> * </blockquote> * * <h3> {@link java.util.Map }:</h3> * * <blockquote> * <table border="1" cellspacing="0" cellpadding="4" summary=""> * <tr style="background-color:#ccccff"> * <th align="left">interface/class</th> * <th align="left"></th> * </tr> * * <tr valign="top"> * <td>{@link java.util.Map Map}</td> * <td> * <ol> * <li>An object that maps keys to values.</li> * <li>A map cannot contain duplicate keys</li> * <li>Takes the place of the Dictionary class</li> * </ol> * </td> * </tr> * * <tr valign="top" style="background-color:#eeeeff"> * <td>{@link java.util.HashMap HashMap}</td> * <td> * <ol> * <li>Hash table based implementation of the Map interface.</li> * <li>permits null values and the null key.</li> * <li>makes no guarantees as to the order of the map</li> * </ol> * <p> * : * </p> * <blockquote> * <ol> * <li>{@link java.util.HashMap HashMap} ?? {@link java.util.HashMap#DEFAULT_INITIAL_CAPACITY }16,DEFAULT_LOAD_FACTOR 0.75 * <code>java.util.HashMap#addEntry</code> 2 * table.length 2?<br> * </ol> * </blockquote> * </td> * </tr> * * <tr valign="top"> * <td>{@link java.util.LinkedHashMap LinkedHashMap}</td> * <td> * <ol> * <li>Hash table and linked list implementation of the Map interface,</li> * <li>with predictable iteration order.</li> * </ol> * Note that: insertion order is not affected if a key is re-inserted into the map. * </td> * </tr> * * <tr valign="top" style="background-color:#eeeeff"> * <td>{@link java.util.TreeMap TreeMap}</td> * <td> * <ol> * <li>A Red-Black tree based NavigableMap implementation</li> * <li>sorted according to the natural ordering of its keys, or by a Comparator.</li> * <li> key?null, <code>NullComparator</code>key ?null.</li> * </ol> * </td> * </tr> * * <tr valign="top"> * <td>{@link java.util.Hashtable Hashtable}</td> * <td> * <ol> * <li>This class implements a hashtable, which maps keys to values.</li> * <li>synchronized.</li> * <li>Any non-null object can be used as a key or as a value.</li> * </ol> * </td> * </tr> * * <tr valign="top" style="background-color:#eeeeff"> * <td>{@link java.util.Properties Properties}</td> * <td> * <ol> * <li>The Properties class represents a persistent set of properties.</li> * <li>can be saved to a stream or loaded from a stream.</li> * <li>Each key and its corresponding value in the property list is a string.</li> * </ol> * </td> * </tr> * * <tr valign="top"> * <td>{@link java.util.IdentityHashMap IdentityHashMap}</td> * <td> * <ol> * <li>using reference-equality in place of object-equality when comparing keys (and values).</li> * <li>==equals()key.</li> * </ol> * <p style="color:red"> * ?:? Map ????? Map ??,?? * </p> * </td> * </tr> * * <tr valign="top" style="background-color:#eeeeff"> * <td>{@link java.util.WeakHashMap WeakHashMap}</td> * <td> * <ol> * <li>A hashtable-based Map implementation with weak keys.</li> * <li>key"",key??,key?GC</li> * </ol> * </td> * </tr> * * <tr valign="top"> * <td>{@link java.util.EnumMap EnumMap}</td> * <td> * <ol> * <li>A specialized Map implementation for use with enum type keys.</li> * <li>Enum maps are maintained in the natural order of their keys</li> * <li>??key</li> * </ol> * </td> * </tr> * </table> * </blockquote> * * @author <a href="http://feitianbenyue.iteye.com/">feilong</a> * @see java.util.AbstractMap.SimpleEntry * @see org.apache.commons.collections4.MapUtils * @see "com.google.common.collect.Maps" * @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!"); } /** * ?<code>arrayValueMap</code> ???map. * * <h3>:</h3> * <blockquote> * <ol> * <li>map ???? <code>arrayValueMap</code>key?key,value?<code>value</code></li> * <li> {@link LinkedHashMap},???? <code>arrayValueMap</code>??</li> * <li>?? {@link #toArrayValueMap(Map)}</li> * </ol> * </blockquote> * * <h3>1:</h3> * <blockquote> * * <pre class="code"> * Map{@code <String, String[]>} arrayValueMap = new LinkedHashMap{@code <String, String[]>}(); * * arrayValueMap.put("province", new String[] { "??" }); * arrayValueMap.put("city", new String[] { "?" }); * LOGGER.info(JsonUtil.format(ParamUtil.toSingleValueMap(arrayValueMap))); * </pre> * * <b>:</b> * * <pre class="code"> * { * "province": "??", * "city": "?" * } * </pre> * * </blockquote> * * <p> * arrayValueMapkey,?map,value?, * </p> * * <h3>2:</h3> * <blockquote> * * <pre class="code"> * Map{@code <String, String[]>} arrayValueMap = new LinkedHashMap{@code <String, String[]>}(); * * arrayValueMap.put("province", new String[] { "?", "??" }); * arrayValueMap.put("city", new String[] { "?" }); * LOGGER.info(JsonUtil.format(ParamUtil.toSingleValueMap(arrayValueMap))); * </pre> * * <b>:</b> * * <pre class="code"> * { * "province": "?", * "city": "?" * } * </pre> * * </blockquote> * * @param <K> * the key type * @param <V> * the value type * @param arrayValueMap * the array value map * @return <code>arrayValueMap</code>nullempty, {@link Collections#emptyMap()},<br> * <code>arrayValueMap</code>key,?map,value?,<br> * <code>arrayValueMap</code>keyvaluenull,?map,value null * @since 1.8.0 change type to generics */ public static <K, V> Map<K, V> toSingleValueMap(Map<K, V[]> arrayValueMap) { if (isNullOrEmpty(arrayValueMap)) { return Collections.emptyMap(); } Map<K, V> singleValueMap = newLinkedHashMap(arrayValueMap.size());//??? ? arrayValueMap ?? for (Map.Entry<K, V[]> entry : arrayValueMap.entrySet()) { singleValueMap.put(entry.getKey(), null == entry.getValue() ? null : entry.getValue()[0]); } return singleValueMap; } /** * ??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> * * <b>:</b> * * <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 (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(), toArray(entry.getValue()));//?Value???V,???Object } return arrayValueMap; } /** * <code>null != map null != value</code>?key/value putmap. * * <p> * <code>map</code> null,??<br> * <code>value</code> null,??<br> * <code>key</code> null,?<code>map</code><code>key</code>??null <br> * </p> * * @param <K> * the key type * @param <V> * the value type * @param map * the map to add to * @param key * the key * @param value * the value * @see org.apache.commons.collections4.MapUtils#safeAddToMap(Map, Object, Object) * @since 1.4.0 */ public static <K, V> void putIfValueNotNull(final Map<K, V> map, final K key, final V value) { if (null != map && null != value) { map.put(key, value); } } /** * Put all if not null. * * @param <K> * the key type * @param <V> * the value type * @param map * the map * @param m * mappings to be stored in this map * @see java.util.Map#putAll(Map) * @since 1.6.3 */ public static <K, V> void putAllIfNotNull(final Map<K, V> map, Map<? extends K, ? extends V> m) { if (null != map && null != m) { map.putAll(m);// m null } } /** * <code>null != map isNotNullOrEmpty(value)</code>?key/value putmap. * * <p> * <code>map</code> null,??<br> * <code>value</code> nullempty,??<br> * <code>key</code> null,?<code>map</code><code>key</code>??null <br> * </p> * * <p> * ?, * </p> * * <blockquote> * * <pre class="code"> * * if (isNotNullOrEmpty(taoBaoOAuthLoginForCodeEntity.getState())){ * nameAndValueMap.put("state", taoBaoOAuthLoginForCodeEntity.getState()); * } * * </pre> * * ???: * * <pre class="code"> * MapUtil.putIfValueNotNullOrEmpty(nameAndValueMap, "state", taoBaoOAuthLoginForCodeEntity.getState()); * </pre> * * </blockquote> * * @param <K> * the key type * @param <V> * the value type * @param map * the map * @param key * the key * @param value * the value * @since 1.6.3 */ public static <K, V> void putIfValueNotNullOrEmpty(final Map<K, V> map, final K key, final V value) { if (null != map && isNotNullOrEmpty(value)) { map.put(key, value); } } /** * <code>map</code><code>key</code>,<code>value</code>;?put. * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * * Map{@code <String, Integer>} map = new HashMap{@code <String, Integer>}(); * MapUtil.putSumValue(map, "1000001", 5); * MapUtil.putSumValue(map, "1000002", 5); * MapUtil.putSumValue(map, "1000002", 5); * LOGGER.debug(JsonUtil.format(map)); * * </pre> * * <b>:</b> * * <pre class="code"> * { * "1000001": 5, * "1000002": 10 * } * </pre> * * </blockquote> * * ?: * * <blockquote> * * <pre class="code"> * * if (disadvantageMap.containsKey(disadvantageToken)){ * disadvantageMap.put(disadvantageToken, disadvantageMap.get(disadvantageToken) + 1); * }else{ * disadvantageMap.put(disadvantageToken, 1); * } * * </pre> * * ???: * * <pre class="code"> * MapUtil.putSumValue(disadvantageMap, disadvantageToken, 1); * </pre> * * </blockquote> * * @param <K> * the key type * @param map * the map * @param key * the key * @param value * the value * @return <code>map</code> null, {@link NullPointerException}<br> * <code>value</code> null, {@link NullPointerException}<br> * @see org.apache.commons.collections4.bag.HashBag * @see org.apache.commons.lang3.mutable.MutableInt * @see "java.util.Map#getOrDefault(Object, Object)" * @see <a href="http://stackoverflow.com/questions/81346/most-efficient-way-to-increment-a-map-value-in-java">most-efficient-way-to- * increment-a-map-value-in-java</a> * @since 1.5.5 */ public static <K> Map<K, Integer> putSumValue(Map<K, Integer> map, K key, Integer value) { Validate.notNull(map, "map can't be null!"); Validate.notNull(value, "value can't be null!"); Integer v = map.get(key);//?? map.containsKey(key),?2 two potentially expensive operations map.put(key, null == v ? value : value + v);//Suggestion: you should care about code readability more than little performance gain in most of the time. return map; } /** * map put key value(?). * * <h3>:</h3> * <blockquote> * <ol> * <li>map????key,valuelist?.</li> * <li>map???key,ArrayList</li> * </ol> * </blockquote> * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * * Map{@code <String, List<String>>} mutiMap = newLinkedHashMap(2); * MapUtil.putMultiValue(mutiMap, "name", ""); * MapUtil.putMultiValue(mutiMap, "name", ""); * MapUtil.putMultiValue(mutiMap, "age", "30"); * * LOGGER.debug(JsonUtil.format(mutiMap)); * * </pre> * * <b>:</b> * * <pre class="code"> { "name": [ "", "" ], "age": ["30"] } * * </pre> * * </blockquote> * * <h3>??:</h3> * * <blockquote> * * <pre class="code"> * * private void putItemToMap(Map{@code <String, List<Item>>} map,String tagName,Item item){ * List{@code <Item>} itemList = map.get(tagName); * * if (isNullOrEmpty(itemList)){ * itemList = new ArrayList{@code <Item>}(); * } * itemList.add(item); * map.put(tagName, itemList); * } * * </pre> * * ???: * * <pre class="code"> * * private void putItemToMap(Map{@code <String, List<Item>>} map,String tagName,Item item){ * com.feilong.core.util.MapUtil.putMultiValue(map, tagName, item); * } * </pre> * * </blockquote> * * @param <K> * the key type * @param <V> * the value type * @param map * the map * @param key * the key * @param value * the value * @return <code>map</code> null, {@link NullPointerException}<br> * @see "com.google.common.collect.ArrayListMultimap" * @see org.apache.commons.collections4.MultiValuedMap * @see org.apache.commons.collections4.IterableMap * @see org.apache.commons.collections4.MultiMapUtils * @see org.apache.commons.collections4.multimap.AbstractMultiValuedMap#put(Object, Object) * @since 1.6.2 */ public static <K, V> Map<K, List<V>> putMultiValue(Map<K, List<V>> map, K key, V value) { Validate.notNull(map, "map can't be null!"); List<V> list = ObjectUtils.defaultIfNull(map.get(key), new ArrayList<V>()); list.add(value); map.put(key, list); return map; } /** * <code>map</code> <code>key</code> ??map. * * <p> * ?: key?map key?,mapkey,warn level log * </p> * * <p> * map {@link LinkedHashMap},key? ? <code>keys</code>? * </p> * * <h3>:</h3> * <blockquote> * * <pre class="code"> * Map{@code <String, Integer>} map = new HashMap{@code <String, Integer>}(); * map.put("a", 3007); * map.put("b", 3001); * map.put("c", 3001); * map.put("d", 3003); * LOGGER.debug(JsonUtil.format(MapUtil.getSubMap(map, "a", "c"))); * </pre> * * <b>:</b> * * <pre class="code"> * { * "a": 3007, * "c": 3001 * } * </pre> * * </blockquote> * * @param <K> * the key type * @param <T> * the generic type * @param map * the map * @param keys * key?map key?,mapkey,warn level log * @return <code>map</code> nullempty, {@link Collections#emptyMap()};<br> * <code>keys</code> nullempty, <code>map</code><br> * key?map key?,mapkey,warn level log */ @SafeVarargs public static <K, T> Map<K, T> getSubMap(Map<K, T> map, K... keys) { if (isNullOrEmpty(map)) { return Collections.emptyMap(); } if (isNullOrEmpty(keys)) { return map; } //??? ,key? ? <code>keys</code>? Map<K, T> returnMap = newLinkedHashMap(keys.length); for (K key : keys) { if (map.containsKey(key)) { returnMap.put(key, map.get(key)); } else { LOGGER.warn("map:[{}] don't contains key:[{}]", JsonUtil.format(map.keySet(), 0, 0), key); } } return returnMap; } /** * sub map(??keys). * * <p> * {@link LinkedHashMap},key? ? <code>map</code>? * </p> * * <h3>:</h3> * <blockquote> * * <pre class="code"> * Map{@code <String, Integer>} map = new LinkedHashMap{@code <String, Integer>}(); * * map.put("a", 3007); * map.put("b", 3001); * map.put("c", 3002); * map.put("g", -1005); * * LOGGER.debug(JsonUtil.format(MapUtil.getSubMapExcludeKeys(map, "a", "g", "m"))); * </pre> * * <b>:</b> * * <pre class="code"> * { * "b": 3001, * "c": 3002 * } * * </pre> * * </blockquote> * * <p> * <code>excludeKeys</code>? map ?key,warnlog * </p> * * @param <K> * the key type * @param <T> * the generic type * @param map * the map * @param excludeKeys * the keys * @return <code>map</code> nullempty, {@link Collections#emptyMap()};<br> * <code>excludeKeys</code> nullempty, <code>map</code> * @since 1.0.9 */ @SafeVarargs public static <K, T> Map<K, T> getSubMapExcludeKeys(Map<K, T> map, K... excludeKeys) { if (isNullOrEmpty(map)) { return Collections.emptyMap(); } return isNullOrEmpty(excludeKeys) ? map : removeKeys(new LinkedHashMap<K, T>(map), excludeKeys); //??? } /** * <code>map</code> <code>keys</code>. * * <h3>?</h3> * * <blockquote> * <p> * ??<code>map</code>, <code>keys</code>,<br> * <code>map</code>?key, {@link Map#remove(Object)},<br> * ??,warn * </p> * </blockquote> * * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * * Map{@code <String, String>} map = newLinkedHashMap(3); * * map.put("name", "feilong"); * map.put("age", "18"); * map.put("country", "china"); * * LOGGER.debug(JsonUtil.format(MapUtil.removeKeys(map, "country"))); * * </pre> * * <b>:</b> * * <pre class="code"> * { * "name": "feilong", * "age": "18" * } * * </pre> * * </blockquote> * * @param <K> * the key type * @param <V> * the value type * @param map * the map * @param keys * the keys * @return <code>map</code> null, {@link NullPointerException}<br> * @since 1.6.3 */ @SafeVarargs public static <K, V> Map<K, V> removeKeys(Map<K, V> map, K... keys) { Validate.notNull(map, "map can't be null!"); for (K key : keys) { if (map.containsKey(key)) { map.remove(key); } else { LOGGER.warn("map:[{}] don't contains key:[{}]", JsonUtil.format(map.keySet(), 0, 0), key); } } return map; } /** * <code>map</code> keyvalue. * * <p> * <span style="color:red">?map</span>.<br> * ?map,??key?value,map(key)?(value),??key * </p> * * <h3>:</h3> * <blockquote> * * <pre class="code"> * Map{@code <String, Integer>} map = new HashMap{@code <String, Integer>}(); * map.put("a", 3007); * map.put("b", 3001); * map.put("c", 3001); * map.put("d", 3003); * LOGGER.debug(JsonUtil.format(MapUtil.invertMap(map))); * </pre> * * <b>:</b> * * <pre class="code"> * { * "3001": "c", * "3007": "a", * "3003": "d" * } * </pre> * * ? b * * </blockquote> * * @param <K> * the key type * @param <V> * the value type * @param map * the map * @return <code>map</code> null, {@link NullPointerException}<br> * <code>map</code> empty, new HashMap * @see org.apache.commons.collections4.MapUtils#invertMap(Map) * @since 1.2.2 */ public static <K, V> Map<V, K> invertMap(Map<K, V> map) { return MapUtils.invertMap(map);// HashMap } /** * ? <code>map</code>keykey,? <code>map</code> value<code>extractPropertyName</code>,?map. * * <h3>:</h3> * <blockquote> * <ol> * <li>?,<code>map</code>? <code>includeKeys</code>, warn log</li> * <li>map?,? map key?</li> * </ol> * </blockquote> * * <h3>:</h3> * <blockquote> * * <pre class="code"> * Map{@code <Long, User>} map = new LinkedHashMap{@code <Long, User>}(); * map.put(1L, new User(100L)); * map.put(2L, new User(200L)); * map.put(5L, new User(500L)); * map.put(4L, new User(400L)); * * LOGGER.debug(JsonUtil.format(MapUtil.extractSubMap(map, "id"))); * </pre> * * <b>:</b> * * <pre class="code"> { "1": 100, "2": 200, "5": 500, "4": 400 } * </pre> * * </blockquote> * * @param <K> * the key type * @param <O> * the generic type * @param <V> * the generic type * @param map * the map * @param extractPropertyName * O??,Possibly indexed and/or nested name of the property to be modified,?? * <a href="../bean/BeanUtil.html#propertyName">propertyName</a> * @return <code>map</code> nullempty, {@link Collections#emptyMap()}<br> * <code>extractPropertyName</code> null, {@link NullPointerException}<br> * <code>extractPropertyName</code> blank, {@link IllegalArgumentException}<br> * @since 1.8.0 remove class param */ public static <K, O, V> Map<K, V> extractSubMap(Map<K, O> map, String extractPropertyName) { return extractSubMap(map, null, extractPropertyName); } /** * ? <code>map</code>keykey,? <code>map</code>value<code>extractPropertyName</code> * ,?map. * * <h3>:</h3> * <blockquote> * <ol> * <li>key? <code>includeKeys</code></li> * <li>?,<code>map</code>? <code>includeKeys</code>, warn log</li> * <li>? <code>includeKeys</code>null,?mapkey</li> * <li>map?,?includeKeys?(includeKeysnull,map key?)</li> * </ol> * </blockquote> * * <h3>:</h3> * <blockquote> * * <pre class="code"> * Map{@code <Long, User>} map = new LinkedHashMap{@code <Long, User>}(); * map.put(1L, new User(100L)); * map.put(2L, new User(200L)); * map.put(53L, new User(300L)); * map.put(5L, new User(500L)); * map.put(6L, new User(600L)); * map.put(4L, new User(400L)); * * Long[] includeKeys = { 5L, 4L }; * LOGGER.debug(JsonUtil.format(MapUtil.extractSubMap(map, includeKeys, "id"))); * </pre> * * <b>:</b> * * <pre class="code"> * { * "5": 500, * "4": 400 * } * </pre> * * </blockquote> * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * * private Map{@code <Long, Long>} constructPropertyIdAndItemPropertiesIdMap( * String properties, * Map{@code <Long, PropertyValueSubViewCommand>} itemPropertiesIdAndPropertyValueSubViewCommandMap){ * Long[] itemPropertiesIds = StoCommonUtil.toItemPropertiesIdLongs(properties); * * Map{@code <Long, Long>} itemPropertiesIdAndPropertyIdMap = MapUtil * .extractSubMap(itemPropertiesIdAndPropertyValueSubViewCommandMap, itemPropertiesIds, "propertyId"); * * return MapUtil.invertMap(itemPropertiesIdAndPropertyIdMap); * } * * </pre> * * </blockquote> * * @param <K> * the key type * @param <O> * the generic type * @param <V> * the value type * @param map * the map * @param includeKeys * the include keys * @param extractPropertyName * O??,Possibly indexed and/or nested name of the property to be modified,?? * <a href="../bean/BeanUtil.html#propertyName">propertyName</a> * @return <code>map</code> nullempty, {@link Collections#emptyMap()}<br> * <code>extractPropertyName</code> null, {@link NullPointerException}<br> * <code>extractPropertyName</code> blank, {@link IllegalArgumentException}<br> * <code>includeKeys</code> nullempty, then will extract map total keys<br> * @since 1.8.0 remove class param */ public static <K, O, V> Map<K, V> extractSubMap(Map<K, O> map, K[] includeKeys, String extractPropertyName) { if (isNullOrEmpty(map)) { return Collections.emptyMap(); } Validate.notBlank(extractPropertyName, "extractPropertyName can't be null/empty!"); //excludeKeysnull,?key @SuppressWarnings("unchecked") // NOPMD - false positive for generics K[] useIncludeKeys = isNullOrEmpty(includeKeys) ? (K[]) map.keySet().toArray() : includeKeys; //???,?? includeKeys? Map<K, V> returnMap = newLinkedHashMap(useIncludeKeys.length); for (K key : useIncludeKeys) { if (map.containsKey(key)) { returnMap.put(key, PropertyUtil.<V>getProperty(map.get(key), extractPropertyName)); } else { LOGGER.warn("map:[{}] don't contains key:[{}]", JsonUtil.format(map.keySet(), 0, 0), key); } } return returnMap; } //************************************************************************************************* /** * Creates a {@code HashMap} 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. It also can't be guaranteed that the * method isn't inadvertently <i>oversizing</i> the returned map. * * <h3>????:</h3> * <blockquote> * * <pre class="code"> * Map{@code <String, Map<Long, List<String>>>} map = new HashMap{@code <String, Map<Long, List<String>>>}(16); * </pre> * * JDK1.7,? : * * <pre class="code"> * Map{@code <String, Map<Long, List<String>>>} map = new HashMap{@code <>}(16); * </pre> * * ???1.5+,??: * * <pre class="code"> * Map{@code <String, Map<Long, List<String>>>} map = MapUtil.newHashMap(16); * </pre> * * </blockquote> * * @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 HashMap} with enough capacity to hold {@code expectedSize} entries without resizing * @see "com.google.common.collect.Maps#newHashMapWithExpectedSize(int)" * @see java.util.HashMap#HashMap(int) * @since 1.7.1 */ public static <K, V> HashMap<K, V> newHashMap(int expectedSize) { return new HashMap<K, V>(toInitialCapacity(expectedSize)); } /** * 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,?100,new 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 } }