org.omnaest.utils.structure.map.MapUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.omnaest.utils.structure.map.MapUtils.java

Source

/*******************************************************************************
 * Copyright 2011 Danny Kunz
 * 
 * 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 org.omnaest.utils.structure.map;

import java.io.PrintStream;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.commons.lang3.EnumUtils;
import org.apache.commons.lang3.StringUtils;
import org.omnaest.utils.assertion.Assert;
import org.omnaest.utils.structure.collection.set.SetUtils;
import org.omnaest.utils.structure.container.ByteArrayContainer;
import org.omnaest.utils.structure.element.KeyExtractor;
import org.omnaest.utils.structure.element.converter.ElementBidirectionalConverter;
import org.omnaest.utils.structure.element.converter.ElementConverter;
import org.omnaest.utils.structure.element.converter.ElementConverterElementToMapEntry;
import org.omnaest.utils.structure.element.converter.ElementConverterIdentity;
import org.omnaest.utils.structure.element.factory.Factory;
import org.omnaest.utils.structure.element.factory.FactoryParameterized;
import org.omnaest.utils.structure.element.factory.FactoryParameterizedSerializable;
import org.omnaest.utils.structure.element.factory.FactorySerializable;
import org.omnaest.utils.structure.element.factory.concrete.ArrayListFactory;
import org.omnaest.utils.structure.element.factory.concrete.LinkedHashSetFactory;
import org.omnaest.utils.structure.element.filter.ElementFilter;
import org.omnaest.utils.structure.iterator.IterableUtils;
import org.omnaest.utils.structure.map.adapter.MapToMapAdapter;
import org.omnaest.utils.structure.map.adapter.SortedMapToSortedMapAdapter;
import org.omnaest.utils.structure.map.decorator.LockingMapDecorator;
import org.omnaest.utils.structure.map.decorator.MapDecorator;
import org.omnaest.utils.structure.map.decorator.SortedMapDecorator;
import org.omnaest.utils.tuple.Tuple2;

/**
 * Helper class for {@link Map} operations.
 * 
 * @author Omnaest
 */
public class MapUtils {
    /* ********************************************** Classes/Interfaces ********************************************** */
    /**
     * A {@link MapElementMergeOperation} defines a {@link #merge(Object, Object, Map)} operation to merge {@link Map} elements into
     * a merged {@link Map} instance.
     * 
     * @author Omnaest
     * @param <K>
     * @param <V>
     */
    public static interface MapElementMergeOperation<K, V> {
        /**
         * Merge operation, which should implement the logic which merges the given key and value pair into the given mergedMap.
         * 
         * @param key
         * @param value
         * @param mergedMap
         */
        public void merge(K key, V value, Map<K, V> mergedMap);
    }

    /**
     * Converted to transform a given {@link Entry} of a {@link Map} to a single {@link List} element
     * 
     * @see #convert(Entry)
     * @author Omnaest
     * @param <TO>
     * @param <K>
     * @param <V>
     */
    public static interface MapEntryToElementConverter<TO, K, V> extends ElementConverter<Entry<K, V>, TO> {
        /**
         * Converts a {@link Entry} of a {@link Map} to a single element for a {@link List}
         * 
         * @param entry
         * @return
         */
        @Override
        public TO convert(Entry<K, V> entry);
    }

    /* ********************************************** Methods ********************************************** */

    /**
     * Merges all given {@link Map} instances into a single {@link LinkedHashMap} using the given {@link MapElementMergeOperation}.
     * 
     * @see #mergeAll(Map...)
     * @see #mergeAll(Collection, MapElementMergeOperation)
     * @param <K>
     * @param <V>
     * @param mapElementMergeOperation
     * @param maps
     * @return
     */
    public static <K, V> Map<K, V> mergeAll(MapElementMergeOperation<K, V> mapElementMergeOperation,
            Map<? extends K, ? extends V>... maps) {
        return MapUtils.mergeAll(Arrays.asList(maps), mapElementMergeOperation);
    }

    private MapUtils() {
        super();
    }

    /**
     * Merges all given {@link Map} instances into a single {@link LinkedHashMap} using the given {@link MapElementMergeOperation}.
     * 
     * @see #mergeAll(Map...)
     * @param <K>
     * @param <V>
     * @param mapCollection
     * @param mapElementMergeOperation
     * @return
     */
    public static <K, V> Map<K, V> mergeAll(Collection<Map<? extends K, ? extends V>> mapCollection,
            MapElementMergeOperation<K, V> mapElementMergeOperation) {
        //
        final Map<K, V> retmap = new LinkedHashMap<K, V>();

        //
        if (mapCollection != null && mapElementMergeOperation != null) {
            for (Map<? extends K, ? extends V> map : mapCollection) {
                if (map != null) {
                    for (K key : map.keySet()) {
                        //
                        V value = map.get(key);

                        //
                        mapElementMergeOperation.merge(key, value, retmap);
                    }
                }
            }
        }

        //
        return retmap;
    }

    /**
     * Merges all given {@link Map} instances into a single {@link LinkedHashMap}.
     * 
     * @see #mergeAll(Map...)
     * @param <K>
     * @param <V>
     * @param mapCollection
     * @return
     */
    public static <K, V> Map<K, V> mergeAll(Collection<Map<K, V>> mapCollection) {
        //
        Map<K, V> retmap = new LinkedHashMap<K, V>();

        //
        for (Map<K, V> map : mapCollection) {
            retmap.putAll(map);
        }

        //
        return retmap;
    }

    /**
     * Merges all given {@link Map} instances into a single {@link LinkedHashMap}.
     * 
     * @see #mergeAll(Collection)
     * @see #mergeAll(Collection, MapElementMergeOperation)
     * @param <K>
     * @param <V>
     * @param maps
     * @return
     */
    public static <K, V> Map<K, V> mergeAll(Map<K, V>... maps) {
        return MapUtils.mergeAll(Arrays.asList(maps));
    }

    /**
     * Similar to {@link #mergeAllValuesIntoList(Collection)}
     * 
     * @param maps
     * @return
     */
    public static <K, V> Map<K, List<V>> mergeAllValuesIntoList(Map<K, V>... maps) {
        return mergeAllValuesIntoList(Arrays.asList(maps));
    }

    /**
     * Merges multiple {@link Map} instances whereby multiple values for the same key are merged into a {@link List}
     * 
     * @param mapCollection
     * @return
     */
    public static <K, V> Map<K, List<V>> mergeAllValuesIntoList(Collection<Map<K, V>> mapCollection) {
        Map<K, List<V>> retmap = new LinkedHashMap<K, List<V>>();

        final Map<K, List<V>> initializedMap = initializedValueListMap(retmap);
        for (Map<K, V> map : mapCollection) {
            for (K key : map.keySet()) {
                initializedMap.get(key).add(map.get(key));
            }
        }

        return retmap;
    }

    /**
     * Similar to {@link #mergeAllMultiValuesIntoList(Collection)}
     * 
     * @param maps
     * @return
     */
    public static <K, V> Map<K, List<V>> mergeAllMultiValuesIntoList(Map<K, ? extends Collection<V>>... maps) {
        return mergeAllMultiValuesIntoList(Arrays.asList(maps));
    }

    /**
     * Similar to {@link #mergeAllMultiValuesIntoSet(Collection)}
     * 
     * @param maps
     * @return
     */
    public static <K, V> Map<K, Set<V>> mergeAllMultiValuesIntoSet(Map<K, ? extends Collection<V>>... maps) {
        return mergeAllMultiValuesIntoSet(Arrays.asList(maps));
    }

    /**
     * Similar to {@link #mergeAllValuesIntoList(Collection)} but merges the elements of the values which are from any
     * {@link Collection} type into an {@link ArrayList}
     * 
     * @param mapCollection
     * @return
     */
    public static <K, V> Map<K, List<V>> mergeAllMultiValuesIntoList(
            Collection<Map<K, ? extends Collection<V>>> mapCollection) {
        Map<K, List<V>> retmap = new LinkedHashMap<K, List<V>>();

        final Map<K, List<V>> initializedMap = initializedValueListMap(retmap);
        for (Map<K, ? extends Collection<V>> map : mapCollection) {
            for (K key : map.keySet()) {
                initializedMap.get(key).addAll(map.get(key));
            }
        }

        return retmap;
    }

    /**
     * Similar to {@link #mergeAllValuesIntoList(Collection)} but merges the elements of the values which are from any
     * {@link Collection} type into a {@link LinkedHashSet}
     * 
     * @param mapCollection
     * @return
     */
    public static <K, V> Map<K, Set<V>> mergeAllMultiValuesIntoSet(
            Collection<Map<K, ? extends Collection<V>>> mapCollection) {
        Map<K, Set<V>> retmap = new LinkedHashMap<K, Set<V>>();

        final Map<K, Set<V>> initializedMap = initializedValueSetMap(retmap);
        for (Map<K, ? extends Collection<V>> map : mapCollection) {
            for (K key : map.keySet()) {
                initializedMap.get(key).addAll(map.get(key));
            }
        }

        return retmap;
    }

    /**
     * Similar to {@link #mergeAllValuesIntoSet(Collection)}
     * 
     * @param maps
     * @return
     */
    public static <K, V> Map<K, Set<V>> mergeAllValuesIntoSet(Map<K, V>... maps) {
        return mergeAllValuesIntoSet(Arrays.asList(maps));
    }

    /**
     * Merges multiple {@link Map} instances whereby multiple values for the same key are merged into a {@link Set}
     * 
     * @param mapCollection
     * @return
     */
    public static <K, V> Map<K, Set<V>> mergeAllValuesIntoSet(Collection<Map<K, V>> mapCollection) {
        Map<K, Set<V>> retmap = new LinkedHashMap<K, Set<V>>();

        final Map<K, Set<V>> initializedMap = initializedValueSetMap(retmap);
        for (Map<K, V> map : mapCollection) {
            for (K key : map.keySet()) {
                initializedMap.get(key).add(map.get(key));
            }
        }

        return retmap;
    }

    /**
     * Returns a {@link Map} with the matching keys and the respective value instances within a of {@link Tuple2} wrapper, which has
     * always the value of the first map and the value of the second map. Only the keys which are contained in both {@link Map}s
     * will be returned.
     * 
     * @param <K>
     * @param <VA>
     * @param <VB>
     * @param mapA
     * @param mapB
     * @return
     */
    public static <K, VA, VB> Map<K, Tuple2<VA, VB>> innerJoinMapByKey(Map<K, VA> mapA, Map<K, VB> mapB) {
        //
        final Map<K, Tuple2<VA, VB>> retmap = new LinkedHashMap<K, Tuple2<VA, VB>>();

        //
        if (mapA != null && mapB != null) {
            //
            for (K key : mapA.keySet()) {
                if (mapB.containsKey(key)) {
                    //
                    VA valueA = mapA.get(key);
                    VB valueB = mapB.get(key);

                    //
                    retmap.put(key, new Tuple2<VA, VB>(valueA, valueB));
                }
            }
        }

        //
        return retmap;
    }

    /**
     * Returns a new {@link MapJoiner} instance
     * 
     * @return
     */
    public static MapJoiner joiner() {
        return new MapJoiner();
    }

    /**
     * Returns a new {@link Map} instance with converted keys using the given {@link ElementConverter}
     * 
     * @see #convertMap(Map, ElementConverter, ElementConverter)
     * @see #convertMapValue(Map, ElementConverter)
     * @param <KeyFrom>
     * @param <KeyTo>
     * @param <Value>
     * @param map
     * @param keyElementConverter
     * @return new ordered {@link Map}
     */
    public static <KeyFrom, KeyTo, Value> Map<KeyTo, Value> convertMapKey(
            Map<? extends KeyFrom, ? extends Value> map, ElementConverter<KeyFrom, KeyTo> keyElementConverter) {
        return MapUtils.convertMap(map, keyElementConverter, new ElementConverterIdentity<Value>());
    }

    /**
     * Returns a new {@link Map} instance with all values converted using the given {@link ElementConverter}
     * 
     * @see #convertMapKey(Map, ElementConverter)
     * @see #convertMap(Map, ElementConverter, ElementConverter)
     * @param <Key>
     * @param <ValueFrom>
     * @param <ValueTo>
     * @param map
     * @param valueElementConverter
     * @return new ordered {@link Map}
     */
    public static <Key, ValueFrom, ValueTo> Map<Key, ValueTo> convertMapValue(
            Map<? extends Key, ? extends ValueFrom> map,
            ElementConverter<ValueFrom, ValueTo> valueElementConverter) {
        return MapUtils.convertMap(map, new ElementConverterIdentity<Key>(), valueElementConverter);
    }

    /**
     * Returns a new {@link Map} instance with converted keys and values using the given {@link ElementConverter}s
     * 
     * @see #convertMapKey(Map, ElementConverter)
     * @see #convertMapValue(Map, ElementConverter)
     * @see ElementConverter
     * @param map
     * @param keyElementConverter
     * @param valueElementConverter
     * @return new ordered {@link Map}
     */
    public static <KeyFrom, KeyTo, ValueFrom, ValueTo> Map<KeyTo, ValueTo> convertMap(
            Map<? extends KeyFrom, ? extends ValueFrom> map, ElementConverter<KeyFrom, KeyTo> keyElementConverter,
            ElementConverter<ValueFrom, ValueTo> valueElementConverter) {
        //
        Map<KeyTo, ValueTo> retmap = null;

        //
        if (map != null && keyElementConverter != null && valueElementConverter != null) {
            //
            retmap = new LinkedHashMap<KeyTo, ValueTo>(map.size());

            //
            for (KeyFrom keyFrom : map.keySet()) {
                KeyTo keyTo = keyElementConverter.convert(keyFrom);
                ValueTo valueTo = valueElementConverter.convert(map.get(keyFrom));

                retmap.put(keyTo, valueTo);
            }

        }

        //
        return retmap;
    }

    /**
     * Similar to {@link #convertMap(Map, ElementConverter, ElementConverter)} using a single {@link ElementConverter} for an
     * {@link Entry}
     * 
     * @param map
     *          {@link Map}
     * @param entryElementConverter
     *          {@link ElementConverter}
     * @return new {@link Map} instance
     */
    @SuppressWarnings("unchecked")
    public static <KeyFrom, KeyTo, ValueFrom, ValueTo> Map<KeyTo, ValueTo> convertMap(
            Map<? extends KeyFrom, ? extends ValueFrom> map,
            ElementConverter<Entry<KeyFrom, ValueFrom>, Entry<KeyTo, ValueTo>> entryElementConverter) {
        //
        Map<KeyTo, ValueTo> retmap = null;

        //
        if (map != null && entryElementConverter != null) {
            //
            retmap = new LinkedHashMap<KeyTo, ValueTo>(map.size());

            //
            for (Entry<? extends KeyFrom, ? extends ValueFrom> entry : map.entrySet()) {
                //
                Entry<KeyTo, ValueTo> convertedEntry = entryElementConverter
                        .convert((Entry<KeyFrom, ValueFrom>) entry);

                final KeyTo keyTo = convertedEntry.getKey();
                final ValueTo valueTo = convertedEntry.getValue();
                retmap.put(keyTo, valueTo);
            }

        }

        //
        return retmap;
    }

    /**
     * Similar to {@link #printMapHierarchical(PrintStream, Map)} but returning a {@link String} value
     * 
     * @param map
     * @return
     */
    public static <K, V> String toStringUsingHierarchy(Map<K, V> map) {
        //
        final ByteArrayContainer byteArrayContainer = new ByteArrayContainer();

        //
        final PrintStream printStream = byteArrayContainer.getPrintStreamWriter();
        printMapHierarchical(printStream, map);

        //
        return byteArrayContainer.toString();
    }

    /**
     * Returns a {@link String} representation for a {@link Map}
     * 
     * @param map
     * @return
     */
    public static <K, V> String toString(Map<K, V> map) {
        //
        StringBuilder retval = new StringBuilder();

        //
        if (map != null) {
            //
            retval.append("[\n");

            //
            Iterator<Entry<K, V>> iterator = map.entrySet().iterator();
            while (iterator != null && iterator.hasNext()) {
                try {
                    Entry<K, V> entry = iterator.next();
                    retval.append("  " + entry.toString() + "\n");
                } catch (Exception e) {
                }
            }

            //
            retval.append("]");
        }

        //
        return retval.toString();
    }

    /**
     * Transforms a given {@link Map} to a {@link List} using the given {@link MapEntryToElementConverter} to create single elements
     * for the {@link List} based on the {@link Entry}s of the given {@link Map}
     * 
     * @param map
     * @param mapEntryToElementConverter
     * @return {@link List}
     */
    public static <TO, K, V> List<TO> toList(Map<K, V> map,
            MapEntryToElementConverter<TO, K, V> mapEntryToElementConverter) {
        //
        List<TO> retlist = new ArrayList<TO>();

        //
        if (map != null && mapEntryToElementConverter != null) {
            for (Entry<K, V> entry : map.entrySet()) {
                retlist.add(mapEntryToElementConverter.convert(entry));
            }
        }

        //
        return retlist;
    }

    /**
     * Returns a new filtered {@link Map} instance. All keys of the given {@link Map} are filtered using the given
     * {@link ElementFilter}
     * 
     * @see #filteredMap(Map, Iterable)
     * @param map
     * @param keyElementFilter
     * @return
     */
    public static <K, V> Map<K, V> filteredMap(Map<K, V> map, ElementFilter<K> keyElementFilter) {
        Set<K> filterKeySet = SetUtils.filter(map.keySet(), keyElementFilter);
        return filteredMap(map, filterKeySet);
    }

    /**
     * Filters a given {@link Map} by its keys. Only keys which are contained within the given key {@link Iterable} will be
     * returned.
     * 
     * @see #filteredMap(Map, ElementFilter)
     * @param map
     * @param filterKeyIterable
     * @return new {@link LinkedHashMap} instance
     */
    public static <K, V> Map<K, V> filteredMap(Map<K, V> map, Iterable<K> filterKeyIterable) {
        //
        Map<K, V> retmap = new LinkedHashMap<K, V>();

        //
        if (map != null && filterKeyIterable != null) {
            //
            for (K key : filterKeyIterable) {
                //
                if (map.containsKey(key)) {
                    retmap.put(key, map.get(key));
                }
            }
        }

        //
        return retmap;
    }

    /**
     * Filters a given {@link Map} by values which are null. Only keys which have a value not null will be retained.
     * 
     * @param map
     * @return new {@link LinkedHashMap} instance
     */
    public static <K, V> Map<K, V> filteredMapExcludingNullValues(Map<K, V> map) {
        //
        Map<K, V> retmap = new LinkedHashMap<K, V>();

        //
        if (map != null) {
            //
            for (Entry<K, V> entry : map.entrySet()) {
                if (entry.getValue() != null) {
                    retmap.put(entry.getKey(), entry.getValue());
                }
            }
        }

        //
        return retmap;
    }

    /**
     * Prints out a given {@link Map} using {@link String#valueOf(Object)} and all submaps indented to a new column.<br>
     * <br>
     * Example:<br>
     * 
     * <pre>
     * -+
     *  |-- valueDouble=1.234
     *  |-+ testClassCopy
     *  | |-- valueDouble=5.678
     *  | |-- testClassCopy=null
     *  | |-- privateField=privateValue0.16433438667207334
     *  | |-+ future
     *  | | |-- countDownLatch=java.util.concurrent.CountDownLatch@1f4384c2[Count = 1]
     *  | | |-- shouldCancel=false
     *  | | |-- isCancelled=false
     *  | | |-- value=null
     *  | | |-- clazz=org.omnaest.utils.structure.element.FutureSimple
     * </pre>
     * 
     * @param printStream
     * @param map
     */
    public static void printMapHierarchical(final PrintStream printStream, @SuppressWarnings("rawtypes") Map map) {
        //
        class MapPrinter {
            @SuppressWarnings("rawtypes")
            public void printMap(Map map, int indentation) {
                if (map != null) {
                    String indentationString = StringUtils.repeat(" |", indentation / 2);
                    printStream.append(indentation == 0 ? indentationString + "-+\n" : "");
                    for (Object key : map.keySet()) {
                        //
                        Object value = map.get(key);

                        //
                        if (value instanceof Map) {
                            //
                            printStream.append(indentationString + " |-+ " + String.valueOf(key) + "\n");
                            this.printMap((Map) value, indentation + 2);
                        } else {
                            //
                            printStream.append(indentationString + " |-- " + String.valueOf(key) + "="
                                    + String.valueOf(map.get(key)) + "\n");
                        }
                    }
                    printStream.append(indentationString + "\n");
                }
            }
        }

        //
        new MapPrinter().printMap(map, 0);
    }

    /**
     * Returns a view of the given {@link Map} using the given {@link Lock} to synchronize all of its methods
     * 
     * @see #lockedByReentrantLock(Map)
     * @param map
     * @param lock
     * @return
     */
    public static <K, V> Map<K, V> locked(Map<K, V> map, Lock lock) {
        return new LockingMapDecorator<K, V>(map, lock);
    }

    /**
     * Returns a view of the given {@link Map} using a new {@link ReentrantLock} instance to synchronize all of its methods
     * 
     * @see #locked(Map, Lock)
     * @param map
     * @return
     */
    public static <K, V> Map<K, V> lockedByReentrantLock(Map<K, V> map) {
        Lock lock = new ReentrantLock();
        return locked(map, lock);
    }

    /**
     * Returns the inverted {@link Map} for the given one.<br>
     * <br>
     * The given {@link Map} has to be <b>bidirectional</b>, which means that the key value pairs inverted into value to key pairs
     * have unique values, too.<br>
     * <br>
     * If the given {@link Map} reference is null, null is returned.<br>
     * <br>
     * For non bidirectional {@link Map}s use {@link #invert(Map)} instead. <br>
     * <br>
     * If a given {@link Map} has some non unique values the first occurring value wins and all further values are dropped.
     * 
     * @param map
     * @return {@link LinkedHashMap}
     */
    public static <K, V> Map<V, K> invertedBidirectionalMap(final Map<? extends K, ? extends V> map) {
        //
        final Map<V, K> retmap = map == null ? null : new LinkedHashMap<V, K>();

        //
        if (retmap != null) {
            //
            for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
                //
                final K key = entry.getKey();
                final V value = entry.getValue();

                //
                if (!retmap.containsKey(value)) {
                    retmap.put(value, key);
                }
            }
        }

        //
        return retmap;
    }

    /**
     * Returns the inverted {@link Map} for the given one. If the given {@link Map} reference is null, null is returned.<br>
     * <br>
     * Since Multiple key of the original {@link Map} can be mapped to the same value, the inverted {@link Map} will contain a
     * {@link Set} of original key values per original value. <br>
     * <br>
     * For bidirectional {@link Map}s consider using {@link #invertedBidirectionalMap(Map)}
     * 
     * @param map
     * @return {@link LinkedHashMap} and {@link LinkedHashSet}
     */
    public static <K, V> Map<V, Set<K>> invert(final Map<? extends K, ? extends V> map) {
        //
        final Map<V, Set<K>> retmap = map == null ? null : new LinkedHashMap<V, Set<K>>();

        //
        if (retmap != null) {
            //
            for (Entry<? extends K, ? extends V> entry : map.entrySet()) {
                //
                final K key = entry.getKey();
                final V value = entry.getValue();

                //
                if (!retmap.containsKey(value)) {
                    retmap.put(value, new LinkedHashSet<K>());
                }

                //
                retmap.get(value).add(key);
            }
        }

        //
        return retmap;
    }

    /**
     * Returns an {@link EnumMap} filled with all available values of the given {@link Enum} type as keys and the result of the
     * {@link Factory} as value for each {@link Enum} key.
     * 
     * @param enumType
     * @param factory
     * @return {@link EnumMap}
     */
    public static <K extends Enum<K>, V> EnumMap<K, V> initializedEnumMap(Class<K> enumType, Factory<V> factory) {
        //    
        final EnumMap<K, V> retmap = enumType != null ? new EnumMap<K, V>(enumType) : null;

        //
        if (retmap != null) {
            for (K key : EnumUtils.getEnumList(enumType)) {
                V value = factory != null ? factory.newInstance() : null;
                retmap.put(key, value);
            }
        }

        //
        return retmap;
    }

    /**
     * Similar to {@link #initializeMap(Map, Iterable, Factory, boolean)} but does not overwrite values of already existing keys.
     * 
     * @param map
     * @param keyIterable
     * @param valueFactory
     */
    public static <K, V> void initializeMap(Map<K, V> map, Iterable<K> keyIterable, Factory<V> valueFactory) {
        boolean overwriteValuesOfExistingKeys = false;
        initializeMap(map, keyIterable, valueFactory, overwriteValuesOfExistingKeys);
    }

    /**
     * Initializes the given {@link Map} for all keys from the key {@link Iterable} with values created by the value
     * {@link Factory#newInstance()} method. If the overwrite values of existing keys flag is set to true, any value of an already
     * existing key is overwritten.
     * 
     * @see #initializedMap(Map, Factory)
     * @param map
     * @param keyIterable
     * @param valueFactory
     * @param overwriteValuesOfExistingKeys
     */
    public static <K, V> void initializeMap(Map<K, V> map, Iterable<K> keyIterable, Factory<V> valueFactory,
            boolean overwriteValuesOfExistingKeys) {
        //
        if (map != null && keyIterable != null && valueFactory != null) {
            //
            final Set<K> keySet = SetUtils.valueOf(keyIterable);
            if (!overwriteValuesOfExistingKeys) {
                keySet.removeAll(map.keySet());
            }

            //
            for (K key : keySet) {
                map.put(key, valueFactory.newInstance());
            }
        }
    }

    /**
     * Similar to {@link #initializedMap(Map, Factory)} using a new {@link LinkedHashMap} instance
     * 
     * @param valueFactory
     * @return
     */
    public static <K, V> Map<K, V> initializedMap(final Factory<V> valueFactory) {
        Map<K, V> map = new LinkedHashMap<K, V>();
        return initializedMap(map, valueFactory);
    }

    /**
     * Similar to {@link #initializedMap(Map, FactoryParameterized)} using a new {@link LinkedHashMap} instance
     * 
     * @param valueFactory
     * @return
     */
    public static <K, V> Map<K, V> initializedMap(final FactoryParameterized<V, K> valueFactory) {
        Map<K, V> map = new LinkedHashMap<K, V>();
        return initializedMap(map, valueFactory);
    }

    /**
     * Returns a {@link MapDecorator} which ensures that all {@link Map#get(Object)} invocations with a valid key type will return a
     * value. If the underlying {@link Map} would return a null value the value {@link Factory#newInstance()} is invoked and the new
     * value is stored within the {@link Map}.<br>
     * <br>
     * This is e.g. useful for scenarios where a {@link Map} contains a {@link Collection} as value and the {@link Collection}
     * should always be present.<br>
     * <br>
     * Be aware of the fact, that {@link Map#containsKey(Object)} will still return false for any non existing key.
     * 
     * @see #initializeMap(Map, Iterable, Factory)
     * @param map
     * @param valueFactory
     * @return {@link Map} decorator
     */
    public static <K, V> Map<K, V> initializedMap(Map<K, V> map, final Factory<V> valueFactory) {
        Assert.isNotNull(valueFactory, "Factory must be not null");
        Assert.isNotNull(map, "Map must be not null");
        return new MapDecorator<K, V>(map) {
            private static final long serialVersionUID = -2028575193912665021L;

            @SuppressWarnings("unchecked")
            @Override
            public V get(Object key) {
                //
                V value = super.get(key);

                //
                if (value == null) {
                    value = valueFactory.newInstance();
                    this.put((K) key, value);
                }

                //
                return value;
            }

        };
    }

    /**
     * Short form of {@link #initializedMap(Factory)} using an {@link ArrayListFactory}
     * 
     * @return
     */
    public static <K, V> Map<K, List<V>> initializedValueListMap() {
        return initializedMap(new ArrayListFactory<V>());
    }

    /**
     * Short form of {@link #initializedMap(Factory)} using an {@link ArrayListFactory}
     * 
     * @param map
     *          underlying {@link Map}
     * @return
     */
    public static <K, V> Map<K, List<V>> initializedValueListMap(Map<K, List<V>> map) {
        return initializedMap(map, new ArrayListFactory<V>());
    }

    /**
     * Short form of {@link #initializedMap(Factory)} using an {@link LinkedHashSetFactory}
     * 
     * @return
     */
    public static <K, V> Map<K, Set<V>> initializedValueSetMap() {
        return initializedMap(new LinkedHashSetFactory<V>());
    }

    /**
     * Short form of {@link #initializedMap(Factory)} using an {@link LinkedHashSetFactory}
     * 
     * @param map
     *          underlying {@link Map}
     * @return
     */
    public static <K, V> Map<K, Set<V>> initializedValueSetMap(Map<K, Set<V>> map) {
        return initializedMap(map, new LinkedHashSetFactory<V>());
    }

    /**
     * Returns a {@link MapDecorator} which ensures that all {@link Map#get(Object)} invocations with a valid key type will return a
     * value. If the underlying {@link Map} would return a null value the value {@link FactoryParameterized#newInstance(Object)}
     * with the key as argument is invoked and the new value is stored within the {@link Map}.<br>
     * <br>
     * This is e.g. useful for scenarios where a {@link Map} contains a {@link Collection} as value and the {@link Collection}
     * should always be present.<br>
     * <br>
     * Be aware of the fact, that {@link Map#containsKey(Object)} will still return false for any non existing key.
     * 
     * @see #initializeMap(Map, Iterable, Factory)
     * @see #initializedMap(Map, Factory)
     * @param map
     * @param valueFactory
     *          {@link FactoryParameterized}
     * @return {@link Map} decorator
     */
    public static <K, V> Map<K, V> initializedMap(Map<K, V> map, final FactoryParameterized<V, K> valueFactory) {
        Assert.isNotNull(valueFactory, "Factory must be not null");
        Assert.isNotNull(map, "Map must be not null");
        return new MapDecorator<K, V>(map) {
            private static final long serialVersionUID = -9085868697374650245L;

            @SuppressWarnings("unchecked")
            @Override
            public V get(Object keyObject) {
                //
                V value = super.get(keyObject);

                //
                if (value == null) {
                    //
                    final K key = (K) keyObject;
                    value = valueFactory.newInstance(key);
                    this.put(key, value);
                }

                //
                return value;
            }

        };
    }

    /**
     * Similar to {@link #defaultValueMap(Map, FactoryParameterized)}
     * 
     * @see #initializedMap(FactoryParameterized)
     * @param map
     * @param defaultValue
     * @return
     */
    public static <K, V> Map<K, V> defaultValueMap(Map<K, V> map, final V defaultValue) {
        return defaultValueMap(map, new FactoryParameterizedSerializable<V, K>() {
            private static final long serialVersionUID = 19870987L;

            @Override
            public V newInstance(K parameterMap) {
                return defaultValue;
            }
        });
    }

    /**
     * Returns a {@link Map} which always returns a value prodcued by the given factory if the value would have be null
     * 
     * @see #initializedMap(Map, FactoryParameterized)
     * @param map
     * @param valueFactory
     * @return
     */
    public static <K, V> Map<K, V> defaultValueMap(Map<K, V> map, final FactoryParameterized<V, K> valueFactory) {
        return new MapDecorator<K, V>(map) {
            private static final long serialVersionUID = -9083838697374650245L;

            @SuppressWarnings("unchecked")
            @Override
            public V get(Object keyObject) {
                //
                V value = super.get(keyObject);

                //
                if (value == null) {
                    //
                    final K key = (K) keyObject;
                    value = valueFactory.newInstance(key);
                }

                //
                return value;
            }

        };
    }

    /**
     * Similar to {@link #initializedMap(Map, Factory)} but for any {@link SortedMap} instance
     * 
     * @param sortedMap
     * @param valueFactory
     * @return {@link SortedMap} decorator
     */
    public static <K, V> SortedMap<K, V> initializedSortedMap(SortedMap<K, V> sortedMap,
            final Factory<V> valueFactory) {
        Assert.isNotNull(valueFactory, "Factory must be not null");
        Assert.isNotNull(sortedMap, "Map must be not null");
        return new SortedMapDecorator<K, V>(sortedMap) {
            @SuppressWarnings("unchecked")
            @Override
            public V get(Object key) {
                //
                V value = super.get(key);

                //
                if (value == null) {
                    value = valueFactory.newInstance();
                    this.put((K) key, value);
                }

                //
                return value;
            }
        };
    }

    /**
     * Returns the value of the first key within a {@link Map} which matches a given regular expression.<br>
     * <br>
     * 
     * <pre>
     * MapUtils.getValueByRegex( null, anyRegex ) = null
     * MapUtils.getValueByRegex( map, null ) = null
     * MapUtils.getValueByRegex( map, regex ) = value for first key matching the regex
     * MapUtils.getValueByRegex( map, ".*" ) = first value of the map for {@link LinkedHashMap}, random value for {@link HashMap}
     * 
     * </pre>
     * 
     * <br>
     * Example:
     * 
     * <pre>
     * //
     * final Map&lt;String, String&gt; map = new LinkedHashMap&lt;String, String&gt;();
     * map.put( &quot;key1&quot;, &quot;value1&quot; );
     * map.put( &quot;key2&quot;, &quot;value2&quot; );
     * map.put( &quot;thisKey&quot;, &quot;value3&quot; );
     * 
     * //
     * String regex = &quot;this.*&quot;;
     * String value = MapUtils.getValueByRegex( map, regex );
     * 
     * //
     * assertEquals( &quot;value3&quot;, value );
     * </pre>
     * 
     * @param map
     * @param regex
     * @return
     */
    public static <E> E getValueByRegex(Map<String, ? extends E> map, String regex) {
        //
        E retval = null;

        //
        if (map != null) {
            //
            retval = map.get(regex);

            //
            if (retval == null) {
                //
                for (String key : map.keySet()) {
                    if (key != null && key.matches(regex)) {
                        retval = map.get(key);
                        break;
                    }
                }
            }
        }

        //
        return retval;
    }

    /**
     * Returns the first {@link Entry} of a given {@link Map} or null if the {@link Map} reference is null or the {@link Map} is
     * empty
     * 
     * @see #lastEntry(Map)
     * @see #entryAt(Map, int)
     * @param map
     * @return
     */
    public static <K, V> Entry<K, V> firstEntry(Map<K, V> map) {
        //    
        Entry<K, V> retval = null;

        //
        if (map != null && !map.isEmpty()) {
            retval = IterableUtils.firstElement(map.entrySet());
        }

        //
        return retval;
    }

    /**
     * Returns the last {@link Entry} of the given {@link Map}. If the given {@link Map} reference is null or the {@link Map} is
     * empty, null will be returned.
     * 
     * @see #firstEntry(Map)
     * @see #entryAt(Map, int)
     * @param map
     * @return
     */
    public static <K, V> Entry<K, V> lastEntry(Map<K, V> map) {
        //    
        Entry<K, V> retval = null;

        //
        if (map != null && !map.isEmpty()) {
            retval = IterableUtils.lastElement(map.entrySet());
        }

        //
        return retval;
    }

    /**
     * Returns the {@link Entry} at the given index position of the given {@link Map}. If null is given as {@link Map} null will be
     * returned. If the index position is invalid null is returned, too.
     * 
     * @see #firstEntry(Map)
     * @see #lastEntry(Map)
     * @param map
     * @param indexPosition
     * @return
     */
    public static <K, V> Entry<K, V> entryAt(Map<K, V> map, int indexPosition) {
        //
        Entry<K, V> retval = map != null ? IterableUtils.elementAt(map.entrySet(), indexPosition) : null;
        return retval;
    }

    /**
     * Similar to {@link #valueOf(KeyExtractor, Iterable)}
     * 
     * @param keyExtractor
     *          {@link KeyExtractor}
     * @param values
     * @return
     */
    public static <K, V> Map<K, V> valueOf(KeyExtractor<? extends K, V> keyExtractor, V... values) {
        return valueOf(keyExtractor, Arrays.asList(values));
    }

    /**
     * Returns a new {@link Map} instance for the given {@link Iterable} using the given {@link KeyExtractor} to extract every key
     * one by one from the {@link Iterable}
     * 
     * @param keyExtractor
     *          {@link KeyExtractor}
     * @param iterable
     *          {@link Iterable}
     * @return new {@link Map}
     */
    public static <K, V> Map<K, V> valueOf(KeyExtractor<? extends K, V> keyExtractor,
            Iterable<? extends V> iterable) {
        //
        final Map<K, V> retmap = new LinkedHashMap<K, V>();

        //
        if (keyExtractor != null && iterable != null) {
            for (V element : iterable) {
                //
                K key = keyExtractor.extractKey(element);
                retmap.put(key, element);
            }
        }

        //
        return retmap;
    }

    /**
     * Similar to {@link #valueOfMultiple(KeyExtractor, Iterable)}
     * 
     * @param keyExtractor
     * @param values
     * @return
     */
    public static <K, V> Map<K, List<V>> valueOfMultiple(KeyExtractor<? extends K, V> keyExtractor, V... values) {
        return valueOfMultiple(keyExtractor, Arrays.asList(values));
    }

    /**
     * Similar to {@link #valueOf(KeyExtractor, Iterable)} but allows to generate multiple values for the same key
     * 
     * @param keyExtractor
     *          {@link KeyExtractor}
     * @param iterable
     *          {@link Iterable}
     * @return
     */
    public static <K, V> Map<K, List<V>> valueOfMultiple(KeyExtractor<? extends K, V> keyExtractor,
            Iterable<? extends V> iterable) {
        //
        final Map<K, List<V>> retmap = new LinkedHashMap<K, List<V>>();

        //
        if (keyExtractor != null && iterable != null) {
            final Map<K, List<V>> initializedRetmap = initializedValueListMap(retmap);
            for (V element : iterable) {
                //
                K key = keyExtractor.extractKey(element);
                initializedRetmap.get(key).add(element);
            }
        }

        //
        return retmap;
    }

    /**
     * Returns a new {@link Map} instance for the given {@link Iterable} using the {@link ElementConverterElementToMapEntry}
     * instance to convert every element to an {@link Entry}
     * 
     * @param iterable
     * @param elementToMapEntryTransformer
     * @return
     */
    public static <K, V, E> Map<K, V> valueOf(Iterable<E> iterable,
            ElementConverterElementToMapEntry<E, K, V> elementToMapEntryTransformer) {
        //
        final Map<K, V> retmap = new LinkedHashMap<K, V>();

        //
        if (iterable != null && elementToMapEntryTransformer != null) {
            for (E element : iterable) {
                //
                Entry<K, V> entry = elementToMapEntryTransformer.convert(element);
                if (entry != null) {
                    retmap.put(entry.getKey(), entry.getValue());
                }
            }
        }

        //
        return retmap;
    }

    /**
     * Returns a new {@link MapComposite} instance for the given {@link Map}s
     * 
     * @param maps
     * @return
     */
    public static <K, V> Map<K, V> composite(Map<K, V>... maps) {
        return new MapComposite<K, V>(maps);
    }

    /**
     * Returns a new {@link MapComposite} instance for the given {@link Map}s
     * 
     * @param mapList
     * @return
     */
    public static <K, V> Map<K, V> composite(List<Map<K, V>> mapList) {
        return new MapComposite<K, V>(mapList);
    }

    /**
     * Returns a {@link MapToMapAdapter} for the given source {@link Map}
     * 
     * @param sourceMap
     *          {@link Map}
     * @param elementBidirectionalConverterKey
     *          {@link ElementBidirectionalConverter}
     * @param elementBidirectionalConverterValue
     *          {@link ElementBidirectionalConverter}
     * @return new {@link MapToMapAdapter} instance
     */
    public static <KEY_FROM, VALUE_FROM, KEY_TO, VALUE_TO> Map<KEY_TO, VALUE_TO> adapter(
            Map<KEY_FROM, VALUE_FROM> sourceMap,
            ElementBidirectionalConverter<KEY_FROM, KEY_TO> elementBidirectionalConverterKey,
            ElementBidirectionalConverter<VALUE_FROM, VALUE_TO> elementBidirectionalConverterValue) {
        return new MapToMapAdapter<KEY_FROM, VALUE_FROM, KEY_TO, VALUE_TO>(sourceMap,
                elementBidirectionalConverterKey, elementBidirectionalConverterValue);
    }

    /**
     * Returns a {@link SortedMapToSortedMapAdapter} for the given source {@link SortedMap}
     * 
     * @param sourceMap
     *          {@link SortedMap}
     * @param elementBidirectionalConverterValue
     *          {@link ElementBidirectionalConverter}
     * @return new {@link SortedMapToSortedMapAdapter} instance
     */
    public static <KEY, VALUE_FROM, VALUE_TO> SortedMap<KEY, VALUE_TO> adapter(SortedMap<KEY, VALUE_FROM> sourceMap,
            ElementBidirectionalConverter<VALUE_FROM, VALUE_TO> elementBidirectionalConverterValue) {
        return new SortedMapToSortedMapAdapter<KEY, VALUE_FROM, VALUE_TO>(sourceMap,
                elementBidirectionalConverterValue);
    }

    /**
     * Similar to {@link #parseString(String, String, String)}
     * 
     * @param content
     * @return
     */
    public static Map<String, String> parseString(String content) {
        final String entityDelimiterRegEx = null;
        final String keyValueDelimiterRegEx = null;
        return parseString(content, entityDelimiterRegEx, keyValueDelimiterRegEx);
    }

    /**
     * Parses a given text into a {@link LinkedHashMap} instance. <br>
     * <br>
     * Example:<br>
     * 
     * <pre>
     * key1=value1;key2=value2
     * </pre>
     * 
     * would be parsed into a {@link Map} with the keys "key1" and "key2" and "key1" would have the value "value1" and similar for
     * "key2". <br>
     * <br>
     * 
     * @param content
     * @param entityDelimiterRegEx
     *          defaults to ";" or "|"
     * @param keyValueDelimiterRegEx
     *          defaults to "=" or ":"
     * @return
     */
    public static Map<String, String> parseString(String content, String entityDelimiterRegEx,
            String keyValueDelimiterRegEx) {
        final Map<String, String> retmap = new LinkedHashMap<String, String>();

        if (content != null) {
            entityDelimiterRegEx = StringUtils.defaultString(entityDelimiterRegEx, "[;\\|]");
            keyValueDelimiterRegEx = StringUtils.defaultString(keyValueDelimiterRegEx, "[=:]");

            final String[] entityTokens = content.split(entityDelimiterRegEx);
            for (String entityToken : entityTokens) {
                if (StringUtils.isNotEmpty(entityToken)) {
                    final String[] keyAndValueTokens = entityToken.split(keyValueDelimiterRegEx);
                    if (keyAndValueTokens.length == 1) {
                        final String key = keyAndValueTokens[0];
                        final String value = null;
                        retmap.put(key, value);
                    } else if (keyAndValueTokens.length == 2) {
                        final String key = keyAndValueTokens[0];
                        final String value = keyAndValueTokens[1];
                        retmap.put(key, value);
                    }
                }
            }
        }

        return retmap;
    }

    /**
     * Returns true if the given type is assignable to the {@link Map} interface
     * 
     * @param type
     * @return
     */
    public static boolean isMapType(Class<?> type) {
        boolean retval = false;
        if (type != null) {
            retval = Map.class.isAssignableFrom(type);
        }
        return retval;
    }

    /**
     * Returns true if the given type is assignable to the {@link SortedMap} interface
     * 
     * @param type
     * @return
     */
    public static boolean isSortedMapType(Class<?> type) {
        boolean retval = false;
        if (type != null) {
            retval = SortedMap.class.isAssignableFrom(type);
        }
        return retval;
    }

    /**
     * Returns a new {@link MapBuilder} instance.<br>
     * <br>
     * Examples:
     * 
     * <pre>
     * Map&lt;String, Long&gt; map = MapUtils.builder()
     *                                 .put( &quot;key1&quot;, 1l )
     *                                 .put( &quot;key2&quot;, 2l )
     *                                 .put( &quot;key3&quot;, 3l )
     *                                 .put( &quot;key4&quot;, 4l )
     *                                 .buildAs()
     *                                 .linkedHashMap();
     * </pre>
     * 
     * <pre>
     * Map&lt;String, Object&gt; map = MapUtils.builder()
     *                                   .&lt;String, Object&gt; put( &quot;key1&quot;, 1l )
     *                                   .put( &quot;key2&quot;, 2l )
     *                                   .put( &quot;key3&quot;, 3l )
     *                                   .put( &quot;key4&quot;, 4l )
     *                                   .buildAs()
     *                                   .linkedHashMap();
     * </pre>
     * 
     * @return
     */
    public static MapBuilder builder() {
        return new MapBuilder();
    }

    /**
     * Returns the size of the given {@link Map} or 0 if the given {@link Map} reference is null.
     * 
     * @param map
     * @return
     */
    public static int size(Map<?, ?> map) {
        int retval = 0;
        if (map != null) {
            retval = map.size();
        }
        return retval;
    }

    @SuppressWarnings("unchecked")
    public static <K, V> V[] filteredValues(Map<K, V> map, Class<V> valueType, K... keys) {
        Assert.isNotNull(valueType);
        final V[] retvals = (V[]) Array.newInstance(valueType, keys != null ? keys.length : 0);
        if (keys != null && map != null) {
            int ii = 0;
            for (K key : keys) {
                V value = map.get(key);
                retvals[ii++] = value;
            }
        }
        return retvals;
    }

    /**
     * Returns a {@link Map} instance which returns for {@link Map#get(Object)} always an {@link AtomicInteger} instance. This
     * allows statements like:
     * 
     * <pre>
     * Map&lt;Object, AtomicInteger&gt; map = MapUtils.initializedCounterMap();
     * int value1 = map.get( &quot;lala&quot; ).getAndIncrement();
     * int value2 = map.get( &quot;lala&quot; ).incrementAndGet();
     * assertEquals( 0, value1 );
     * assertEquals( 2, value2 );
     * </pre>
     * 
     * @return
     */
    public static <E> Map<E, AtomicInteger> initializedCounterMap() {
        return MapUtils.<E, AtomicInteger>initializedMap(new FactorySerializable<AtomicInteger>() {
            private static final long serialVersionUID = 2356741002226308586L;

            @Override
            public AtomicInteger newInstance() {
                return new AtomicInteger();
            }
        });
    }

    /**
     * Returns a new {@link MapDelta} for the given two {@link Map} instances
     * 
     * @see SetUtils#delta(Set, Set)
     * @see Map
     * @param mapFirst
     * @param mapSecond
     * @return new {@link MapDelta}
     */
    public static <K, V> MapDelta<K, V> delta(Map<K, V> mapFirst, Map<K, V> mapSecond) {
        return new MapDelta<K, V>(mapFirst, mapSecond);
    }

    /**
     * Returns an {@link AggregatedMap} for the given {@link Map}s
     * 
     * @param mapIterable
     * @return new {@link AggregatedMap}
     */
    public static <K, V> AggregatedMap<K, V> aggregatedMap(Iterable<? extends Map<K, V>> mapIterable) {
        return new AggregatedMap<K, V>(mapIterable);
    }

    /**
     * Puts the given key and value into the given {@link Map} only if there is no equal key already contained within the
     * {@link Map}.<br>
     * If the given {@link Map} is null, the method does nothing.
     * 
     * @param map
     *          {@link Map}
     * @param key
     * @param value
     * @return true, if the key and value were put into the {@link Map}
     */
    public static <K, V> boolean putIfAbsent(Map<K, V> map, K key, V value) {
        boolean retval = false;
        if (map != null && !map.containsKey(key)) {
            map.put(key, value);
            retval = true;
        }
        return retval;
    }

    /**
     * Puts the given key and value into the given {@link Map} only if there is no equal key already contained within the
     * {@link Map}.<br>
     * The value factory is only invoked, if the value has to be put into the {@link Map}.<br>
     * If the given {@link Map} is null, the method does nothing.
     * 
     * @param map
     *          {@link Map}
     * @param key
     * @param valueFactory
     *          {@link Factory} for a single value
     * @return true, if the key and value were put into the {@link Map}
     */
    public static <K, V> boolean putIfAbsent(Map<K, V> map, K key, Factory<V> valueFactory) {
        boolean retval = false;
        if (map != null && valueFactory != null && !map.containsKey(key)) {
            V value = valueFactory.newInstance();
            map.put(key, value);
            retval = true;
        }
        return retval;
    }

    /**
     * Returns a {@link TreeMap} using the given {@link Comparator} and with the key and values of the given {@link Map}
     * 
     * @param map
     * @param comparator
     * @return new {@link TreeMap}
     */
    public static <K, V> NavigableMap<K, V> sortedMap(Map<K, V> map, Comparator<K> comparator) {
        final TreeMap<K, V> treeMap = comparator != null ? new TreeMap<K, V>(comparator) : new TreeMap<K, V>();
        if (map != null) {
            treeMap.putAll(map);
        }
        return treeMap;
    }

    /**
     * Sorts the keys of the given {@link Map} by swapping them and their values into a {@link TreeMap} and back again
     * 
     * @param map
     * @param comparator
     *          {@link Comparator}
     */
    public static <K, V> void sortKeys(Map<K, V> map, Comparator<? super K> comparator) {
        if (map != null) {
            Set<K> keySet = map.keySet();
            if (keySet != null) {
                Map<K, V> treeMap = new TreeMap<K, V>(comparator);
                treeMap.putAll(map);

                map.clear();
                map.putAll(treeMap);
            }
        }
    }

}