All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jtrim2.collections.CollectionsEx Maven / Gradle / Ivy

There is a newer version: 2.0.7
Show newest version
package org.jtrim2.collections;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.RandomAccess;
import java.util.Set;
import java.util.function.Consumer;
import org.jtrim2.utils.ExceptionHelper;

/**
 * Contains helper methods for arrays not present in
 * {@link java.util.Collections}.
 * 

* This class cannot be instantiated or inherited. */ public final class CollectionsEx { private static final float DEFAULT_HASHMAP_LOAD_FACTOR = 0.75f; private CollectionsEx() { throw new AssertionError(); } private static T configure(T obj, Consumer config) { config.accept(obj); return obj; } /** * Creates and populates a {@code Map}. This method is a convenience to create a non-empty * map without requiring explicit declaration. It is useful when passing a map as an argument * or when initializing a (static) field. For example: * *

{@code
     * static final Map MY_MAP = CollectionsEx.newMap(MyKey.class, map -> {
     *   map.put(MyKey.KEY1, "Value1");
     *   map.put(MyKey.KEY2, "Value2");
     * });
     * }
* * The type of the map to be created depends on the type of the key. If the key is an * enum, an {@link EnumMap} is created, otherwise a {@link HashMap}. * * @param the type of the key of the created map * @param the type of the value of the created map * @param keyType the type of the key of the created map. This argument cannot be * {@code null}. * @param contentConfig the lambda to which the map to be returned is passed. This * argument cannot be {@code null}. * @return the newly created map, after initialized by the given lambda. This method * never returns {@code null}. */ public static Map newMap( Class keyType, Consumer> contentConfig) { if (keyType.isEnum()) { return newEnumMapUnsafe(keyType, contentConfig); } else { return newHashMap(contentConfig); } } @SuppressWarnings("unchecked") private static , K, V> Map newEnumMapUnsafe( Class keyType, Consumer> contentConfig) { Class unsafeKeyType = (Class) keyType; Consumer> unsafeConfig = (Consumer>) contentConfig; return (Map) newEnumMap(unsafeKeyType, unsafeConfig); } /** * Creates and populates a {@code EnumMap}. This method is a convenience to create a non-empty * map without requiring explicit declaration. It is useful when passing a map as an argument * or when initializing a (static) field. For example: * *
{@code
     * static final Map MY_MAP = CollectionsEx.newEnumMap(MyEnum.class, map -> {
     *   map.put(MyEnum.KEY1, "Value1");
     *   map.put(MyEnum.KEY2, "Value2");
     * });
     * }
* * @param the type of the key of the created map * @param the type of the value of the created map * @param keyType the type of the key of the created map. This argument cannot be * {@code null}. * @param contentConfig the lambda to which the map to be returned is passed. This * argument cannot be {@code null}. * @return the newly created map, after initialized by the given lambda. This method * never returns {@code null}. */ public static , V> EnumMap newEnumMap( Class keyType, Consumer> contentConfig) { return configure(new EnumMap<>(keyType), contentConfig); } /** * Creates and populates a {@code HashMap}. This method is a convenience to create a non-empty * map without requiring explicit declaration. It is useful when passing a map as an argument * or when initializing a (static) field. For example: * *
{@code
     * static final Map MY_MAP = CollectionsEx.newHashMap(map -> {
     *   map.put("Key1", "Value1");
     *   map.put("Key2", "Value2");
     * });
     * }
* * @param the type of the key of the created map * @param the type of the value of the created map * @param contentConfig the lambda to which the map to be returned is passed. This * argument cannot be {@code null}. * @return the newly created map, after initialized by the given lambda. This method * never returns {@code null}. */ public static HashMap newHashMap(Consumer> contentConfig) { return configure(new HashMap<>(), contentConfig); } /** * Creates a new {@link java.util.LinkedHashMap LinkedHashMap} specifying the * expected number of mappings. The returned map will never do a rehash * if the number of mappings remain bellow the specified size. So if a * reasonable upper bound can be specified for the number of mappings * the expensive rehash operation can be avoided. * * @param the type of the key of the returned map * @param the type of the value of the returned map * @param expectedSize the expected number mappings. This argument must not * be a negative value. * @return a hash map with a {@code loadFactor == 0.75} and a minimal * capacity which is enough to store the specified number of elements * without a rehash. This method always returns a new unique object. * * @throws IllegalArgumentException thrown if the expectedSize is negative */ public static LinkedHashMap newLinkedHashMap(int expectedSize) { return newLinkedHashMap(expectedSize, DEFAULT_HASHMAP_LOAD_FACTOR); } /** * Creates a new {@link java.util.LinkedHashMap LinkedHashMap} specifying the * expected number of mappings and the load factor. The returned map will * never do a rehash if the number of mappings remain bellow the specified * size. So if a reasonable upper bound can be specified for the number of * mappings the expensive rehash operation can be avoided. * * @param the type of the key of the returned map * @param the type of the value of the returned map * @param expectedSize the expected number mappings. This argument must not * be a negative value. * @param loadFactor the load factor of the returned hash map. This argument * must be a positive value * @return a hash map with the specified load factor and a minimal capacity * which is enough to store the specified number of elements without a * rehash. This method always returns a new unique object. * * @throws IllegalArgumentException thrown if the expectedSize is negative * or the loadFactor is nonpositive */ public static LinkedHashMap newLinkedHashMap(int expectedSize, float loadFactor) { int capacity = getRequiredHashCapacity(expectedSize, loadFactor); return new LinkedHashMap<>(capacity, loadFactor); } /** * Creates a new {@link java.util.HashMap HashMap} specifying the * expected number of mappings. The returned map will never do a rehash * if the number of mappings remain bellow the specified size. So if a * reasonable upper bound can be specified for the number of mappings * the expensive rehash operation can be avoided. * * @param the type of the key of the returned map * @param the type of the value of the returned map * @param expectedSize the expected number mappings. This argument must not * be a negative value. * @return a hash map with a {@code loadFactor == 0.75} and a minimal * capacity which is enough to store the specified number of elements * without a rehash. This method always returns a new unique object. * * @throws IllegalArgumentException thrown if the expectedSize is negative */ public static HashMap newHashMap(int expectedSize) { return newHashMap(expectedSize, DEFAULT_HASHMAP_LOAD_FACTOR); } /** * Creates a new {@link java.util.HashMap HashMap} specifying the * expected number of mappings and the load factor. The returned map will * never do a rehash if the number of mappings remain bellow the specified * size. So if a reasonable upper bound can be specified for the number of * mappings the expensive rehash operation can be avoided. * * @param the type of the key of the returned map * @param the type of the value of the returned map * @param expectedSize the expected number mappings. This argument must not * be a negative value. * @param loadFactor the load factor of the returned hash map. This argument * must be a positive value * @return a hash map with the specified load factor and a minimal capacity * which is enough to store the specified number of elements without a * rehash. This method always returns a new unique object. * * @throws IllegalArgumentException thrown if the expectedSize is negative * or the loadFactor is nonpositive */ public static HashMap newHashMap(int expectedSize, float loadFactor) { int capacity = getRequiredHashCapacity(expectedSize, loadFactor); return new HashMap<>(capacity, loadFactor); } private static int getRequiredHashCapacity(int expectedSize, float loadFactor) { ExceptionHelper.checkArgumentInRange(expectedSize, 0, Integer.MAX_VALUE, "expectedSize"); int capacity = (int) ((double) expectedSize / (double) loadFactor) + 1; return capacity >= 1 ? capacity : 1; } /** * Creates a new {@link java.util.LinkedHashSet LinkedHashSet} specifying the * expected number of elements. The returned set will never do a rehash * if the number of elements remain bellow the specified size. So if a * reasonable upper bound can be specified for the number of elements * the expensive rehash operation can be avoided. * * @param the type of the values of the returned set * @param expectedSize the expected number elements. This argument must not * be a negative value. * @return a hash set with a {@code loadFactor == 0.75} and a minimal * capacity which is enough to store the specified number of elements * without a rehash. This method always returns a new unique object. * * @throws IllegalArgumentException thrown if the expectedSize is negative */ public static LinkedHashSet newLinkedHashSet(int expectedSize) { return newLinkedHashSet(expectedSize, DEFAULT_HASHMAP_LOAD_FACTOR); } /** * Creates a new {@link java.util.LinkedHashSet LinkedHashSet} specifying the * expected number of elements and the load factor. The returned set will * never do a rehash if the number of elements remain bellow the specified * size. So if a reasonable upper bound can be specified for the number of * elements the expensive rehash operation can be avoided. * * @param the type of the values of the returned set * @param expectedSize the expected number elements. This argument must not * be a negative value. * @param loadFactor the load factor of the returned hash set. This argument * must be a positive value * @return a hash set with the specified load factor and a minimal capacity * which is enough to store the specified number of elements without a * rehash. This method always returns a new unique object. * * @throws IllegalArgumentException thrown if the expectedSize is negative * or the loadFactor is nonpositive */ public static LinkedHashSet newLinkedHashSet(int expectedSize, float loadFactor) { int capacity = getRequiredHashCapacity(expectedSize, loadFactor); return new LinkedHashSet<>(capacity, loadFactor); } /** * Creates a new {@link java.util.HashSet HashSet} specifying the * expected number of elements. The returned set will never do a rehash * if the number of elements remain bellow the specified size. So if a * reasonable upper bound can be specified for the number of elements * the expensive rehash operation can be avoided. * * @param the type of the values of the returned set * @param expectedSize the expected number elements. This argument must not * be a negative value. * @return a hash set with a {@code loadFactor == 0.75} and a minimal * capacity which is enough to store the specified number of elements * without a rehash. This method always returns a new unique object. * * @throws IllegalArgumentException thrown if the expectedSize is negative */ public static HashSet newHashSet(int expectedSize) { return newHashSet(expectedSize, DEFAULT_HASHMAP_LOAD_FACTOR); } /** * Creates a new {@link java.util.HashSet HashSet} specifying the * expected number of elements and the load factor. The returned set will * never do a rehash if the number of elements remain bellow the specified * size. So if a reasonable upper bound can be specified for the number of * elements the expensive rehash operation can be avoided. * * @param the type of the values of the returned set * @param expectedSize the expected number elements. This argument must not * be a negative value. * @param loadFactor the load factor of the returned hash set. This argument * must be a positive value * @return a hash set with the specified load factor and a minimal capacity * which is enough to store the specified number of elements without a * rehash. This method always returns a new unique object. * * @throws IllegalArgumentException thrown if the expectedSize is negative * or the loadFactor is nonpositive */ public static HashSet newHashSet(int expectedSize, float loadFactor) { int capacity = getRequiredHashCapacity(expectedSize, loadFactor); return new HashSet<>(capacity, loadFactor); } /** * Returns a new set which is based on the reference equality operator (==) * instead of its {@code equals} method. This method is equivalent to * {@code Collections.newSetFromMap(new IdentityHashMap(expectedSize))}. * * Note that this method does not return a general purpose {@code set} * implementation because it does not rely on the {@code equals} method * of its elements. * * @param the type of the elements of the set * @param expectedSize the expected size the returned set. The returned * set will not execute a time consuming rehash operation if its size will * not grow over this limit. * * @return the newly returned */ public static Set newIdentityHashSet(int expectedSize) { return Collections.newSetFromMap(new IdentityHashMap<>(expectedSize)); } /** * Returns an unmodifiable copy of the specified collection. * The returned list is always a random access list and will contain * the elements in the order the iterator of the specified collection * returned them. *

* The result of this method is undefined if the specified collection * is modified while calling this method. *

* Note that this method does not necessarily returns a unique object * each time, only ensures that the returned list will be independent * of the specified collection (except that it will contain the same * objects) so subsequent modifications to the specified collection will * not be reflected in the returned list. * * @param the type of the elements of the specified collection * @param c the collection which is to be copied. This argument cannot be * {@code null}. * @return the readonly copy of the specified collection. This method never * returns {@code null}. * * @throws NullPointerException thrown if the specified collection is * {@code null} */ public static List readOnlyCopy(Collection c) { if (c.isEmpty()) { return Collections.emptyList(); } else { return Collections.unmodifiableList(new ArrayList<>(c)); } } /** * Returns a readonly view of two concatenated lists. * Changes made to the specified lists will be reflected immediately * in the returned list. *

* The returned list will contain the elements in the order they are * contained in the specified lists; the elements of the first list coming * first. * * @param the type of the elements in the list * @param list1 the first part of the concatenated list. This argument * cannot be {@code null}. * @param list2 the second part of the concatenated list. This argument * cannot be {@code null}. * @return the concatenated view of the specified lists. This method never * returns {@code null}. * * @throws NullPointerException thrown if any of the arguments is * {@code null} */ public static List viewConcatList( List list1, List list2) { if (list1 instanceof RandomAccess && list2 instanceof RandomAccess && !(list1 instanceof RandomAccessConcatListView) && !(list2 instanceof RandomAccessConcatListView)) { return new RandomAccessConcatListView<>(list1, list2); } else { return new ConcatListView<>(list1, list2); } } /** * Returns a comparator which uses the natural ordering of elements. * Note that the returned comparator can only be used on elements * implementing the {@link java.util.Comparator} interface. *

* Note that the return comparator is not entirely type safe and must not * be abused otherwise unexpected {@link ClassCastException} can be thrown * while trying to use it. * * @param the type of the elements which the returned comparator * compares * @return a comparator which uses the natural ordering of elements. * This method never returns {@code null}. */ @SuppressWarnings("unchecked") public static Comparator naturalOrder() { return (Comparator) unsafeNaturalOrder(); } private static > Comparator unsafeNaturalOrder() { return (o1, o2) -> o1.compareTo(o2); } /** * Returns an element reference of a list which is not actually attached * to any list. The returned element reference will be a detached reference * containing the specified element. * * @param the type of element * @param element the element contained in the returned list element * reference. This argument will be returned by * {@link RefList.ElementRef#getElement()}. * @return a detached list element reference of the specified element. * This method never returns {@code null}. */ public static RefList.ElementRef getDetachedListRef(E element) { return new DetachedListRef<>(element); } /** * Returns a copy of the given map where the key is an enum. * * @param the type of the keys * @param the type of the values * @param keyType the type of the keys. This argument cannot be {@code null}. * @param src the map to be copied. This argument cannot be {@code null} and * cannot contain {@code null} keys. However, {@code null} values are permitted. * @return the copy of the given map. This method never returns {@code null}. */ public static , V> EnumMap copyToEnumMap( Class keyType, Map src) { EnumMap result = new EnumMap<>(keyType); result.putAll(src); return result; } /** * Returns a read-only copy of the given map where the key is an enum. The returned * map is backed by an {@link EnumMap}. * * @param the type of the keys * @param the type of the values * @param keyType the type of the keys. This argument cannot be {@code null}. * @param src the map to be copied. This argument cannot be {@code null} and * cannot contain {@code null} keys. However, {@code null} values are permitted. * @return the read-only copy of the given map. This method never returns {@code null}. */ public static , V> Map copyToReadOnlyEnumMap( Class keyType, Map src) { EnumMap result = copyToEnumMap(keyType, src); return Collections.unmodifiableMap(result); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy