de.unkrig.commons.util.collections.CollectionUtil Maven / Gradle / Ivy
/*
* de.unkrig.commons - A general-purpose Java class library
*
* Copyright (c) 2014, Arno Unkrig
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
* following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package de.unkrig.commons.util.collections;
import java.io.Serializable;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import de.unkrig.commons.lang.AssertionUtil;
import de.unkrig.commons.nullanalysis.NotNullByDefault;
import de.unkrig.commons.nullanalysis.Nullable;
/**
* {@code java.util.collection}-related utility methods.
*/
public final
class CollectionUtil {
static { AssertionUtil.enableAssertionsForThisClass(); }
private
CollectionUtil() {}
/**
* Removes and returns the first element of the given collection. This is also known as the 'shift' operation.
*
* @return {@code null} iff the collection is empty
*/
@Nullable public static T
removeFirstFrom(Collection subject) {
Iterator it = subject.iterator();
if (!it.hasNext()) return null;
T result = it.next();
it.remove();
return result;
}
/**
* Returns an unmodifiable map, mapping the given key-value pairs. {@code null} keys and {@code null} values are
* supported.
*
* @param keyValuePairs An alternating sequence of keys and values
* @throws ArrayIndexOutOfBoundsException The length of {@code keyValuePairs} is odd
* @throws IllegalArgumentException Two of the keys are equal
*/
@SuppressWarnings("unchecked") public static Map
map(Object... keyValuePairs) {
int n = keyValuePairs.length;
if ((n & 1) == 1) throw new ArrayIndexOutOfBoundsException(n);
if (n == 0) return Collections.emptyMap();
if (n == 2) return Collections.singletonMap((K) keyValuePairs[0], (V) keyValuePairs[1]);
Map result = (
n <= 8
? new LinearMap(n / 2)
: new HashMap(n)
);
for (int i = 0; i < n;) {
if (result.put((K) keyValuePairs[i++], (V) keyValuePairs[i++]) != null) {
throw new IllegalArgumentException("Duplicate key '" + keyValuePairs[i - 2]);
}
}
return Collections.unmodifiableMap(result);
}
/**
* Returns an unmodifiable map, mapping the given key-value pairs. {@code null} keys and {@code null} values are
* supported.
*
* @throws ArrayIndexOutOfBoundsException The length of {@code keyValuePairs} is odd
* @throws IllegalArgumentException Two of the keys are equal
*/
public static Map
map(K[] keys, V[] values) {
int n = keys.length;
assert n == values.length;
if (n == 0) return Collections.emptyMap();
if (n == 1) return Collections.singletonMap(keys[0], values[0]);
Map result = (
n <= 4
? new LinearMap(n)
: new HashMap(2 * n)
);
for (int i = 0; i < n; i++) {
if (result.put(keys[i], values[i]) != null) {
throw new IllegalArgumentException("Duplicate key '" + keys[i]);
}
}
return Collections.unmodifiableMap(result);
}
/**
* Desperately missing from {@code java.util.Collections}.
*/
@SuppressWarnings("rawtypes") public static final SortedMap
EMPTY_SORTED_MAP = new EmptySortedMap();
/**
* Desperately missing from {@code java.util.Collections}.
*/
@SuppressWarnings("unchecked") public static SortedMap
emptySortedMap() { return CollectionUtil.EMPTY_SORTED_MAP; }
@NotNullByDefault(false) @SuppressWarnings("rawtypes") private static
class EmptySortedMap extends AbstractMap implements SortedMap, Serializable {
private static final long serialVersionUID = 1;
@Override public Comparator comparator() { return null; }
@Override public SortedMap subMap(Object fromKey, Object toKey) { return CollectionUtil.EMPTY_SORTED_MAP; }
@Override public SortedMap headMap(Object toKey) { return CollectionUtil.EMPTY_SORTED_MAP; }
@Override public SortedMap tailMap(Object fromKey) { return CollectionUtil.EMPTY_SORTED_MAP; }
@Override public Object firstKey() { throw new NoSuchElementException(); }
@Override public Object lastKey() { throw new NoSuchElementException(); }
@Override public int size() { return 0; }
@Override public boolean isEmpty() { return true; }
@Override public boolean containsKey(Object key) { return false; }
@Override public boolean containsValue(Object value) { return false; }
@Override public Object get(Object key) { return null; }
@Override public Set keySet() { return Collections.EMPTY_SET; }
@Override public Collection values() { return Collections.EMPTY_SET; }
@Override public Set entrySet() { return Collections.EMPTY_SET; }
@Override public boolean equals(Object o) { return (o instanceof SortedMap) && ((SortedMap) o).size() == 0; } // SUPPRESS CHECKSTYLE LineLength
@Override public int hashCode() { return 0; }
}
/**
* Desperately missing from {@code java.util.Collections}.
*/
@SuppressWarnings("rawtypes") public static final SortedSet
EMPTY_SORTED_SET = new EmptySortedSet();
/**
* Desperately missing from {@code java.util.Collections}.
*/
@SuppressWarnings("unchecked") public static SortedSet
emptySortedSet() { return CollectionUtil.EMPTY_SORTED_SET; }
@NotNullByDefault(false) @SuppressWarnings("rawtypes") private static
class EmptySortedSet extends AbstractSet implements SortedSet, Serializable {
private static final long serialVersionUID = 1L;
@Override public Iterator iterator() { return CollectionUtil.AT_END; }
@Override public int size() { return 0; }
@Override public boolean isEmpty() { return true; }
@Override public boolean contains(Object obj) { return false; }
@Override public Comparator comparator() { return null; }
@Override public SortedSet subSet(Object from, Object to) { return CollectionUtil.EMPTY_SORTED_SET; }
@Override public SortedSet headSet(Object toElement) { return CollectionUtil.EMPTY_SORTED_SET; }
@Override public SortedSet tailSet(Object fromElement) { return CollectionUtil.EMPTY_SORTED_SET; }
@Override public Object first() { throw new NoSuchElementException(); }
@Override public Object last() { throw new NoSuchElementException(); }
@Override public boolean equals(Object o) { return (o instanceof SortedSet) && ((SortedSet) o).size() == 0; } // SUPPRESS CHECKSTYLE LineLength
@Override public int hashCode() { return 0; }
}
/**
* An iterator which is at its end.
*/
@SuppressWarnings("rawtypes") public static final Iterator AT_END = new Iterator() {
@Override public boolean hasNext() { return false; }
@Override public Object next() { throw new NoSuchElementException(); }
@Override public void remove() { throw new UnsupportedOperationException(); }
};
/**
* Returns an unmodifiable collection containing the elements of the given collection, but sorted by
* their "natural ordering".
*/
@SuppressWarnings("unchecked") public static Collection
sorted(Collection collection) {
Object[] a = collection.toArray();
Arrays.sort(a);
return (Collection) Arrays.asList(a);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy