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

com.helger.commons.collection.CollectionHelper Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2014-2024 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * 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.helger.commons.collection;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.CodingStyleguideUnaware;
import com.helger.commons.annotation.PresentForCodeCoverage;
import com.helger.commons.annotation.ReturnsImmutableObject;
import com.helger.commons.annotation.ReturnsMutableCopy;
import com.helger.commons.annotation.ReturnsMutableObject;
import com.helger.commons.collection.impl.CommonsArrayList;
import com.helger.commons.collection.impl.CommonsHashMap;
import com.helger.commons.collection.impl.CommonsHashSet;
import com.helger.commons.collection.impl.CommonsLinkedHashMap;
import com.helger.commons.collection.impl.CommonsLinkedHashSet;
import com.helger.commons.collection.impl.CommonsTreeMap;
import com.helger.commons.collection.impl.CommonsTreeSet;
import com.helger.commons.collection.impl.ICommonsList;
import com.helger.commons.collection.impl.ICommonsMap;
import com.helger.commons.collection.impl.ICommonsOrderedMap;
import com.helger.commons.collection.impl.ICommonsSet;
import com.helger.commons.collection.iterate.IIterableIterator;
import com.helger.commons.lang.ClassHelper;
import com.helger.commons.state.EChange;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;

/**
 * Provides various helper methods to handle collections like {@link List},
 * {@link Set} and {@link Map}.
 *
 * @author Philip Helger
 */
@Immutable
@SuppressFBWarnings ("JCIP_FIELD_ISNT_FINAL_IN_IMMUTABLE_CLASS")
public final class CollectionHelper
{
  @PresentForCodeCoverage
  private static final CollectionHelper INSTANCE = new CollectionHelper ();

  private CollectionHelper ()
  {}

  @Nullable
  public static ECollectionBaseType getCollectionBaseTypeOfClass (@Nullable final Class  aClass)
  {
    if (aClass != null)
    {
      // Query Set before Collection, because Set is derived from Collection!
      if (Set.class.isAssignableFrom (aClass))
        return ECollectionBaseType.SET;
      if (Collection.class.isAssignableFrom (aClass))
        return ECollectionBaseType.COLLECTION;
      if (Map.class.isAssignableFrom (aClass))
        return ECollectionBaseType.MAP;
      if (ClassHelper.isArrayClass (aClass))
        return ECollectionBaseType.ARRAY;
      if (Iterator.class.isAssignableFrom (aClass))
        return ECollectionBaseType.ITERATOR;
      if (Iterable.class.isAssignableFrom (aClass))
        return ECollectionBaseType.ITERABLE;
      if (Enumeration.class.isAssignableFrom (aClass))
        return ECollectionBaseType.ENUMERATION;
    }
    return null;
  }

  @Nullable
  public static ECollectionBaseType getCollectionBaseTypeOfObject (@Nullable final Object aObj)
  {
    return aObj == null ? null : getCollectionBaseTypeOfClass (aObj.getClass ());
  }

  public static boolean isCollectionClass (@Nullable final Class  aClass)
  {
    return getCollectionBaseTypeOfClass (aClass) != null;
  }

  public static boolean isCollectionObject (@Nullable final Object aObj)
  {
    return getCollectionBaseTypeOfObject (aObj) != null;
  }

  /**
   * Get the passed object as a {@link CommonsArrayList} object. This is helpful
   * in case you want to compare the String array ["a", "b"] with the
   * List<String> ("a", "b") If the passed object is not a recognized.
   * container type, than a new list with one element is created!
   *
   * @param aObj
   *        The object to be converted. May not be null.
   * @return The object as a collection. Never null.
   */
  @Nonnull
  public static CommonsArrayList  getAsList (@Nonnull final Object aObj)
  {
    ValueEnforcer.notNull (aObj, "Object");

    final ECollectionBaseType eType = getCollectionBaseTypeOfObject (aObj);
    if (eType == null)
    {
      // It's not a supported container -> create a new list with one element
      return newList (aObj);
    }

    switch (eType)
    {
      case COLLECTION:
        // It's already a collection
        if (aObj instanceof CommonsArrayList )
          return (CommonsArrayList ) aObj;
        return newList ((Collection ) aObj);
      case SET:
        // Convert to list
        return newList ((Set ) aObj);
      case MAP:
        // Use the entry set of the map as list
        return newList (((Map ) aObj).entrySet ());
      case ARRAY:
        // Convert the array to a list
        return newList ((Object []) aObj);
      case ITERATOR:
        // Convert the iterator to a list
        return newList ((Iterator ) aObj);
      case ITERABLE:
        // Convert the iterable to a list
        return newList ((Iterable ) aObj);
      case ENUMERATION:
        // Convert the enumeration to a list
        return newList ((Enumeration ) aObj);
      default:
        throw new IllegalStateException ("Unhandled collection type " + eType + "!");
    }
  }

  @SafeVarargs
  @Nullable
  @ReturnsImmutableObject
  @CodingStyleguideUnaware
  public static  List  makeUnmodifiable (@Nullable final ELEMENTTYPE... aArray)
  {
    return aArray == null ? null : Collections.unmodifiableList (newList (aArray));
  }

  @Nullable
  @ReturnsImmutableObject
  @CodingStyleguideUnaware
  public static  Collection  makeUnmodifiable (@Nullable final Collection  aCollection)
  {
    return aCollection == null ? null : Collections.unmodifiableCollection (aCollection);
  }

  @Nullable
  @ReturnsImmutableObject
  @CodingStyleguideUnaware
  public static  List  makeUnmodifiable (@Nullable final List  aList)
  {
    return aList == null ? null : Collections.unmodifiableList (aList);
  }

  @Nullable
  @ReturnsImmutableObject
  @CodingStyleguideUnaware
  public static  Set  makeUnmodifiable (@Nullable final Set  aSet)
  {
    return aSet == null ? null : Collections.unmodifiableSet (aSet);
  }

  @Nullable
  @ReturnsImmutableObject
  @CodingStyleguideUnaware
  public static  Map  makeUnmodifiable (@Nullable final Map  aMap)
  {
    return aMap == null ? null : Collections.unmodifiableMap (aMap);
  }
  //
  // @Nullable
  // @ReturnsImmutableObject
  // public static >
  // SortedSet  makeUnmodifiable (@Nullable final SortedSet
  //  aSortedSet)
  // {
  // return aSortedSet == null ? null : Collections.unmodifiableSortedSet
  // (aSortedSet);
  // }
  //
  // @Nullable
  // @ReturnsImmutableObject
  // public static  SortedMap 
  // makeUnmodifiable (@Nullable final SortedMap 
  // aSortedMap)
  // {
  // return aSortedMap == null ? null : Collections.unmodifiableSortedMap
  // (aSortedMap);
  // }

  @Nullable
  @ReturnsImmutableObject
  @CodingStyleguideUnaware
  public static  NavigableSet  makeUnmodifiable (@Nullable final NavigableSet  aNavigableSet)
  {
    return aNavigableSet == null ? null : Collections.unmodifiableNavigableSet (aNavigableSet);
  }

  @Nullable
  @ReturnsImmutableObject
  @CodingStyleguideUnaware
  public static  NavigableMap  makeUnmodifiable (@Nullable final NavigableMap  aNavigableMap)
  {
    return aNavigableMap == null ? null : Collections.unmodifiableNavigableMap (aNavigableMap);
  }

  @Nonnull
  @ReturnsImmutableObject
  @CodingStyleguideUnaware
  public static  Collection  makeUnmodifiableNotNull (@Nullable final Collection  aCollection)
  {
    return aCollection == null ? Collections.emptyList () : Collections.unmodifiableCollection (aCollection);
  }

  @Nonnull
  @ReturnsImmutableObject
  @CodingStyleguideUnaware
  public static  List  makeUnmodifiableNotNull (@Nullable final List  aList)
  {
    return aList == null ? Collections.emptyList () : Collections.unmodifiableList (aList);
  }

  @Nonnull
  @ReturnsImmutableObject
  @CodingStyleguideUnaware
  public static  Set  makeUnmodifiableNotNull (@Nullable final Set  aSet)
  {
    return aSet == null ? Collections.emptySet () : Collections.unmodifiableSet (aSet);
  }

  @Nonnull
  @ReturnsImmutableObject
  @CodingStyleguideUnaware
  public static  Map  makeUnmodifiableNotNull (@Nullable final Map  aMap)
  {
    return aMap == null ? Collections.emptyMap () : Collections.unmodifiableMap (aMap);
  }

  // @Nonnull
  // @ReturnsImmutableObject
  // public static >
  // SortedSet  makeUnmodifiableNotNull (@Nullable final SortedSet
  //  aSortedSet)
  // {
  // return aSortedSet == null ? Collections.emptySortedSet () :
  // Collections.unmodifiableSortedSet (aSortedSet);
  // }
  //
  // @Nonnull
  // @ReturnsImmutableObject
  // public static , VALUETYPE>
  // SortedMap  makeUnmodifiableNotNull (@Nullable final
  // SortedMap  aSortedMap)
  // {
  // return aSortedMap == null ? Collections.emptySortedMap () :
  // Collections.unmodifiableSortedMap (aSortedMap);
  // }

  @Nonnull
  @ReturnsImmutableObject
  @CodingStyleguideUnaware
  public static > NavigableSet  makeUnmodifiableNotNull (@Nullable final NavigableSet  aNavigableSet)
  {
    return aNavigableSet == null ? Collections.emptyNavigableSet ()
                                 : Collections.unmodifiableNavigableSet (aNavigableSet);
  }

  @Nonnull
  @ReturnsImmutableObject
  @CodingStyleguideUnaware
  public static , VALUETYPE> NavigableMap  makeUnmodifiableNotNull (@Nullable final NavigableMap  aNavigableMap)
  {
    return aNavigableMap == null ? Collections.emptyNavigableMap ()
                                 : Collections.unmodifiableNavigableMap (aNavigableMap);
  }

  /**
   * Get all elements that are only contained in the first contained, and not in
   * the second. This method implements aCont1 - aCont2.
   *
   * @param 
   *        Set element type
   * @param aCollection1
   *        The first container. May be null or empty.
   * @param aCollection2
   *        The second container. May be null or empty.
   * @return The difference and never null. Returns an empty set,
   *         if the first container is empty. Returns a copy of the first
   *         container, if the second container is empty. Returns
   *         aCont1 - aCont2 if both containers are non-empty.
   */
  @Nullable
  @ReturnsMutableCopy
  public static  ICommonsSet  getDifference (@Nullable final Collection  aCollection1,
                                                                       @Nullable final Collection  aCollection2)
  {
    if (isEmpty (aCollection1))
      return newSet (0);
    if (isEmpty (aCollection2))
      return newSet (aCollection1);

    final ICommonsSet  ret = newSet (aCollection1);
    ret.removeAll (aCollection2);
    return ret;
  }

  /**
   * Get all elements that are contained in the first AND in the second
   * container.
   *
   * @param 
   *        Collection element type
   * @param aCollection1
   *        The first container. May be null or empty.
   * @param aCollection2
   *        The second container. May be null or empty.
   * @return An empty set, if either the first or the second container are
   *         empty. Returns a set of elements that are contained in both
   *         containers, if both containers are non-empty. The return value is
   *         never null.
   */
  @Nullable
  @ReturnsMutableCopy
  public static  ICommonsSet  getIntersected (@Nullable final Collection  aCollection1,
                                                                        @Nullable final Collection  aCollection2)
  {
    if (isEmpty (aCollection1))
      return newSet (0);
    if (isEmpty (aCollection2))
      return newSet (0);

    final ICommonsSet  ret = newSet (aCollection1);
    ret.retainAll (aCollection2);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashMap  newMap (@Nonnegative final int nInitialCapacity)
  {
    return new CommonsHashMap <> (nInitialCapacity);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashMap  newMap ()
  {
    return new CommonsHashMap <> ();
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashMap  newMapMapped (@Nullable final Map  aMap,
                                                                                                                             @Nonnull final Function  aKeyMapper,
                                                                                                                             @Nonnull final Function  aValueMapper)
  {
    if (isEmpty (aMap))
      return newMap (0);
    return new CommonsHashMap <> (aMap, aKeyMapper, aValueMapper);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashMap  newMapMapped (@Nullable final Collection  aCollection,
                                                                                                            @Nonnull final Function  aKeyMapper,
                                                                                                            @Nonnull final Function  aValueMapper)
  {
    if (isEmpty (aCollection))
      return newMap (0);
    return new CommonsHashMap <> (aCollection, aKeyMapper, aValueMapper);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashMap  newMap (@Nullable final Map  aMap,
                                                                                 @Nonnull final Predicate > aFilter)
  {
    if (isEmpty (aMap))
      return newMap (0);
    final CommonsHashMap  ret = newMap (aMap.size ());
    ret.putAll (aMap, aFilter);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashMap  newMap (@Nullable final KEYTYPE aKey,
                                                                                 @Nullable final VALUETYPE aValue)
  {
    final CommonsHashMap  ret = newMap (1);
    ret.put (aKey, aValue);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  @SafeVarargs
  public static  CommonsHashMap  newMap (@Nullable final ELEMENTTYPE... aValues)
  {
    if (ArrayHelper.isEmpty (aValues))
      return newMap (0);

    if ((aValues.length % 2) != 0)
      throw new IllegalArgumentException ("The passed array needs an even number of elements!");

    final CommonsHashMap  ret = newMap (aValues.length / 2);
    for (int i = 0; i < aValues.length; i += 2)
      ret.put (aValues[i], aValues[i + 1]);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashMap  newMap (@Nullable final KEYTYPE [] aKeys,
                                                                                 @Nullable final VALUETYPE [] aValues)
  {
    final int nKeys = ArrayHelper.getSize (aKeys);
    final int nValues = ArrayHelper.getSize (aValues);

    // Check for identical size
    if (nKeys != nValues)
      throw new IllegalArgumentException ("The passed arrays have different length (" +
                                          nKeys +
                                          " keys and " +
                                          nValues +
                                          " values)!");

    // Are both empty?
    if (nKeys == 0)
      return newMap (0);

    final CommonsHashMap  ret = newMap (nKeys);
    for (int i = 0; i < aKeys.length; ++i)
      ret.put (aKeys[i], aValues[i]);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashMap  newMap (@Nullable final Collection  aKeys,
                                                                                 @Nullable final Collection  aValues)
  {
    final int nKeys = getSize (aKeys);
    final int nValues = getSize (aValues);

    // Check for identical size
    if (nKeys != nValues)
      throw new IllegalArgumentException ("The passed arrays have different length (" +
                                          nKeys +
                                          " keys and " +
                                          nValues +
                                          " values)!");

    // Are both empty?
    if (nKeys == 0)
      return newMap (0);

    final CommonsHashMap  ret = newMap (nKeys);
    final Iterator  itk = aKeys.iterator ();
    final Iterator  itv = aValues.iterator ();
    while (itk.hasNext ())
      ret.put (itk.next (), itv.next ());
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashMap  newMap (@Nullable final Map  aMap)
  {
    if (isEmpty (aMap))
      return newMap (0);

    return new CommonsHashMap <> (aMap);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashMap  newMap (@Nullable final Map  [] aMaps)
  {
    if (aMaps == null || aMaps.length == 0)
      return newMap (0);

    final CommonsHashMap  ret = newMap ();
    for (final Map  aMap : aMaps)
      ret.putAll (aMap);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashMap  newMap (@Nullable final Collection > aCollection)
  {
    if (isEmpty (aCollection))
      return newMap (0);

    final CommonsHashMap  ret = newMap (aCollection.size ());
    ret.putAll (aCollection);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashMap  newMap (@Nullable final Iterable > aCollection)
  {
    if (isEmpty (aCollection))
      return newMap (0);

    final CommonsHashMap  ret = newMap ();
    ret.putAll (aCollection);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashMap  newOrderedMap (@Nonnegative final int nInitialCapacity)
  {
    return new CommonsLinkedHashMap <> (nInitialCapacity);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashMap  newOrderedMap ()
  {
    return new CommonsLinkedHashMap <> ();
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashMap  newOrderedMapMapped (@Nullable final Map  aMap,
                                                                                                                                          @Nonnull final Function  aKeyMapper,
                                                                                                                                          @Nonnull final Function  aValueMapper)
  {
    if (isEmpty (aMap))
      return newOrderedMap (0);
    return new CommonsLinkedHashMap <> (aMap, aKeyMapper, aValueMapper);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashMap  newOrderedMapMapped (@Nullable final Collection  aCollection,
                                                                                                                         @Nonnull final Function  aKeyMapper,
                                                                                                                         @Nonnull final Function  aValueMapper)
  {
    if (isEmpty (aCollection))
      return newOrderedMap (0);
    return new CommonsLinkedHashMap <> (aCollection, aKeyMapper, aValueMapper);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashMap  newOrderedMap (@Nullable final Map  aMap,
                                                                                              @Nonnull final Predicate > aFilter)
  {
    if (isEmpty (aMap))
      return newOrderedMap (0);
    final CommonsLinkedHashMap  ret = newOrderedMap (aMap.size ());
    ret.putAll (aMap, aFilter);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashMap  newOrderedMap (@Nullable final KEYTYPE aKey,
                                                                                              @Nullable final VALUETYPE aValue)
  {
    final CommonsLinkedHashMap  ret = newOrderedMap (1);
    ret.put (aKey, aValue);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  @SafeVarargs
  public static  CommonsLinkedHashMap  newOrderedMap (@Nullable final ELEMENTTYPE... aValues)
  {
    if (ArrayHelper.isEmpty (aValues))
      return newOrderedMap (0);

    if ((aValues.length % 2) != 0)
      throw new IllegalArgumentException ("The passed array needs an even number of elements!");

    final CommonsLinkedHashMap  ret = newOrderedMap (aValues.length / 2);
    for (int i = 0; i < aValues.length; i += 2)
      ret.put (aValues[i], aValues[i + 1]);
    return ret;
  }

  /**
   * Retrieve a map that is ordered in the way the parameter arrays are passed
   * in. Note that key and value arrays need to have the same length.
   *
   * @param 
   *        The key type.
   * @param 
   *        The value type.
   * @param aKeys
   *        The key array to use. May not be null.
   * @param aValues
   *        The value array to use. May not be null.
   * @return A {@link CommonsLinkedHashMap} containing the passed key-value
   *         entries. Never null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashMap  newOrderedMap (@Nullable final KEYTYPE [] aKeys,
                                                                                              @Nullable final VALUETYPE [] aValues)
  {
    final int nKeys = ArrayHelper.getSize (aKeys);
    final int nValues = ArrayHelper.getSize (aValues);

    // Check for identical size
    if (nKeys != nValues)
      throw new IllegalArgumentException ("The passed arrays have different length (" +
                                          nKeys +
                                          " keys and " +
                                          nValues +
                                          " values)!");

    // Are both empty?
    if (nKeys == 0)
      return newOrderedMap (0);

    final CommonsLinkedHashMap  ret = newOrderedMap (nKeys);
    for (int i = 0; i < aKeys.length; ++i)
      ret.put (aKeys[i], aValues[i]);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashMap  newOrderedMap (@Nullable final Collection  aKeys,
                                                                                              @Nullable final Collection  aValues)
  {
    final int nKeys = getSize (aKeys);
    final int nValues = getSize (aValues);

    // Check for identical size
    if (nKeys != nValues)
      throw new IllegalArgumentException ("The passed arrays have different length (" +
                                          nKeys +
                                          " keys and " +
                                          nValues +
                                          " values)!");

    // Are both empty?
    if (nKeys == 0)
      return newOrderedMap (0);

    final CommonsLinkedHashMap  ret = newOrderedMap (nKeys);
    final Iterator  itk = aKeys.iterator ();
    final Iterator  itv = aValues.iterator ();
    while (itk.hasNext ())
      ret.put (itk.next (), itv.next ());
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashMap  newOrderedMap (@Nullable final Map  aMap)
  {
    if (isEmpty (aMap))
      return newOrderedMap (0);
    return new CommonsLinkedHashMap <> (aMap);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashMap  newOrderedMap (@Nullable final Map  [] aMaps)
  {
    if (ArrayHelper.isEmpty (aMaps))
      return newOrderedMap (0);

    final CommonsLinkedHashMap  ret = newOrderedMap ();
    for (final Map  aMap : aMaps)
      ret.putAll (aMap);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashMap  newOrderedMap (@Nullable final Collection > aCollection)
  {
    if (isEmpty (aCollection))
      return newOrderedMap (0);

    final CommonsLinkedHashMap  ret = newOrderedMap (aCollection.size ());
    ret.putAll (aCollection);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashMap  newOrderedMap (@Nullable final Iterable > aCollection)
  {
    if (isEmpty (aCollection))
      return newOrderedMap (0);

    final CommonsLinkedHashMap  ret = newOrderedMap ();
    ret.putAll (aCollection);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static , VALUETYPE> CommonsTreeMap  newSortedMap ()
  {
    return new CommonsTreeMap <> (Comparator.nullsFirst (Comparator.naturalOrder ()));
  }

  @Nonnull
  @ReturnsMutableCopy
  public static , DSTVALUETYPE> CommonsTreeMap  newSortedMapMapped (@Nullable final Map  aMap,
                                                                                                                                                                           @Nonnull final Function  aKeyMapper,
                                                                                                                                                                           @Nonnull final Function  aValueMapper)
  {
    return new CommonsTreeMap <> (aMap, aKeyMapper, aValueMapper);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static , VALUETYPE> CommonsTreeMap  newSortedMap (@Nullable final Map  aMap,
                                                                                                                            @Nonnull final Predicate > aFilter)
  {
    final CommonsTreeMap  ret = newSortedMap ();
    ret.putAll (aMap, aFilter);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static , VALUETYPE> CommonsTreeMap  newSortedMap (@Nullable final KEYTYPE aKey,
                                                                                                                            @Nullable final VALUETYPE aValue)
  {
    final CommonsTreeMap  ret = newSortedMap ();
    ret.put (aKey, aValue);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  @SafeVarargs
  public static > CommonsTreeMap  newSortedMap (@Nullable final ELEMENTTYPE... aValues)
  {
    if (ArrayHelper.isEmpty (aValues))
      return newSortedMap ();

    if ((aValues.length % 2) != 0)
      throw new IllegalArgumentException ("The passed array needs an even number of elements!");

    final CommonsTreeMap  ret = newSortedMap ();
    for (int i = 0; i < aValues.length; i += 2)
      ret.put (aValues[i], aValues[i + 1]);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static , VALUETYPE> CommonsTreeMap  newSortedMap (@Nullable final KEYTYPE [] aKeys,
                                                                                                                            @Nullable final VALUETYPE [] aValues)
  {
    // Are both empty?
    if (ArrayHelper.isEmpty (aKeys) && ArrayHelper.isEmpty (aValues))
      return newSortedMap ();

    // keys OR values may be null here
    if (ArrayHelper.getSize (aKeys) != ArrayHelper.getSize (aValues))
      throw new IllegalArgumentException ("The passed arrays have different length!");

    final CommonsTreeMap  ret = newSortedMap ();
    for (int i = 0; i < aKeys.length; ++i)
      ret.put (aKeys[i], aValues[i]);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static , VALUETYPE> CommonsTreeMap  newSortedMap (@Nullable final Collection  aKeys,
                                                                                                                            @Nullable final Collection  aValues)
  {
    // Are both empty?
    if (isEmpty (aKeys) && isEmpty (aValues))
      return newSortedMap ();

    // keys OR values may be null here
    if (getSize (aKeys) != getSize (aValues))
      throw new IllegalArgumentException ("Number of keys is different from number of values");

    final CommonsTreeMap  ret = newSortedMap ();
    final Iterator  itk = aKeys.iterator ();
    final Iterator  itv = aValues.iterator ();
    while (itk.hasNext ())
      ret.put (itk.next (), itv.next ());
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static , VALUETYPE> CommonsTreeMap  newSortedMap (@Nullable final Map  aMap)
  {
    if (isEmpty (aMap))
      return newSortedMap ();

    final CommonsTreeMap  ret = newSortedMap ();
    ret.putAll (aMap);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static , VALUETYPE> CommonsTreeMap  newSortedMap (@Nullable final Map  [] aMaps)
  {
    if (aMaps == null || aMaps.length == 0)
      return newSortedMap ();

    final CommonsTreeMap  ret = newSortedMap ();
    for (final Map  aMap : aMaps)
      ret.putAll (aMap);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static , VALUETYPE> CommonsTreeMap  newSortedMap (@Nullable final Collection > aCollection)
  {
    if (isEmpty (aCollection))
      return newSortedMap ();

    final CommonsTreeMap  ret = newSortedMap ();
    ret.putAll (aCollection);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static , VALUETYPE> CommonsTreeMap  newSortedMap (@Nullable final Iterable > aCollection)
  {
    if (isEmpty (aCollection))
      return newSortedMap ();

    final CommonsTreeMap  ret = newSortedMap ();
    ret.putAll (aCollection);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashSet  newSet (@Nonnegative final int nInitialCapacity)
  {
    return new CommonsHashSet <> (nInitialCapacity);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashSet  newSet ()
  {
    return new CommonsHashSet <> ();
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashSet  newSetMapped (@Nullable final Collection  aCollection,
                                                                          @Nonnull final Function  aMapper)
  {
    if (isEmpty (aCollection))
      return newSet (0);
    final CommonsHashSet  ret = newSet (aCollection.size ());
    ret.addAllMapped (aCollection, aMapper);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashSet  newSetMapped (@Nullable final SRCTYPE [] aArray,
                                                                          @Nonnull final Function  aMapper)
  {
    if (ArrayHelper.isEmpty (aArray))
      return newSet (0);

    final CommonsHashSet  ret = newSet (aArray.length);
    ret.addAllMapped (aArray, aMapper);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashSet  newSet (@Nullable final Collection  aCollection,
                                                                   @Nonnull final Predicate  aFilter)
  {
    if (isEmpty (aCollection))
      return newSet (0);
    final CommonsHashSet  ret = newSet (aCollection.size ());
    ret.addAll (aCollection, aFilter);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashSet  newSet (@Nullable final ELEMENTTYPE aValue)
  {
    final CommonsHashSet  ret = newSet (1);
    ret.add (aValue);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  @SafeVarargs
  public static  CommonsHashSet  newSet (@Nullable final ELEMENTTYPE... aValues)
  {
    if (ArrayHelper.isEmpty (aValues))
      return newSet (0);

    final CommonsHashSet  ret = newSet (aValues.length);
    ret.addAll (aValues);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashSet  newSet (@Nullable final Iterable  aCont)
  {
    final CommonsHashSet  ret = newSet ();
    ret.addAll (aCont);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashSet  newSet (@Nullable final Collection  aCont)
  {
    if (isEmpty (aCont))
      return newSet (0);

    return new CommonsHashSet <> (aCont);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashSet  newSet (@Nullable final Iterator  aIter)
  {
    final CommonsHashSet  ret = newSet ();
    ret.addAll (aIter);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashSet  newSet (@Nullable final IIterableIterator  aIter)
  {
    if (aIter == null)
      return newSet (0);
    return newSet (aIter.iterator ());
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsHashSet  newSet (@Nullable final Enumeration  aEnum)
  {
    final CommonsHashSet  ret = newSet ();
    ret.addAll (aEnum);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  @SafeVarargs
  public static > EnumSet  newEnumSet (@Nonnull final Class  aEnumClass,
                                                                                           @Nullable final ELEMENTTYPE... aValues)
  {
    final EnumSet  ret = EnumSet.noneOf (aEnumClass);
    if (aValues != null)
      Collections.addAll (ret, aValues);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static > EnumSet  newEnumSet (@Nonnull final Class  aEnumClass,
                                                                                           @Nullable final Collection  aValues)
  {
    if (isEmpty (aValues))
      return EnumSet.noneOf (aEnumClass);
    return EnumSet.copyOf (aValues);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static > EnumSet  newEnumSet (@Nonnull final Class  aEnumClass,
                                                                                           @Nullable final EnumSet  aValues)
  {
    if (aValues == null)
      return EnumSet.noneOf (aEnumClass);
    return EnumSet.copyOf (aValues);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsTreeSet  newSortedSet ()
  {
    return new CommonsTreeSet <> (Comparator.nullsFirst (Comparator.naturalOrder ()));
  }

  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsTreeSet  newSortedSetMapped (@Nullable final Collection  aCollection,
                                                                                                                     @Nonnull final Function  aMapper)
  {
    final CommonsTreeSet  ret = newSortedSet ();
    ret.addAllMapped (aCollection, aMapper);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsTreeSet  newSortedSetMapped (@Nullable final SRCTYPE [] aArray,
                                                                                                                     @Nonnull final Function  aMapper)
  {
    final CommonsTreeSet  ret = newSortedSet ();
    ret.addAllMapped (aArray, aMapper);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsTreeSet  newSortedSet (@Nullable final Collection  aCollection,
                                                                                                                  @Nonnull final Predicate  aFilter)
  {
    final CommonsTreeSet  ret = newSortedSet ();
    ret.addAll (aCollection, aFilter);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  @SuppressFBWarnings (value = { "NP_PARAMETER_MUST_BE_NONNULL_BUT_MARKED_AS_NULLABLE" }, justification = "When using the constructor with the Comparator it works with null values!")
  public static > CommonsTreeSet  newSortedSet (@Nullable final ELEMENTTYPE aValue)
  {
    final CommonsTreeSet  ret = newSortedSet ();
    ret.add (aValue);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  @SafeVarargs
  public static > CommonsTreeSet  newSortedSet (@Nullable final ELEMENTTYPE... aValues)
  {
    final CommonsTreeSet  ret = newSortedSet ();
    ret.addAll (aValues);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsTreeSet  newSortedSet (@Nullable final Iterable  aCont)
  {
    final CommonsTreeSet  ret = newSortedSet ();
    ret.addAll (aCont);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsTreeSet  newSortedSet (@Nullable final Collection  aCont)
  {
    final CommonsTreeSet  ret = newSortedSet ();
    if (isNotEmpty (aCont))
      ret.addAll (aCont);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsTreeSet  newSortedSet (@Nullable final Iterator  aIter)
  {
    final CommonsTreeSet  ret = newSortedSet ();
    ret.addAll (aIter);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsTreeSet  newSortedSet (@Nullable final IIterableIterator  aIter)
  {
    if (aIter == null)
      return newSortedSet ();
    return newSortedSet (aIter.iterator ());
  }

  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsTreeSet  newSortedSet (@Nullable final Enumeration  aEnum)
  {
    final CommonsTreeSet  ret = newSortedSet ();
    ret.addAll (aEnum);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashSet  newOrderedSet (@Nonnegative final int nInitialCapacity)
  {
    return new CommonsLinkedHashSet <> (nInitialCapacity);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashSet  newOrderedSet ()
  {
    return new CommonsLinkedHashSet <> ();
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashSet  newOrderedSetMapped (@Nullable final Collection  aCollection,
                                                                                       @Nonnull final Function  aMapper)
  {
    if (isEmpty (aCollection))
      return newOrderedSet (0);
    final CommonsLinkedHashSet  ret = newOrderedSet (aCollection.size ());
    ret.addAllMapped (aCollection, aMapper);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashSet  newOrderedSetMapped (@Nullable final SRCTYPE [] aArray,
                                                                                       @Nonnull final Function  aMapper)
  {
    if (ArrayHelper.isEmpty (aArray))
      return newOrderedSet (0);
    final CommonsLinkedHashSet  ret = newOrderedSet (aArray.length);
    ret.addAllMapped (aArray, aMapper);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashSet  newOrderedSet (@Nullable final Collection  aCollection,
                                                                                @Nonnull final Predicate  aFilter)
  {
    if (isEmpty (aCollection))
      return newOrderedSet (0);
    final CommonsLinkedHashSet  ret = newOrderedSet (aCollection.size ());
    ret.addAll (aCollection, aFilter);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashSet  newOrderedSet (@Nullable final ELEMENTTYPE aValue)
  {
    final CommonsLinkedHashSet  ret = newOrderedSet (1);
    ret.add (aValue);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  @SafeVarargs
  public static  CommonsLinkedHashSet  newOrderedSet (@Nullable final ELEMENTTYPE... aValues)
  {
    if (ArrayHelper.isEmpty (aValues))
      return newOrderedSet (0);

    final CommonsLinkedHashSet  ret = newOrderedSet (aValues.length);
    Collections.addAll (ret, aValues);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashSet  newOrderedSet (@Nullable final Iterable  aCont)
  {
    final CommonsLinkedHashSet  ret = newOrderedSet ();
    ret.addAll (aCont);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashSet  newOrderedSet (@Nullable final Collection  aCont)
  {
    if (isEmpty (aCont))
      return newOrderedSet (0);
    return new CommonsLinkedHashSet <> (aCont);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashSet  newOrderedSet (@Nonnull final Iterator  aIter)
  {
    final CommonsLinkedHashSet  ret = newOrderedSet ();
    ret.addAll (aIter);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashSet  newOrderedSet (@Nullable final IIterableIterator  aIter)
  {
    if (aIter == null)
      return newOrderedSet (0);
    return newOrderedSet (aIter.iterator ());
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsLinkedHashSet  newOrderedSet (@Nullable final Enumeration  aEnum)
  {
    final CommonsLinkedHashSet  ret = newOrderedSet ();
    ret.addAll (aEnum);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newListPrefilled (@Nullable final ELEMENTTYPE aValue,
                                                                               @Nonnegative final int nElements)
  {
    ValueEnforcer.isGE0 (nElements, "Elements");

    final CommonsArrayList  ret = new CommonsArrayList <> (nElements);
    for (int i = 0; i < nElements; ++i)
      ret.add (aValue);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newList (@Nonnegative final int nInitialCapacity)
  {
    return new CommonsArrayList <> (nInitialCapacity);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newList ()
  {
    return new CommonsArrayList <> ();
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newList (@Nullable final Collection  aCollection,
                                                                      @Nonnull final Predicate  aFilter)
  {
    return CommonsArrayList.createFiltered (aCollection, aFilter);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newList (@Nullable final ELEMENTTYPE aValue)
  {
    final CommonsArrayList  ret = newList (1);
    ret.add (aValue);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  @SafeVarargs
  public static  CommonsArrayList  newList (@Nullable final ELEMENTTYPE... aValues)
  {
    // Don't user Arrays.asList since aIter returns an unmodifiable list!
    if (ArrayHelper.isEmpty (aValues))
      return newList (0);

    final CommonsArrayList  ret = newList (aValues.length);
    ret.addAll (aValues);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newListMapped (@Nullable final SRCTYPE [] aValues,
                                                                             @Nonnull final Function  aMapper)
  {
    // Don't user Arrays.asList since aIter returns an unmodifiable list!
    if (ArrayHelper.isEmpty (aValues))
      return newList (0);

    final CommonsArrayList  ret = newList (aValues.length);
    ret.addAllMapped (aValues, aMapper);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newListMapped (@Nullable final Iterable  aIter,
                                                                                 @Nonnull final Function  aMapper)
  {
    final CommonsArrayList  ret = newList ();
    ret.addAllMapped (aIter, aMapper);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newListMapped (@Nullable final Collection  aCollection,
                                                                             @Nonnull final Function  aMapper)
  {
    if (isEmpty (aCollection))
      return newList (0);
    final CommonsArrayList  ret = newList (aCollection.size ());
    ret.addAllMapped (aCollection, aMapper);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newListMapped (@Nullable final Iterable  aCollection,
                                                                                 @Nullable final Predicate  aFilter,
                                                                                 @Nonnull final Function  aMapper)
  {
    final CommonsArrayList  ret = newList ();
    ret.addAllMapped (aCollection, aFilter, aMapper);
    return ret;
  }

  /**
   * Compared to {@link Collections#list(Enumeration)} this method is more
   * flexible in Generics parameter.
   *
   * @param 
   *        Type of the elements
   * @param aEnum
   *        The enumeration to be converted
   * @return The non-null created {@link CommonsArrayList}.
   * @see Collections#list(Enumeration)
   */
  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newList (@Nullable final Enumeration  aEnum)
  {
    return new CommonsArrayList <> (aEnum);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newList (@Nullable final Iterator  aIter)
  {
    final CommonsArrayList  ret = newList ();
    ret.addAll (aIter);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newList (@Nullable final Iterable  aIter)
  {
    return new CommonsArrayList <> (aIter);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newList (@Nullable final Collection  aCont)
  {
    if (isEmpty (aCont))
      return newList (0);

    return new CommonsArrayList <> (aCont);
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  newList (@Nullable final IIterableIterator  aIter)
  {
    if (aIter == null)
      return newList (0);
    return newList (aIter.iterator ());
  }

  /**
   * Convert the given iterator to a sorted list.
   *
   * @param 
   *        The type of elements to iterate. May not be null.
   * @param aIter
   *        Input iterator. May be null.
   * @return a non-null {@link CommonsArrayList} based on the results of
   *         {@link Collections#sort(List)}.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsArrayList  getSorted (@Nullable final IIterableIterator  aIter)
  {
    return getSortedInline (newList (aIter));
  }

  /**
   * Convert the given iterator to a sorted list.
   *
   * @param 
   *        The type of elements to iterate. May not be null.
   * @param aIter
   *        Input iterator. May be null.
   * @param aComparator
   *        The comparator to use. May not be null.
   * @return a non-null {@link CommonsArrayList} based on the results of
   *         {@link Collections#sort(List)}.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsArrayList  getSorted (@Nullable final IIterableIterator  aIter,
                                                                                                                 @Nonnull final Comparator  aComparator)
  {
    return getSortedInline (newList (aIter), aComparator);
  }

  /**
   * Convert the given iterator to a sorted list.
   *
   * @param 
   *        The type of elements to iterate. May not be null.
   * @param aIter
   *        Input iterator. May not be null.
   * @return a non-null {@link CommonsArrayList} based on the results of
   *         {@link Collections#sort(List)}.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsArrayList  getSorted (@Nullable final Iterator  aIter)
  {
    return getSortedInline (newList (aIter));
  }

  /**
   * Convert the given iterator to a sorted list.
   *
   * @param 
   *        The type of elements to iterate.
   * @param aIter
   *        Input iterator. May be null.
   * @param aComparator
   *        The comparator to use. May not be null.
   * @return a non-null {@link CommonsArrayList} based on the results of
   *         {@link Collections#sort(List, Comparator)}.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  getSorted (@Nullable final Iterator  aIter,
                                                                        @Nonnull final Comparator  aComparator)
  {
    return getSortedInline (newList (aIter), aComparator);
  }

  /**
   * Convert the given iterable object to a sorted list.
   *
   * @param 
   *        The type of element to iterate.
   * @param aCont
   *        Iterable input object. May be null.
   * @return A {@link CommonsArrayList} based on the results of
   *         {@link Collections#sort(List)}.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsArrayList  getSorted (@Nullable final Iterable  aCont)
  {
    return getSortedInline (newList (aCont));
  }

  /**
   * Convert the given iterable object to a sorted list.
   *
   * @param 
   *        The type of element to iterate.
   * @param aCont
   *        Iterable input object. May be null.
   * @param aComparator
   *        The comparator to use. May not be null.
   * @return A {@link CommonsArrayList} based on the results of
   *         {@link Collections#sort(List, Comparator)}.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  getSorted (@Nullable final Iterable  aCont,
                                                                        @Nonnull final Comparator  aComparator)
  {
    return getSortedInline (newList (aCont), aComparator);
  }

  /**
   * Convert the given collection object to a sorted list.
   *
   * @param 
   *        The type of element to iterate.
   * @param aCont
   *        Collection input object. May be null.
   * @return A {@link CommonsArrayList} based on the results of
   *         {@link Collections#sort(List)}.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static > CommonsArrayList  getSorted (@Nullable final Collection  aCont)
  {
    return getSortedInline (newList (aCont));
  }

  /**
   * Convert the given collection object to a sorted list.
   *
   * @param 
   *        The type of element to iterate.
   * @param aCont
   *        Collection input object. May be null.
   * @param aComparator
   *        The comparator to use. May not be null.
   * @return A {@link CommonsArrayList} based on the results of
   *         {@link Collections#sort(List, Comparator)}.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  getSorted (@Nullable final Collection  aCont,
                                                                        @Nonnull final Comparator  aComparator)
  {
    return getSortedInline (newList (aCont), aComparator);
  }

  /**
   * Convert the given iterable object to a sorted list.
   *
   * @param 
   *        The type of element to iterate.
   * @param aCont
   *        Array input object. May be null.
   * @return A {@link CommonsArrayList} based on the results of
   *         {@link Collections#sort(List)}.
   */
  @Nonnull
  @ReturnsMutableCopy
  @SafeVarargs
  public static > CommonsArrayList  getSorted (@Nullable final ELEMENTTYPE... aCont)
  {
    return getSortedInline (newList (aCont));
  }

  /**
   * Convert the given iterable object to a sorted list.
   *
   * @param 
   *        The type of element to iterate.
   * @param aCont
   *        Iterable input object. May be null.
   * @param aComparator
   *        The comparator to use. May not be null.
   * @return A {@link CommonsArrayList} based on the results of
   *         {@link Collections#sort(List, Comparator)}.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  getSorted (@Nullable final ELEMENTTYPE [] aCont,
                                                                        @Nonnull final Comparator  aComparator)
  {
    return getSortedInline (newList (aCont), aComparator);
  }

  @Nullable
  @ReturnsMutableObject ("design")
  @CodingStyleguideUnaware
  public static , LISTTYPE extends List > LISTTYPE getSortedInline (@Nullable final LISTTYPE aList)
  {
    if (isNotEmpty (aList))
      aList.sort (null);
    return aList;
  }

  @Nullable
  @ReturnsMutableObject ("design")
  @CodingStyleguideUnaware
  public static > LISTTYPE getSortedInline (@Nullable final LISTTYPE aList,
                                                                                             @Nonnull final Comparator  aComparator)
  {
    ValueEnforcer.notNull (aComparator, "Comparator");

    if (isNotEmpty (aList))
      aList.sort (aComparator);
    return aList;
  }

  /**
   * Get a map sorted by aIter's keys. Because no comparator is defined, the key
   * type needs to implement the {@link java.lang.Comparable} interface.
   *
   * @param 
   *        map key type
   * @param 
   *        map value type
   * @param aMap
   *        the map to sort
   * @return the sorted map and never null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static , VALUETYPE> ICommonsOrderedMap  getSortedByKey (@Nullable final Map  aMap)
  {
    if (isEmpty (aMap))
      return newOrderedMap (0);

    // get sorted entry list
    final ICommonsList > aList = newList (aMap.entrySet ());
    aList.sort (Comparator.comparing (Map.Entry::getKey));
    return newOrderedMap (aList);
  }

  /**
   * Get a map sorted by its keys. The comparison order is defined by the passed
   * comparator object.
   *
   * @param 
   *        map key type
   * @param 
   *        map value type
   * @param aMap
   *        The map to sort. May not be null.
   * @param aKeyComparator
   *        The comparator to be used. May not be null.
   * @return the sorted map and never null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static  ICommonsOrderedMap  getSortedByKey (@Nullable final Map  aMap,
                                                                                             @Nonnull final Comparator  aKeyComparator)
  {
    ValueEnforcer.notNull (aKeyComparator, "KeyComparator");

    if (isEmpty (aMap))
      return newOrderedMap (0);

    // get sorted Map.Entry list by Entry.getValue ()
    final ICommonsList > aList = newList (aMap.entrySet ());
    aList.sort (Comparator.comparing (Map.Entry::getKey, aKeyComparator));
    return newOrderedMap (aList);
  }

  /**
   * Get a map sorted by its values. Because no comparator is defined, the value
   * type needs to implement the {@link java.lang.Comparable} interface.
   *
   * @param 
   *        map key type
   * @param 
   *        map value type
   * @param aMap
   *        The map to sort. May not be null.
   * @return the sorted map and never null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static > ICommonsOrderedMap  getSortedByValue (@Nullable final Map  aMap)
  {
    if (isEmpty (aMap))
      return newOrderedMap (0);

    // get sorted entry list
    final ICommonsList > aList = newList (aMap.entrySet ());
    aList.sort (Comparator.comparing (Map.Entry::getValue));
    return newOrderedMap (aList);
  }

  /**
   * Get a map sorted by aIter's values. The comparison order is defined by the
   * passed comparator object.
   *
   * @param 
   *        map key type
   * @param 
   *        map value type
   * @param aMap
   *        The map to sort. May not be null.
   * @param aValueComparator
   *        The comparator to be used. May not be null.
   * @return the sorted map and never null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static  ICommonsOrderedMap  getSortedByValue (@Nullable final Map  aMap,
                                                                                               @Nonnull final Comparator  aValueComparator)
  {
    ValueEnforcer.notNull (aValueComparator, "ValueComparator");

    if (isEmpty (aMap))
      return newOrderedMap (0);

    // get sorted Map.Entry list by Entry.getValue ()
    final ICommonsList > aList = newList (aMap.entrySet ());
    aList.sort (Comparator.comparing (Map.Entry::getValue, aValueComparator));
    return newOrderedMap (aList);
  }

  @Nullable
  @ReturnsMutableCopy
  public static  CommonsArrayList  getReverseList (@Nullable final Collection  aCollection)
  {
    if (isEmpty (aCollection))
      return newList (0);

    final CommonsArrayList  ret = newList (aCollection);
    ret.reverse ();
    return ret;
  }

  @Nullable
  @ReturnsMutableObject ("semantics of this method")
  @CodingStyleguideUnaware
  public static > LISTTYPE getReverseInlineList (@Nullable final LISTTYPE aList)
  {
    if (aList == null)
      return null;

    Collections.reverse (aList);
    return aList;
  }

  /**
   * Get a map consisting only of a set of specified keys. If an element from
   * the key set is not contained in the original map, the key is ignored.
   *
   * @param 
   *        Source map key type.
   * @param 
   *        Source map value type.
   * @param aValues
   *        Source map to filter. May not be null.
   * @param aKeys
   *        The filter set to filter the entries from. May not be
   *        null.
   * @return A non-null map containing only the elements from the
   *         specified key set.
   */
  @Nullable
  @ReturnsMutableCopy
  public static  ICommonsMap  getFilteredMap (@Nullable final ICommonsMap  aValues,
                                                                      @Nullable final Collection  aKeys)
  {
    if (isEmpty (aValues) || isEmpty (aKeys))
      return null;

    final ICommonsMap  ret = newMap ();
    for (final KEY aKey : aKeys)
      if (aValues.containsKey (aKey))
        ret.put (aKey, aValues.get (aKey));
    return ret;
  }

  /**
   * Get the first element of the passed list.
   *
   * @param 
   *        List element type
   * @param aList
   *        The list. May be null.
   * @return null if the list is null or empty, the
   *         first element otherwise.
   */
  @Nullable
  public static  ELEMENTTYPE getFirstElement (@Nullable final List  aList)
  {
    return isEmpty (aList) ? null : aList.get (0);
  }

  /**
   * Get the first element of the passed collection.
   *
   * @param 
   *        Collection element type
   * @param aCollection
   *        The collection. May be null.
   * @return null if the collection is null or empty,
   *         the first element otherwise.
   */
  @Nullable
  public static  ELEMENTTYPE getFirstElement (@Nullable final Collection  aCollection)
  {
    return isEmpty (aCollection) ? null : aCollection.iterator ().next ();
  }

  /**
   * Get the first element of the passed iterable.
   *
   * @param 
   *        Iterable element type
   * @param aIterable
   *        The iterable. May be null.
   * @return null if the iterable is null or empty,
   *         the first element otherwise.
   */
  @Nullable
  public static  ELEMENTTYPE getFirstElement (@Nullable final Iterable  aIterable)
  {
    return getFirstElement (aIterable, (ELEMENTTYPE) null);
  }

  /**
   * Get the first element of the passed iterable.
   *
   * @param 
   *        Iterable element type
   * @param aIterable
   *        The iterable. May be null.
   * @param aDefault
   *        The default value to be returned, if no such value is present. May
   *        be null.
   * @return null if the iterable is null or empty,
   *         the first element otherwise.
   * @since 10.1.3
   */
  @Nullable
  public static  ELEMENTTYPE getFirstElement (@Nullable final Iterable  aIterable,
                                                           @Nullable final ELEMENTTYPE aDefault)
  {
    if (aIterable != null)
    {
      final Iterator  it = aIterable.iterator ();
      if (it.hasNext ())
        return it.next ();
    }
    return aDefault;
  }

  @Nullable
  public static  ELEMENTTYPE removeFirstElement (@Nullable final List  aList)
  {
    return isEmpty (aList) ? null : aList.remove (0);
  }

  @Nullable
  public static  ELEMENTTYPE getLastElement (@Nullable final List  aList)
  {
    final int nSize = getSize (aList);
    return nSize == 0 ? null : aList.get (nSize - 1);
  }

  @Nullable
  public static  ELEMENTTYPE getLastElement (@Nullable final Collection  aCollection)
  {
    if (isEmpty (aCollection))
      return null;

    // Slow but shouldn't matter
    ELEMENTTYPE aLast = null;
    for (final ELEMENTTYPE aElement : aCollection)
      aLast = aElement;
    return aLast;
  }

  @Nullable
  public static  ELEMENTTYPE getLastElement (@Nullable final Iterable  aIterable)
  {
    if (aIterable == null)
      return null;

    // Slow but shouldn't matter
    ELEMENTTYPE aLast = null;
    for (final ELEMENTTYPE aElement : aIterable)
      aLast = aElement;
    return aLast;
  }

  /**
   * Remove the element at the specified index from the passed list. This works
   * if the list is not null and the index is ≥ 0 and <
   * list.size()
   *
   * @param aList
   *        The list to remove an element from. May be null.
   * @param nIndex
   *        The index to be removed. May be arbitrary.
   * @return {@link EChange#CHANGED} if removal was successful
   * @see #removeAndReturnElementAtIndex(List, int)
   */
  @Nonnull
  public static EChange removeAtIndex (@Nullable final List  aList, final int nIndex)
  {
    if (aList == null || nIndex < 0 || nIndex >= aList.size ())
      return EChange.UNCHANGED;
    aList.remove (nIndex);
    return EChange.CHANGED;
  }

  /**
   * Remove the element at the specified index from the passed list. This works
   * if the list is not null and the index is ≥ 0 and <
   * list.size()
   *
   * @param 
   *        List element type
   * @param aList
   *        The list to remove an element from. May be null.
   * @param nIndex
   *        The index to be removed. May be arbitrary.
   * @return null if removal failed or the removed element. Note:
   *         the removed element may also be null so it may be
   *         tricky to determine if removal succeeded or not!
   * @see #removeAtIndex(List, int)
   */
  @Nullable
  public static  ELEMENTTYPE removeAndReturnElementAtIndex (@Nullable final List  aList,
                                                                         final int nIndex)
  {
    if (aList == null || nIndex < 0 || nIndex >= aList.size ())
      return null;
    return aList.remove (nIndex);
  }

  @Nullable
  public static  ELEMENTTYPE removeLastElement (@Nullable final List  aList)
  {
    final int nSize = getSize (aList);
    return nSize == 0 ? null : aList.remove (nSize - 1);
  }

  public static boolean isEmpty (@Nullable final Iterable  aCont)
  {
    return aCont == null || !aCont.iterator ().hasNext ();
  }

  public static boolean isEmpty (@Nullable final Collection  aCont)
  {
    return aCont == null || aCont.isEmpty ();
  }

  public static boolean isEmpty (@Nullable final Map  aCont)
  {
    return aCont == null || aCont.isEmpty ();
  }

  public static boolean isNotEmpty (@Nullable final Iterable  aCont)
  {
    return aCont != null && aCont.iterator ().hasNext ();
  }

  public static boolean isNotEmpty (@Nullable final Collection  aCont)
  {
    return aCont != null && !aCont.isEmpty ();
  }

  public static boolean isNotEmpty (@Nullable final Map  aCont)
  {
    return aCont != null && !aCont.isEmpty ();
  }

  /**
   * Retrieve the size of the passed {@link Collection}. This method handles
   * null containers.
   *
   * @param aCollection
   *        Object to check. May be null.
   * @return The size of the object or 0 if the passed parameter is
   *         null.
   */
  @Nonnegative
  public static int getSize (@Nullable final Collection  aCollection)
  {
    return aCollection == null ? 0 : aCollection.size ();
  }

  /**
   * Retrieve the size of the passed {@link Map}. This method handles
   * null containers.
   *
   * @param aMap
   *        Object to check. May be null.
   * @return The size of the object or 0 if the passed parameter is
   *         null.
   */
  @Nonnegative
  public static int getSize (@Nullable final Map  aMap)
  {
    return aMap == null ? 0 : aMap.size ();
  }

  /**
   * Retrieve the size of the passed {@link Iterable}.
   *
   * @param aIterable
   *        Iterator to check. May be null.
   * @return The number objects or 0 if the passed parameter is
   *         null.
   */
  @Nonnegative
  public static int getSize (@Nullable final Iterable  aIterable)
  {
    return aIterable == null ? 0 : IteratorHelper.getSize (aIterable.iterator ());
  }

  /**
   * Retrieve the size of the passed {@link Enumeration}.
   *
   * @param aEnumeration
   *        Enumeration to check. May be null.
   * @return The number objects or 0 if the passed parameter is
   *         null.
   */
  @Nonnegative
  public static int getSize (@Nullable final Enumeration  aEnumeration)
  {
    int ret = 0;
    if (aEnumeration != null)
      while (aEnumeration.hasMoreElements ())
      {
        aEnumeration.nextElement ();
        ++ret;
      }
    return ret;
  }

  @Nullable
  @ReturnsMutableCopy
  public static  CommonsArrayList  getConcatenatedList (@Nullable final Collection  aCollection1,
                                                                                  @Nullable final Collection  aCollection2)
  {
    final int nSize1 = getSize (aCollection1);
    if (nSize1 == 0)
      return newList (aCollection2);

    final int nSize2 = getSize (aCollection2);
    if (nSize2 == 0)
      return newList (aCollection1);

    final CommonsArrayList  ret = newList (nSize1 + nSize2);
    ret.addAll (aCollection1);
    ret.addAll (aCollection2);
    return ret;
  }

  @Nullable
  @ReturnsMutableCopy
  @SafeVarargs
  public static  CommonsArrayList  getConcatenatedList (@Nullable final Collection  aCont1,
                                                                                  @Nullable final ELEMENTTYPE... aCont2)
  {
    final int nSize1 = getSize (aCont1);
    if (nSize1 == 0)
      return newList (aCont2);

    final int nSize2 = ArrayHelper.getSize (aCont2);
    if (nSize2 == 0)
      return newList (aCont1);

    final CommonsArrayList  ret = newList (nSize1 + nSize2);
    ret.addAll (aCont1);
    Collections.addAll (ret, aCont2);
    return ret;
  }

  @Nullable
  @ReturnsMutableCopy
  public static  CommonsArrayList  getConcatenatedList (@Nullable final ELEMENTTYPE [] aCont1,
                                                                                  @Nullable final Collection  aCont2)
  {
    final int nSize1 = ArrayHelper.getSize (aCont1);
    if (nSize1 == 0)
      return newList (aCont2);

    final int nSize2 = getSize (aCont2);
    if (nSize2 == 0)
      return newList (aCont1);

    final CommonsArrayList  ret = newList (nSize1 + nSize2);
    Collections.addAll (ret, aCont1);
    ret.addAll (aCont2);
    return ret;
  }

  @Nullable
  @ReturnsMutableCopy
  public static  ICommonsSet  getConcatenatedSet (@Nullable final Collection  aCont1,
                                                                            @Nullable final Collection  aCont2)
  {
    final int nSize1 = getSize (aCont1);
    if (nSize1 == 0)
      return newSet (aCont2);

    final int nSize2 = getSize (aCont2);
    if (nSize2 == 0)
      return newSet (aCont1);

    final ICommonsSet  ret = newSet (nSize1 + nSize2);
    ret.addAll (aCont1);
    ret.addAll (aCont2);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  @SafeVarargs
  public static  ICommonsSet  getConcatenatedSet (@Nullable final Collection  aCont1,
                                                                            @Nullable final ELEMENTTYPE... aCont2)
  {
    final int nSize1 = getSize (aCont1);
    if (nSize1 == 0)
      return newSet (aCont2);

    final int nSize2 = ArrayHelper.getSize (aCont2);
    if (nSize2 == 0)
      return newSet (aCont1);

    final ICommonsSet  ret = newSet (nSize1 + nSize2);
    ret.addAll (aCont1);
    Collections.addAll (ret, aCont2);
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public static  ICommonsSet  getConcatenatedSet (@Nullable final ELEMENTTYPE [] aCont1,
                                                                            @Nullable final Collection  aCont2)
  {
    final int nSize1 = ArrayHelper.getSize (aCont1);
    if (nSize1 == 0)
      return newSet (aCont2);

    final int nSize2 = getSize (aCont2);
    if (nSize2 == 0)
      return newSet (aCont1);

    final ICommonsSet  ret = newSet (nSize1 + nSize2);
    Collections.addAll (ret, aCont1);
    ret.addAll (aCont2);
    return ret;
  }

  @Nonnull
  @ReturnsMutableObject ("design")
  @SafeVarargs
  @CodingStyleguideUnaware
  public static > COLLTYPE getConcatenatedInline (@Nonnull final COLLTYPE aCont,
                                                                                                                 @Nullable final ELEMENTTYPE... aElementsToAdd)
  {
    ValueEnforcer.notNull (aCont, "Container");

    if (aElementsToAdd != null)
      Collections.addAll (aCont, aElementsToAdd);
    return aCont;
  }

  @Nonnull
  @ReturnsMutableObject ("design")
  @CodingStyleguideUnaware
  public static > COLLTYPE getConcatenatedInline (@Nonnull final COLLTYPE aCont,
                                                                                                                 @Nullable final Collection  aElementsToAdd)
  {
    ValueEnforcer.notNull (aCont, "Container");

    if (aElementsToAdd != null)
      aCont.addAll (aElementsToAdd);
    return aCont;
  }

  /**
   * Create a map that contains the combination of the other 2 maps. Both maps
   * need to have the same key and value type.
   *
   * @param 
   *        The map key type.
   * @param 
   *        The map value type.
   * @param aMap1
   *        The first map. May be null.
   * @param aMap2
   *        The second map. May be null.
   * @return Never null and always a new object. If both parameters
   *         are not null a new map is created, initially
   *         containing the entries from the first parameter, afterwards
   *         extended by the parameters of the second map potentially
   *         overwriting elements from the first map.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static  ICommonsMap  getCombinedMap (@Nullable final Map  aMap1,
                                                                      @Nullable final Map  aMap2)
  {
    if (isEmpty (aMap1))
      return newMap (aMap2);
    if (isEmpty (aMap2))
      return newMap (aMap1);

    // create and fill result map
    final ICommonsMap  ret = new CommonsHashMap <> (aMap1);
    ret.putAll (aMap2);
    return ret;
  }

  @Nullable
  @ReturnsMutableCopy
  public static CommonsArrayList  newObjectListFromArray (@Nullable final Object aValue,
                                                             @Nonnull final Class  aComponentType)
  {
    if (aValue == null)
      return null;

    if (aComponentType == boolean.class)
    {
      // get as CommonsList
      return PrimitiveCollectionHelper.newPrimitiveList ((boolean []) aValue);
    }
    if (aComponentType == byte.class)
    {
      // get as CommonsList
      return PrimitiveCollectionHelper.newPrimitiveList ((byte []) aValue);
    }
    if (aComponentType == char.class)
    {
      // get as CommonsList
      return PrimitiveCollectionHelper.newPrimitiveList ((char []) aValue);
    }
    if (aComponentType == double.class)
    {
      // get as CommonsList
      return PrimitiveCollectionHelper.newPrimitiveList ((double []) aValue);
    }
    if (aComponentType == float.class)
    {
      // get as CommonsList
      return PrimitiveCollectionHelper.newPrimitiveList ((float []) aValue);
    }
    if (aComponentType == int.class)
    {
      // get as CommonsList
      return PrimitiveCollectionHelper.newPrimitiveList ((int []) aValue);
    }
    if (aComponentType == long.class)
    {
      // get as CommonsList
      return PrimitiveCollectionHelper.newPrimitiveList ((long []) aValue);
    }
    if (aComponentType == short.class)
    {
      // get as CommonsList
      return PrimitiveCollectionHelper.newPrimitiveList ((short []) aValue);
    }

    // the rest
    final Object [] aArray = (Object []) aValue;
    if (ArrayHelper.isEmpty (aArray))
      return null;

    final CommonsArrayList  ret = newList (aArray.length);
    Collections.addAll (ret, aArray);
    return ret;
  }

  /**
   * Gets a sublist excerpt of the passed list.
   *
   * @param 
   *        Type of elements in list
   * @param aCont
   *        The backing list. May not be null.
   * @param nStartIndex
   *        The start index to use. Needs to be ≥ 0.
   * @param nSectionLength
   *        the length of the desired subset. If list is shorter than that,
   *        aIter will return a shorter section
   * @return The specified section of the passed list, or a shorter list if
   *         nStartIndex + nSectionLength is an invalid index. Never
   *         null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public static  CommonsArrayList  getSubList (@Nullable final List  aCont,
                                                                         @Nonnegative final int nStartIndex,
                                                                         @Nonnegative final int nSectionLength)
  {
    ValueEnforcer.isGE0 (nStartIndex, "StartIndex");
    ValueEnforcer.isGE0 (nSectionLength, "SectionLength");

    final int nSize = getSize (aCont);
    if (nSize == 0 || nStartIndex >= nSize)
      return newList (0);

    int nEndIndex = nStartIndex + nSectionLength;
    if (nEndIndex > nSize)
      nEndIndex = nSize;

    // Create a copy of the list because "subList" only returns a view of the
    // original list!
    return newList (aCont.subList (nStartIndex, nEndIndex));
  }

  public static  boolean contains (@Nullable final Collection  aCollection,
                                                @Nullable final ELEMENTTYPE aSearch)
  {
    if (isEmpty (aCollection))
      return false;

    return aCollection.contains (aSearch);
  }

  @Nullable
  public static  ELEMENTTYPE findFirst (@Nullable final Iterable  aCollection,
                                                     @Nullable final Predicate  aFilter)
  {
    // use null as default
    return findFirst (aCollection, aFilter, (ELEMENTTYPE) null);
  }

  @Nullable
  public static  ELEMENTTYPE findFirst (@Nullable final Iterable  aCollection,
                                                     @Nullable final Predicate  aFilter,
                                                     @Nullable final ELEMENTTYPE aDefault)
  {
    if (aFilter == null)
      return getFirstElement (aCollection, aDefault);

    if (isNotEmpty (aCollection))
      for (final ELEMENTTYPE aElement : aCollection)
        if (aFilter.test (aElement))
          return aElement;

    return aDefault;
  }

  @Nullable
  public static  DSTTYPE findFirstMapped (@Nullable final Iterable  aCollection,
                                                                @Nullable final Predicate  aFilter,
                                                                @Nonnull final Function  aMapper)
  {
    return findFirstMapped (aCollection, aFilter, aMapper, (DSTTYPE) null);
  }

  @Nullable
  public static  DSTTYPE findFirstMapped (@Nullable final Iterable  aCollection,
                                                                @Nullable final Predicate  aFilter,
                                                                @Nonnull final Function  aMapper,
                                                                @Nullable final DSTTYPE aDefault)
  {
    ValueEnforcer.notNull (aMapper, "Mapper");

    if (isNotEmpty (aCollection))
    {
      if (aFilter == null)
        return aMapper.apply (aCollection.iterator ().next ());

      for (final ELEMENTTYPE aElement : aCollection)
        if (aFilter.test (aElement))
          return aMapper.apply (aElement);
    }

    return aDefault;
  }

  public static  void findAll (@Nullable final Iterable  aSrc,
                                            @Nullable final Predicate  aFilter,
                                            @Nonnull final Consumer  aConsumer)
  {
    ValueEnforcer.notNull (aConsumer, "Consumer");

    if (isNotEmpty (aSrc))
    {
      if (aFilter == null)
        aSrc.forEach (aConsumer);
      else
      {
        for (final ELEMENTTYPE aElement : aSrc)
          if (aFilter.test (aElement))
            aConsumer.accept (aElement);
      }
    }
  }

  public static  void findAllMapped (@Nullable final Iterable  aSrc,
                                                       @Nonnull final Function  aMapper,
                                                       @Nonnull final Consumer  aConsumer)
  {
    ValueEnforcer.notNull (aMapper, "Mapper");
    ValueEnforcer.notNull (aConsumer, "Consumer");

    if (isNotEmpty (aSrc))
      for (final SRCTYPE aElement : aSrc)
        aConsumer.accept (aMapper.apply (aElement));
  }

  /**
   * Iterate, filter, map, add.
   *
   * @param aSrc
   *        Source collection. May be null.
   * @param aFilter
   *        Filter on source object to use. May be null.
   * @param aMapper
   *        Mapping function. May not be null.
   * @param aConsumer
   *        Destination consumer. May not be null.
   * @param 
   *        Source object type
   * @param 
   *        Destination object type
   */
  public static  void findAllMapped (@Nullable final Iterable  aSrc,
                                                       @Nullable final Predicate  aFilter,
                                                       @Nonnull final Function  aMapper,
                                                       @Nonnull final Consumer  aConsumer)
  {
    ValueEnforcer.notNull (aMapper, "Mapper");
    ValueEnforcer.notNull (aConsumer, "Consumer");

    if (aFilter == null)
      findAllMapped (aSrc, aMapper, aConsumer);
    else
      if (isNotEmpty (aSrc))
        for (final SRCTYPE aElement : aSrc)
          if (aFilter.test (aElement))
            aConsumer.accept (aMapper.apply (aElement));
  }

  /**
   * Iterate, map, filter, add.
   *
   * @param aSrc
   *        Source collection. May be null.
   * @param aMapper
   *        Mapping function. May not be null.
   * @param aFilter
   *        Filter on mapped object to use. May be null.
   * @param aConsumer
   *        Destination consumer. May not be null.
   * @param 
   *        Source object type
   * @param 
   *        Destination object type
   * @since 8.5.2
   */
  public static  void findAllMapped (@Nullable final Iterable  aSrc,
                                                       @Nonnull final Function  aMapper,
                                                       @Nullable final Predicate  aFilter,
                                                       @Nonnull final Consumer  aConsumer)
  {
    ValueEnforcer.notNull (aMapper, "Mapper");
    ValueEnforcer.notNull (aConsumer, "Consumer");

    if (aFilter == null)
      findAllMapped (aSrc, aMapper, aConsumer);
    else
      if (isNotEmpty (aSrc))
        for (final SRCTYPE aElement : aSrc)
        {
          final DSTTYPE aMapped = aMapper.apply (aElement);
          if (aFilter.test (aMapped))
            aConsumer.accept (aMapped);
        }
  }

  /**
   * Count the number of elements in the passed iterable (collection) matching
   * the provided filter.
   *
   * @param aCollection
   *        The collection to count. May not be null.
   * @param aFilter
   *        The filter to be applied. May be null.
   * @return The number of matching elements. Always ≥ 0. If no filter is
   *         provided this is the same as {@link #getSize(Iterable)}.
   * @param 
   *        The element type to count
   */
  @Nonnegative
  public static  int getCount (@Nullable final Iterable  aCollection,
                                            @Nullable final Predicate  aFilter)
  {
    if (aFilter == null)
      return getSize (aCollection);

    int ret = 0;
    if (isNotEmpty (aCollection))
      for (final ELEMENTTYPE aElement : aCollection)
        if (aFilter.test (aElement))
          ret++;
    return ret;
  }

  /**
   * Count the number of elements in the passed collection matching the provided
   * filter.
   *
   * @param aCollection
   *        The collection to count. May not be null.
   * @param aFilter
   *        The filter to be applied. May be null.
   * @return The number of matching elements. Always ≥ 0. If no filter is
   *         provided this is the same as {@link #getSize(Collection)}.
   * @param 
   *        The element type to count
   */
  @Nonnegative
  public static  int getCount (@Nullable final Collection  aCollection,
                                            @Nullable final Predicate  aFilter)
  {
    if (aFilter == null)
      return getSize (aCollection);

    int ret = 0;
    if (isNotEmpty (aCollection))
      for (final ELEMENTTYPE aElement : aCollection)
        if (aFilter.test (aElement))
          ret++;
    return ret;
  }

  public static  boolean containsAny (@Nullable final Iterable  aCollection,
                                                   @Nullable final Predicate  aFilter)
  {
    if (aFilter == null)
      return isNotEmpty (aCollection);

    if (isNotEmpty (aCollection))
      for (final ELEMENTTYPE aElement : aCollection)
        if (aFilter.test (aElement))
          return true;
    return false;
  }

  public static  boolean containsNone (@Nullable final Iterable  aCollection,
                                                    @Nullable final Predicate  aFilter)
  {
    if (aFilter == null)
      return isEmpty (aCollection);

    for (final ELEMENTTYPE aElement : aCollection)
      if (aFilter.test (aElement))
        return false;
    return true;
  }

  /**
   * Check if the passed collection contains only elements matching the
   * predicate. An empty collection does not fulfill this requirement! If no
   * filter is provided the return value is identical to
   * {@link #isNotEmpty(Iterable)}
   *
   * @param aCollection
   *        The collection to check. May be null.
   * @param aFilter
   *        Predicate to check against all elements. May not be
   *        null.
   * @return true only if the passed collection is neither
   *         null nor empty and if only matching elements are
   *         contained, or if no filter is provided and the collection is not
   *         empty.
   * @param 
   *        Collection data type
   */
  public static  boolean containsOnly (@Nullable final Iterable  aCollection,
                                                    @Nullable final Predicate  aFilter)
  {
    if (isEmpty (aCollection))
      return false;

    if (aFilter == null)
      return isNotEmpty (aCollection);

    for (final ELEMENTTYPE aElement : aCollection)
      if (!aFilter.test (aElement))
        return false;
    return true;
  }

  /**
   * Check if the passed collection contains at least one null
   * element.
   *
   * @param aCont
   *        The collection to check. May be null.
   * @return true only if the passed collection is neither
   *         null nor empty and if at least one null
   *         element is contained.
   */
  public static boolean containsAnyNullElement (@Nullable final Iterable  aCont)
  {
    return containsAny (aCont, Objects::isNull);
  }

  /**
   * Check if the passed collection contains only null element.
   *
   * @param aCont
   *        The collection to check. May be null.
   * @return true only if the passed collection is neither
   *         null nor empty and if at least one null
   *         element is contained.
   */
  public static boolean containsOnlyNullElements (@Nullable final Iterable  aCont)
  {
    return containsOnly (aCont, Objects::isNull);
  }

  /**
   * Safe list element accessor method.
   *
   * @param aList
   *        The list to extract from. May be null.
   * @param nIndex
   *        The index to access. Should be ≥ 0.
   * @return null if the element cannot be accessed.
   * @param 
   *        The type of elements on the list.
   */
  @Nullable
  public static  ELEMENTTYPE getAtIndex (@Nullable final List  aList,
                                                      final int nIndex)
  {
    return getAtIndex (aList, nIndex, (ELEMENTTYPE) null);
  }

  /**
   * Safe list element accessor method.
   *
   * @param aList
   *        The list to extract from. May be null.
   * @param nIndex
   *        The index to access. Should be ≥ 0.
   * @param aDefault
   *        The value to be returned, if the index is out of bounds.
   * @return The default parameter if the element cannot be accessed.
   * @param 
   *        The type of elements on the list.
   */
  @Nullable
  public static  ELEMENTTYPE getAtIndex (@Nullable final List  aList,
                                                      final int nIndex,
                                                      @Nullable final ELEMENTTYPE aDefault)
  {
    return aList != null && nIndex >= 0 && nIndex < aList.size () ? aList.get (nIndex) : aDefault;
  }

  @Nullable
  public static  ELEMENTTYPE getAtIndex (@Nullable final Iterable  aCollection,
                                                      @Nonnegative final int nIndex)
  {
    return getAtIndex (aCollection, nIndex, (ELEMENTTYPE) null);
  }

  @Nullable
  public static  ELEMENTTYPE getAtIndex (@Nullable final Iterable  aCollection,
                                                      @Nonnegative final int nIndex,
                                                      @Nullable final ELEMENTTYPE aDefault)
  {
    if (nIndex >= 0)
    {
      int nCurIndex = 0;
      for (final ELEMENTTYPE aElement : aCollection)
      {
        if (nCurIndex == nIndex)
          return aElement;
        ++nCurIndex;
      }
    }
    return aDefault;
  }

  @Nullable
  public static  ELEMENTTYPE getAtIndex (@Nullable final Iterable  aCollection,
                                                      @Nullable final Predicate  aFilter,
                                                      @Nonnegative final int nIndex)
  {
    return getAtIndex (aCollection, aFilter, nIndex, (ELEMENTTYPE) null);
  }

  @Nullable
  public static  ELEMENTTYPE getAtIndex (@Nullable final Iterable  aCollection,
                                                      @Nullable final Predicate  aFilter,
                                                      @Nonnegative final int nIndex,
                                                      @Nullable final ELEMENTTYPE aDefault)
  {
    if (aFilter == null)
      return getAtIndex (aCollection, nIndex, aDefault);

    if (nIndex >= 0)
    {
      int nCurIndex = 0;
      for (final ELEMENTTYPE aElement : aCollection)
        if (aFilter.test (aElement))
        {
          if (nCurIndex == nIndex)
            return aElement;
          ++nCurIndex;
        }
    }
    return aDefault;
  }

  @Nullable
  public static  DSTTYPE getAtIndexMapped (@Nullable final Iterable  aCollection,
                                                             @Nonnegative final int nIndex,
                                                             @Nonnull final Function  aMapper)
  {
    return getAtIndexMapped (aCollection, nIndex, aMapper, (DSTTYPE) null);
  }

  @Nullable
  public static  DSTTYPE getAtIndexMapped (@Nullable final Iterable  aCollection,
                                                             @Nonnegative final int nIndex,
                                                             @Nonnull final Function  aMapper,
                                                             @Nullable final DSTTYPE aDefault)
  {
    if (nIndex >= 0)
    {
      int nCurIndex = 0;
      for (final SRCTYPE aElement : aCollection)
      {
        if (nCurIndex == nIndex)
          return aMapper.apply (aElement);
        ++nCurIndex;
      }
    }
    return aDefault;
  }

  @Nullable
  public static  DSTTYPE getAtIndexMapped (@Nullable final Iterable  aCollection,
                                                             @Nullable final Predicate  aFilter,
                                                             @Nonnegative final int nIndex,
                                                             @Nonnull final Function  aMapper)
  {
    return getAtIndexMapped (aCollection, aFilter, nIndex, aMapper, (DSTTYPE) null);
  }

  @Nullable
  public static  DSTTYPE getAtIndexMapped (@Nullable final Iterable  aCollection,
                                                             @Nullable final Predicate  aFilter,
                                                             @Nonnegative final int nIndex,
                                                             @Nonnull final Function  aMapper,
                                                             @Nullable final DSTTYPE aDefault)
  {
    if (aFilter == null)
      return getAtIndexMapped (aCollection, nIndex, aMapper, aDefault);

    if (nIndex >= 0)
    {
      int nCurIndex = 0;
      for (final SRCTYPE aElement : aCollection)
        if (aFilter.test (aElement))
        {
          if (nCurIndex == nIndex)
            return aMapper.apply (aElement);
          ++nCurIndex;
        }
    }
    return aDefault;
  }
}