Java tutorial
/* Copyright (C) 2013-2014 Ian Teune <ian.teune@gmail.com> * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package com.tinspx.util.collect; import com.google.common.base.Function; import com.google.common.base.Optional; import static com.google.common.base.Preconditions.*; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.ForwardingCollection; import com.google.common.collect.ForwardingList; import com.google.common.collect.ForwardingSet; import com.google.common.collect.HashMultiset; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.common.collect.Multiset; import com.google.common.collect.SetMultimap; import com.google.common.collect.Table; import com.tinspx.util.base.Base; import java.io.Serializable; import java.util.AbstractList; import java.util.AbstractSet; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.NavigableSet; import java.util.NoSuchElementException; import java.util.RandomAccess; import java.util.Set; import java.util.SortedSet; import javax.annotation.Nullable; /** * Basic Collection and Iterator related utility methods * * @author Ian */ public class CollectUtils { private CollectUtils() { }; /** * Adds all elements in the {@code add} Iterable to the {@code collection} * Collection. If {@code add} is a Collection, the * {@link Collection#addAll(java.util.Collection)} method will be used, * else each element of the Iterbale will be added one at a time * * @param collection the Collection that id added to * @param add the Iterable of elements that will be added to the collection * @return the {@code collection} argument */ @SuppressWarnings("unchecked") public static <C extends Collection<E>, E> C addAll(C collection, Iterable<? extends E> add) { if (add instanceof Collection) { collection.addAll((Collection<E>) add); } else { for (E a : add) { collection.add(a); } } return collection; } /** * Differs from * {@link Lists#transform(java.util.List, com.google.common.base.Function)} * in that the transformation is not lazy. Rather, a new List is created and * the items are all copied and transformed once into the new List. */ public static <F, T> List<T> transformCopy(List<F> from, Function<? super F, ? extends T> function) { List<T> to = Lists.newArrayListWithCapacity(from.size()); for (F item : from) { to.add(function.apply(item)); } return to; } /** * Returns a new ArrayList from a nullable list of elements. If * {@code elements} is null or empty, an empty ArrayList is returned. * * @param elements the initial elements of the returned ArrayList, may be * null * @return a new ArrayList with initially containing {@code elements} */ public static <E> java.util.ArrayList<E> newArrayList(@Nullable Iterable<? extends E> elements) { return elements != null ? Lists.<E>newArrayList(elements) : Lists.<E>newArrayList(); } /** * Determines the size of the nullable {@code collection} argument, * returning 0 if it is null. * * @param collection the nullable Collection to determine its size * @return the size of {@code collection} or 0 if null */ public static int size(@Nullable Collection<?> collection) { return collection != null ? collection.size() : 0; } /** * Determines if the Collection is null or empty * * @param collection the Collection to check * @return true of {@code collection} is null or empty */ public static boolean isNullOrEmpty(@Nullable Collection<?> collection) { return collection != null ? collection.isEmpty() : true; } public static <T> Iterable<T> synchronizedIterable(final Iterable<T> iterable) { checkNotNull(iterable); return new Iterable<T>() { @Override public Iterator<T> iterator() { return synchronizedIterator(iterable.iterator()); } }; } public static <T> Iterator<T> synchronizedIterator(final Iterator<T> iter) { checkNotNull(iter); return new Iterator<T>() { @Override public synchronized boolean hasNext() { return iter.hasNext(); } @Override public synchronized T next() { return iter.next(); } @Override public synchronized void remove() { iter.remove(); } }; } /** * Creates a singleton Iterable for {@code element} * * @param element the sole element of the returned Iterable * @return a singleton Iterable whose sole element is {@code element} */ public static <T> Iterable<T> iterable(@Nullable final T element) { return iterable(element, null); } /** * Creates a singleton Iterable for {@code element}. If {@code onRemove} * is not null, {@link Iterator#remove()} will call the Function with * {@code element} as the apply argument. {@code onRemove} should return * a Boolean determining if the remove is allowed; if {@code onRemove} * returns false from apply, an UnsupportedOperationException will be * thrown. * * @param element the sole element of the returned Iterable * @param onRemove Function called when when {@code element} is removed. The * Function may throw any unchecked exception; if false is returned from * the Function, an UnsupportedOperationException is thrown from remove. * @return a singleton Iterable whose sole element is {@code element} */ public static <T> Iterable<T> iterable(@Nullable final T element, @Nullable final Function<? super T, Boolean> onRemove) { return new Iterable<T>() { @Override public Iterator<T> iterator() { return CollectUtils.iterator(element, onRemove); } }; } /** * Creates a singleton Iterator for {@code element} * * @param element the sole element of the returned Iterator * @return a singleton Iterator whose sole element is {@code element} */ public static <T> Iterator<T> iterator(@Nullable final T element) { return iterator(element, null); } /** * Creates a singleton Iterator for {@code element}. If {@code onRemove} * is not null, {@link Iterator#remove()} will call the Function with * {@code element} as the apply argument. {@code onRemove} should return * a Boolean determining if the remove is allowed; if {@code onRemove} * returns false from apply, an UnsupportedOperationException will be * thrown. * * @param element the sole element of the returned Iterable * @param onRemove Function called when when {@code element} is removed. The * Function may throw any unchecked exception; if false is returned from * the Function, an UnsupportedOperationException is thrown from remove. * @return a singleton Iterable whose sole element is {@code element} */ public static <T> Iterator<T> iterator(@Nullable final T element, @Nullable final Function<? super T, Boolean> onRemove) { return new Iterator<T>() { private boolean returned; private boolean removed; @Override public boolean hasNext() { return !returned; } @Override public T next() { if (returned) { throw new NoSuchElementException(); } returned = true; return element; } @Override public void remove() { if (returned) { if (removed) { throw new IllegalStateException("removed already called"); } else { removed = true; } if (onRemove == null || !onRemove.apply(element)) { throw new UnsupportedOperationException(); } } else { throw new IllegalStateException("next never called"); } } }; } /** * appends {@code value} to the <i>end</i> of {@code iter} */ public static <T> Iterable<T> concat(Iterable<? extends T> iter, T value) { return Iterables.concat(iter, iterable(value)); } /** * appends {@code value} to the <i>end</i> of {@code iter} */ public static <T> Iterator<T> concat(Iterator<? extends T> iter, T value) { return Iterators.concat(iter, iterator(value)); } /** * prepends {@code value} to the <i>beginning</i> of {@code iter} */ public static <T> Iterable<T> concat(T value, Iterable<? extends T> iter) { return Iterables.concat(iterable(value), iter); } /** * prepends {@code value} to the <i>beginning</i> of {@code iter} */ public static <T> Iterator<T> concat(T value, Iterator<? extends T> iter) { return Iterators.concat(iterator(value), iter); } public static <T> Iterable<T> copy(Iterable<T> iter) { return ImmutableList.copyOf(iter); } public static <T> Iterable<T> copy(T... items) { return Arrays.asList(items.clone()); } /** * Returns {@code iterable} as is if not null or an empty Iterable if * {@code iterable} is null. * * @param iterable the Iterable to convert to an empty Iterable if null * @return {@code iterable} or an empty Iterable if {@code iterable} is * null. */ public static <T> Iterable<T> nullToEmptyIterable(@Nullable Iterable<T> iterable) { return iterable != null ? iterable : Collections.<T>emptyList(); } /** * Returns {@code iterator} as is if not null or an empty Iterator if * {@code iterator} is null. * * @param iterator the Iterator to convert to an empty Iterator if null * @return {@code iterator} or an empty Iterable if {@code iterator} is * null. */ public static <T> Iterator<T> nullToEmptyIterator(@Nullable Iterator<T> iterator) { return iterator != null ? iterator : ImmutableSet.<T>of().iterator(); } /** * Returns a Collection that forwards all {@link Collection} methods to * {@code view}, but modifications to the returned Collection are applied to * both {@code source} and {@code view}. * <p> * {@code view} is intended to be a "view" or subset of {@code source} (this * is not a requirement however). The returned Collection forwards all * {@link Collection} interface method calls to {@code view} * unconditionally. Therefore, any modifications made to the returned * Collection are done in exactly the same manner to {@code view}. However, * any changes made to {@code view} are also done to {@code source}. All * elements added to the returned Collection are added to both {@code view} * and {@code source}. Likewise, any elements removed are removed from both * {@code view} and {@code source}. In cases like removeAll and retainAll, * only the elements <i>actually</i> removed from {@code view} are then * removed from {@code source} (retainAll and removeAll are not directly * forwarded to {@code source} - exactly what elements that were removed * from {@code view} must be determined and then those elements are * removed from {@code source}). * <p> * This function returns a Collection that essentially links {@code view} to * {@code source}. The intended use case is when {@code view} is a subset of * {@code source} acquired through some filtering mechanism, and it is * desired that any changes made to {@code view} be reflected in * {@code source}. * <p> * Although the returned Collection forwards all Collection methods to * {@code view}, {@code linkCollections(source, view).equals(view)} will * return false. * <p> * If {@code source} and {@code view} are the same reference, then that * reference is returned as is. * <p> * {@link #linkSets(java.util.Set, java.util.Set)} and * {@link #linkSortedSets(java.util.Set, java.util.SortedSet)} perform the * exact same thing, except return a Set and SortedSet, respectively. * * @param source the source Collection, all modifications done to * {@code view} are mirrored to source * @param view the view Collection, the returned Collection forwards all * calls to view * @return a Collection that wraps {@code view} but modifications are * applied to both {@code source} and {@code view} */ public static <T> Collection<T> linkCollections(Collection<T> source, Collection<T> view) { if (source == view) { return checkNotNull(view); } return LinkingCollection.linkCollections(source, view); } /** * Returns a Set equal to {@code view}, but all modifications made to the * returned Set are performed to both {@code source} and {@code view}. * <p> * See {@link #linkCollections(java.util.Collection, java.util.Collection)} * for more detailed documentation. This function performs the exact same * operation on its arguments except on Sets rather than Collections and * therefore {@code linkSets(source, view).equals(view)} will return true. * * @param source the source Set, all modifications done to {@code view} are * mirrored to source * @param view the view Set, the returned Set is equal to view and forwards * all calls to view * @return a Set that wraps {@code view} but modifications are applied to * both {@code source} and {@code view} */ public static <T> Set<T> linkSets(Set<T> source, Set<T> view) { if (source == view) { return checkNotNull(view); } return LinkingSet.linkSets(source, view); } /** * Returns a SortedSet equal to {@code view}, but all modifications made to * the returned SortedSet are performed to both {@code source} and * {@code view}. * <p> * See {@link #linkCollections(java.util.Collection, java.util.Collection)} * for more detailed documentation. This function performs the exact same * operation on its arguments except on SortedSets rather than Collections * and therefore {@code linkSortedSets(source, view).equals(view)} will * return true. * * @param source the source Set, all modifications done to {@code view} are * mirrored to source * @param view the view SortedSet, the returned SortedSet is equal to view * and forwards all calls to view * @return a SortedSet that wraps {@code view} but modifications are applied * to both {@code source} and {@code view} */ public static <T> SortedSet<T> linkSortedSets(Set<T> source, SortedSet<T> view) { if (source == view) { return checkNotNull(view); } return LinkingSortedSet.linkSortedSets(source, view); } /** * * @param <S> the source collection type * @param <D> the delegate collection type * @param <T> the element type of both source and delegate */ static class LinkingCollection<S extends Collection<T>, D extends Collection<T>, T> extends ForwardingCollection<T> { static <S extends Collection<T>, D extends Collection<T>, T> LinkingCollection<S, D, T> linkCollections( S source, D delegate) { return new LinkingCollection<S, D, T>(source, delegate); } final S source; final D delegate; public LinkingCollection(S source, D delegate) { this.source = checkNotNull(source); this.delegate = checkNotNull(delegate); } @Override protected D delegate() { return delegate; } @Override public boolean add(T e) { if (delegate.add(e)) { source.add(e); return true; } else { return false; } } @Override public boolean remove(Object o) { if (delegate.remove(o)) { source.remove(o); return true; } else { return false; } } @Override public boolean addAll(Collection<? extends T> c) { if (delegate.addAll(c)) { source.addAll(c); return true; } else { return false; } } @Override public boolean retainAll(Collection<?> retain) { List<Object> removed = new java.util.ArrayList<Object>(); Iterator<?> it = delegate.iterator(); while (it.hasNext()) { Object object = it.next(); if (!retain.contains(object)) { removed.add(object); } } if (removed.isEmpty()) { return false; } else { delegate.retainAll(retain); source.removeAll(removed); return true; } } @Override public boolean removeAll(Collection<?> remove) { List<Object> removed = new java.util.ArrayList<Object>(); Iterator<?> it = delegate.iterator(); while (it.hasNext()) { Object object = it.next(); if (remove.contains(object)) { removed.add(object); } } if (removed.isEmpty()) { return false; } else { delegate.removeAll(remove); source.removeAll(removed); return true; } } @Override public void clear() { source.removeAll(delegate); delegate.clear(); } @Override public Iterator<T> iterator() { return new LinkedIterator<T>(delegate.iterator(), source); } } static class LinkedIterator<T> implements Iterator<T> { final Iterator<T> delegate; final Collection<T> source; T current; public LinkedIterator(Iterator<T> delegate, Collection<T> source) { this.delegate = checkNotNull(delegate); this.source = checkNotNull(source); } @Override public boolean hasNext() { return delegate.hasNext(); } @Override public T next() { current = delegate.next(); return current; } @Override public void remove() { delegate.remove(); source.remove(current); } } static class LinkingSet<S extends Set<T>, D extends Set<T>, T> extends LinkingCollection<S, D, T> implements Set<T> { static <S extends Set<T>, D extends Set<T>, T> LinkingSet<S, D, T> linkSets(S source, D delegate) { return new LinkingSet<S, D, T>(source, delegate); } public LinkingSet(S source, D delegate) { super(source, delegate); } @Override @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") public boolean equals(Object object) { return object == this || delegate.equals(object); } @Override public int hashCode() { return delegate.hashCode(); } } static class LinkingSortedSet<S extends Set<T>, D extends SortedSet<T>, T> extends LinkingSet<S, D, T> implements SortedSet<T> { static <S extends Set<T>, D extends SortedSet<T>, T> LinkingSortedSet<S, D, T> linkSortedSets(S source, D delegate) { return new LinkingSortedSet<S, D, T>(source, delegate); } public LinkingSortedSet(S source, D delegate) { super(source, delegate); } @Override public Comparator<? super T> comparator() { return delegate.comparator(); } private SortedSet<T> link(SortedSet<T> newDelegate) { if (newDelegate == delegate) { return this; } else { return linkSortedSets(source, newDelegate); } } @Override public SortedSet<T> subSet(T fromElement, T toElement) { return link(delegate.subSet(fromElement, toElement)); } @Override public SortedSet<T> headSet(T toElement) { return link(delegate.headSet(toElement)); } @Override public SortedSet<T> tailSet(T fromElement) { return link(delegate.tailSet(fromElement)); } @Override public T first() { return delegate.first(); } @Override public T last() { return delegate.last(); } } /** * Ensures that all elements in the specified Iterable have type * {@code cls}. An empty Iterable will always return true. * * @param elements the elements to check all have type {@code cls} * @param cls the type that all {@code elements} must be * @return true if all {@code elements} are instances of or a subtype of * {@code cls} */ public static boolean verifyType(Iterable<?> elements, Class<?> cls) { checkNotNull(cls); for (Object o : elements) { if (!cls.isInstance(o)) { return false; } } return true; } static class EmptyNavigableSet<E> extends ForwardingSet<E> implements NavigableSet<E>, Serializable { private static final long serialVersionUID = 0; static final EmptyNavigableSet<Object> INSTANCE = new EmptyNavigableSet<Object>(); @Override protected Set<E> delegate() { return Collections.emptySet(); } @Override public E lower(E e) { return null; } @Override public E floor(E e) { return null; } @Override public E ceiling(E e) { return null; } @Override public E higher(E e) { return null; } @Override public E pollFirst() { return null; } @Override public E pollLast() { return null; } @Override public NavigableSet<E> descendingSet() { return this; } @Override public Iterator<E> descendingIterator() { return ImmutableSet.<E>of().iterator(); } @Override public NavigableSet<E> subSet(E fromElement, boolean fromInclusive, E toElement, boolean toInclusive) { return this; } @Override public NavigableSet<E> headSet(E toElement, boolean inclusive) { return this; } @Override public NavigableSet<E> tailSet(E fromElement, boolean inclusive) { return this; } @Override public SortedSet<E> subSet(E fromElement, E toElement) { return this; } @Override public SortedSet<E> headSet(E toElement) { return this; } @Override public SortedSet<E> tailSet(E fromElement) { return this; } @Override public Comparator<? super E> comparator() { return null; } @Override public E first() { throw new NoSuchElementException(); } @Override public E last() { throw new NoSuchElementException(); } } @SuppressWarnings("unchecked") public static <T> SortedSet<T> emptySortedSet() { return (SortedSet<T>) EmptyNavigableSet.INSTANCE; } @SuppressWarnings("unchecked") public static <T> NavigableSet<T> emptyNavigableSet() { return (NavigableSet<T>) EmptyNavigableSet.INSTANCE; } /** * returns true if all elements in the Iterable are nonnull (true when * the Iterable is empty) */ public static boolean allNonNull(Iterable<?> iter) { for (Object o : iter) { if (o == null) { return false; } } return true; } public static <T extends Iterable<?>> T checkAllNotNull(T iter) { if (!allNonNull(iter)) { throw new NullPointerException(); } return iter; } public static <T extends Iterable<?>> T checkAllNotNull(T iter, String msg) { if (!allNonNull(iter)) { throw new NullPointerException(msg); } return iter; } /** * Wraps the given Collection as a Set. If {@code collection} is already a * Set, it is returned as is. If {@code collection} is not a Set, it is * wrapped in a Set thats simply forwards the Set methods to the * Collection methods of {@code collection} (the interfaces are identical). * The equals/hashCode of the returned Set have identical behavior from * those of {@link AbstractSet}. * <p> * Obviously there are some caveats of wrapping non-Set Collection as a * Set. This is provided as a utility when this hack is needed and may be * useful if a non-Set Collection is known to have only unique elements. * * @param <T> * @param collection the Collection to wrap as a Set * @return {@code collection} as is if already a Set or wrapped as a Set */ public static <T> Set<T> asSet(Collection<T> collection) { return collection instanceof Set ? (Set<T>) collection : new CollectionSet<T>(collection); } static final class CollectionSet<T> extends ForwardingCollection<T> implements Set<T>, Serializable { private static final long serialVersionUID = 0; private final Collection<T> delegate; public CollectionSet(Collection<T> delegate) { this.delegate = checkNotNull(delegate); } @Override protected Collection<T> delegate() { return delegate; } /** * delegate is not a Set so cannot forward to delegate. equals logic * here comes from {@link AbstractSet#equals(java.lang.Object)}. */ @Override public boolean equals(Object object) { if (object == this) { return true; } if (object == null || !(object instanceof Set)) { return false; } Collection<?> c = (Collection<?>) object; if (c.size() != size()) { return false; } try { return containsAll(c); } catch (ClassCastException ex) { return false; } } /** * delegate may not be a Set so cannot be forwarded to delegate. hash * logic comes from {@link AbstractSet#hashCode()}. */ @Override public int hashCode() { int h = 0; for (T element : delegate) { if (element != null) { h += element.hashCode(); } } return h; } } /** * Returns a fixed-length List containing the elements in the specified * array. The returned list is backed by the provided array and changes to * the List "write through" and are reflected in the provided array. * * @param <T> the type of the objects in the array * @param elements the array to wrap as a List * @return a List view of {@code elements} */ public static <T> List<T> asList(T... elements) { return new SubArrayList<T>(elements, 0, elements.length); } /** * Returns a fixed-length List of the first {@code len} elements in * the specified array. The returned list is backed by the provided array * and changes to the List "write through" and are reflected in the provided * array. * * @param <T> the type of the objects in the array * @param len the length of the returned array, must not be larger than * the length of {@code elements} * @param elements the array to wrap as a List * @return a List view of the first {@code len} elements in {@code elements} * @throws IndexOutOfBoundsException if {@code len > elements.length} */ public static <T> List<T> asList(int len, T... elements) { return new SubArrayList<T>(elements, 0, len); } /** * Returns a fixed-length List of a range of the specified array. The * returned list is backed by the provided array and changes to the List * "write through" and are reflected in the provided array. The returned * List will start at {@code off} in {@code elements} and will have a length * of {@code len} * * @param <T> the type of the objects in the array * @param off the index of the first element to include in the returned List * @param len the length of the returned List, starting at index {@code off} * @param elements the array to wrap as a List * @return a List view of the {@code len} elements starting at index * {@code off} in {@code elements} * @throws IndexOutOfBoundsException if {@code off} and {@code len} specify * an invalid range of {@code elements} */ public static <T> List<T> asList(int off, int len, T... elements) { return new SubArrayList<T>(elements, off, len); } static class SubArrayList<T> extends AbstractList<T> implements RandomAccess, Serializable { private static final long serialVersionUID = 0; private transient Object[] elements; //final private transient final int off; private final int len; public SubArrayList(Object[] elements, int off, int len) { this.elements = checkNotNull(elements); checkPositionIndexes(off, off + len, elements.length); this.off = off; this.len = len; } @Override @SuppressWarnings("unchecked") public T get(int index) { return (T) elements[off + checkElementIndex(index, len)]; } @Override public int size() { return len; } @Override @SuppressWarnings("unchecked") public T set(int index, T element) { index = off + checkElementIndex(index, len); T prev = (T) elements[index]; elements[index] = element; return prev; } @Override public int indexOf(Object o) { if (o == null) { for (int i = off, end = off + len; i < end; i++) { if (elements[i] == null) { return i - off; } } } else { for (int i = off, end = off + len; i < end; i++) { if (o.equals(elements[i])) { return i - off; } } } return -1; } @Override public int lastIndexOf(Object o) { if (o == null) { for (int i = off + len - 1; i >= off; i--) { if (elements[i] == null) { return i - off; } } } else { for (int i = off + len - 1; i >= off; i--) { if (o.equals(elements[i])) { return i - off; } } } return -1; } @Override public boolean contains(Object o) { return indexOf(o) != -1; } @Override public Object[] toArray() { Object[] a = new Object[len]; System.arraycopy(elements, off, a, 0, len); return a; } @Override @SuppressWarnings("unchecked") public <T> T[] toArray(T[] a) { if (a.length < len) { return Arrays.copyOfRange(elements, off, off + len, (Class<? extends T[]>) a.getClass()); } System.arraycopy(this.elements, off, a, 0, len); if (a.length > len) { a[len] = null; } return a; } @Override public List<T> subList(int fromIndex, int toIndex) { checkPositionIndexes(fromIndex, toIndex, len); return new SubArrayList<T>(elements, off + fromIndex, toIndex - fromIndex); } @Override public Iterator<T> iterator() { return new ListItr(0); } @Override public ListIterator<T> listIterator() { return new ListItr(0); } @Override public ListIterator<T> listIterator(int index) { return new ListItr(checkPositionIndex(index, len)); } private class ListItr implements ListIterator<T> { /** * the next index to return */ private int next; /** * the last index returned */ private int last = -1; public ListItr(int next) { this.next = next; } @Override public boolean hasNext() { return next < len; } @Override @SuppressWarnings("unchecked") public T next() { if (next < len) { return (T) elements[off + (last = next++)]; } throw new NoSuchElementException(); } @Override public boolean hasPrevious() { return next > 0; } @Override @SuppressWarnings("unchecked") public T previous() { if (next > 0) { return (T) elements[off + (last = --next)]; } throw new NoSuchElementException(); } @Override public int nextIndex() { return next; } @Override public int previousIndex() { return next - 1; } @Override public void set(T e) { if (last != -1) { elements[off + last] = e; } else { throw new IllegalStateException(); } } @Override public void remove() { throw new UnsupportedOperationException(); } @Override public void add(T e) { throw new UnsupportedOperationException(); } } private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); elements = new Object[len]; for (int i = 0; i < len; i++) { elements[i] = s.readObject(); } assert off == 0; } private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { s.defaultWriteObject(); for (int i = 0; i < len; i++) { s.writeObject(elements[off + i]); } } } /** * Wraps {@code list}, forcing its toString() method to return * {@code toString} * * @param list the List to force to have a toString() result of * {@code toString} * @param toString a non-null String that will be returned from toString() * of the returned List * @return a List equal to {@code list} but whose toString() returns * {@code toString} */ public static <T> List<T> wrapListWithToString(List<T> list, String toString) { return new ListWrapper<T>(list, toString); } static final class ListWrapper<T> extends ForwardingList<T> { final List<T> list; final String toString; public ListWrapper(List<T> list, String toString) { this.list = checkNotNull(list); this.toString = checkNotNull(toString); } @Override public String toString() { return toString; } @Override protected List<T> delegate() { return list; } } /** * Returns an Iterable that returns all elements in {@code iter} * {@code repeat + 1} times. Each element is "repeated" {@code repeat} * times, so a {@code repeat} of 1 causes all elements of {@code iter} to be * returned twice. If {@code repeat} is 0, {@code iter} is returned as is * (repeating 0 times has no effect). The returned Iterable supports removal * if {@code iter} supports removal. * * @param iter the Iterable to repeat * @param repeat the number of times each element is repeated. This is in * addition to the first time each element is returned, so a repeat of 2 * causes the each element in {@code iter} to be returned 3 times. * @return an Iterable that returns each element in {@code iter} * {@code repeat + 1} times */ public static <T> Iterable<T> repeatingIterable(Iterable<T> iter, int repeat) { checkArgument(repeat >= 0); return repeat > 0 ? new RepeatingIterable<T>(iter, repeat) : checkNotNull(iter); } /** * Returns an Iterator that returns all elements in {@code iter} * {@code repeat + 1} times. Each element is "repeated" {@code repeat} * times, so a {@code repeat} of 1 causes all elements of {@code iter} to be * returned twice. If {@code repeat} is 0, {@code iter} is returned as is * (repeating 0 times has no effect). The returned Iterator supports removal * if {@code iter} supports removal. * * @param iter the Iterator to repeat * @param repeat the number of times each element is repeated. This is in * addition to the first time each element is returned, so a repeat of 2 * causes the each element in {@code iter} to be returned 3 times. * @return an Iterator that returns each element in {@code iter} * {@code repeat + 1} times */ public static <T> Iterator<T> repeatingIterator(Iterator<T> iter, int repeat) { checkArgument(repeat >= 0); return repeat > 0 ? new RepeatingIterator<T>(iter, repeat) : checkNotNull(iter); } private static int checkRepeat(int repeat) { if (repeat <= 0) { throw new IllegalArgumentException(String.format("invalid repeat (%s)", repeat)); } return repeat; } static final class RepeatingIterable<T> implements Iterable<T> { final Iterable<T> delegate; final int repeat; public RepeatingIterable(Iterable<T> delegate, int repeat) { this.delegate = checkNotNull(delegate); this.repeat = checkRepeat(repeat); } @Override public Iterator<T> iterator() { return new RepeatingIterator<T>(delegate.iterator(), repeat); } } static final class RepeatingIterator<T> implements Iterator<T> { final Iterator<T> delegate; final int repeat; T current; int count; boolean canRemove, removed; public RepeatingIterator(Iterator<T> delegate, int repeat) { this.delegate = checkNotNull(delegate); this.repeat = this.count = checkRepeat(repeat); } @Override public boolean hasNext() { return count < repeat || delegate.hasNext(); } @Override public T next() { if (count < repeat) { count++; } else { current = delegate.next(); removed = false; count = 0; } canRemove = true; return current; } @Override public void remove() { if (canRemove) { canRemove = false; if (!removed) { removed = true; delegate.remove(); } } else { throw new IllegalStateException(); } } } /** * Adds all {@code key/value} entries from {@code map} to {@code map}. * * @return {@code true} if {@code multimap} was modified */ public static <K, V> boolean putAll(@lombok.NonNull Multimap<K, V> multimap, @lombok.NonNull Map<? extends K, ? extends Iterable<? extends V>> map) { boolean changed = false; for (Map.Entry<? extends K, ? extends Iterable<? extends V>> e : map.entrySet()) { if (multimap.putAll(e.getKey(), e.getValue())) { changed = true; } } return changed; } /** * Adds all {@code key/value} entries from {@code map} to {@code map}. * * @return {@code true} if {@code multimap} was modified */ public static <K, V> boolean putAllFrom(@lombok.NonNull Multimap<K, V> multimap, @lombok.NonNull Map<? extends K, ? extends V> map) { boolean changed = false; for (Map.Entry<? extends K, ? extends V> e : map.entrySet()) { if (multimap.put(e.getKey(), e.getValue())) { changed = true; } } return changed; } private static <T> Multiset<T> multiset(Collection<T> c) { return c instanceof Multiset ? (Multiset<T>) c : HashMultiset.create(c); } public static boolean equalIgnoreOrder(@Nullable Collection<?> a, @Nullable Collection<?> b) { if (a == null || b == null) { return a == null && b == null; } if (a.size() != b.size()) { return false; } if (a.equals(b)) { return true; } if (a instanceof Set && b instanceof Set) { return false; } if (a instanceof Multiset && b instanceof Multiset) { return false; } return multiset(a).equals(multiset(b)); } public static <K> boolean equalIgnoreOrder(@Nullable Multimap<K, ?> a, @Nullable Multimap<? super K, ?> b) { if (a == null || b == null) { return a == null && b == null; } if (a.size() != b.size()) { return false; } if (a.keySet().size() != b.keySet().size()) { return false; } if (a.equals(b)) { return true; } if (a instanceof SetMultimap && b instanceof SetMultimap) { return false; } for (K key : a.keySet()) { if (!equalIgnoreOrder(a.get(key), b.get(key))) { return false; } } //a and b have the same number distinct keys so don't need to iterate //over b keys return true; } public interface Selector<T> extends Function<Object, T> { /** * Convenience method equivalent to * {@code Optional.fromNullable(apply(input))}. */ Optional<T> select(Object input); } @SuppressWarnings("rawtypes") private static Collection<?> toCollection(@Nullable Object input) { if (input instanceof Collection) { return (Collection) input; } else if (input instanceof Map) { return ((Map) input).values(); } else if (input instanceof Multimap) { return ((Multimap) input).asMap().values(); } else if (input instanceof Table) { return ((Table) input).values(); } else { return Collections.emptyList(); } } @SuppressWarnings("rawtypes") private static Map<?, ?> toMap(@Nullable Object input) { if (input instanceof Map) { return (Map) input; } else if (input instanceof Multimap) { return ((Multimap) input).asMap(); } else { return Collections.emptyMap(); } } private static final Object ABSENT = new Object(); /** * Returns the element at the given index in source. index may be negative * in which it represents the number of indices from the end of the source. */ @SuppressWarnings("rawtypes") private static @Nullable Object find(Iterable source, int index) { if (source instanceof List) { List list = (List) source; if (index < 0) { index += list.size(); } return index >= 0 && index < list.size() ? list.get(index) : ABSENT; } else { return find(source, Predicates.alwaysTrue(), index); } } @SuppressWarnings("rawtypes") private static @Nullable Object find(Iterable source, Predicate predicate, int index) { if (source instanceof Collection && (Math.abs(index) + (index < 0 ? 0 : 1)) > ((Collection) source).size()) { return ABSENT; } if (index < 0) { if (source instanceof List) { return findBackwardNegative((List) source, predicate, Math.abs(index)); } else { return findForwardNegative(source, predicate, Math.abs(index)); } } else { return findForwardPositive(source, predicate, index); } } @SuppressWarnings({ "rawtypes", "unchecked" }) private static @Nullable Object findForwardPositive(Iterable source, Predicate predicate, int index) { assert index >= 0 : index; int count = 0; for (Object value : source) { if (predicate.apply(value) && count++ >= index) { return value; } } return ABSENT; } @SuppressWarnings({ "rawtypes", "unchecked" }) private static @Nullable Object findForwardNegative(Iterable source, Predicate predicate, int index) { assert index > 0 : index; int count = 0; Object[] values = new Object[index]; for (Object value : source) { if (predicate.apply(value)) { values[count++ % index] = value; } } return count >= index ? values[count % index] : ABSENT; } @SuppressWarnings({ "rawtypes", "unchecked" }) private static @Nullable Object findBackwardNegative(List source, Predicate predicate, int index) { assert index > 0 : index; index--; int count = 0; ListIterator iter = source.listIterator(source.size()); while (iter.hasPrevious()) { Object value = iter.previous(); if (predicate.apply(value) && count++ >= index) { return value; } } return ABSENT; } private static @Nullable Object absentToNull(@Nullable Object result) { return result == ABSENT ? null : result; } private static class ValueIndexSelector implements Function<Object, Object> { final int index; public ValueIndexSelector(int index) { this.index = index; } @Override public Object apply(Object root) { if (root == null) { return null; } return absentToNull(find(toCollection(root), index)); } } private static class ValuePredicateSelector implements Function<Object, Object> { final int index; final Predicate<Object> predicate; public ValuePredicateSelector(int index, Predicate<Object> predicate) { this.index = index; this.predicate = checkNotNull(predicate); } @Override @SuppressWarnings("rawtypes") public Object apply(Object root) { if (root == null) { return null; } return absentToNull(find(toCollection(root), predicate, index)); } } private static class KeyIndexSelector implements Function<Object, Object> { final int index; public KeyIndexSelector(int index) { this.index = index; } @Override @SuppressWarnings({ "rawtypes", "null" }) public Object apply(Object root) { if (root == null) { return null; } Map map = toMap(root); if (map.isEmpty()) { return null; } Object result = find(map.keySet(), index); return result == ABSENT ? null : map.get(result); } } private static class KeyPredicateSelector implements Function<Object, Object> { final int index; final Predicate<Object> predicate; public KeyPredicateSelector(int index, Predicate<Object> predicate) { this.index = index; this.predicate = checkNotNull(predicate); } @Override @SuppressWarnings({ "rawtypes", "null" }) public Object apply(Object root) { if (root == null) { return null; } Map map = toMap(root); if (map.isEmpty()) { return null; } Object result = find(map.keySet(), predicate, index); return result == ABSENT ? null : map.get(result); } } private static class KeySelector implements Function<Object, Object> { final @Nullable Object key; public KeySelector(@Nullable Object key) { this.key = key; } @Override @SuppressWarnings("null") public Object apply(Object root) { if (root == null) { return null; } return toMap(root).get(key); } } private static class PredicateSelector implements Function<Object, Object> { final Predicate<Object> predicate; public PredicateSelector(Predicate<Object> predicate) { this.predicate = checkNotNull(predicate); } @Override public Object apply(Object root) { return predicate.apply(root) ? root : null; } } private static final Predicate<Object> MAP_OR_MULTIMAP = Predicates.or(Predicates.instanceOf(Map.class), Predicates.instanceOf(Multimap.class)); /** * Returns a new {@code SelectorBuilder}. */ public static SelectorBuilder selector() { return new SelectorBuilder(); } /** * Builds a {@link Selector} for searching collection hierarchies. Create an * instance through {@link #selector()} or create a subclass. Selectors * built with this class understand following collection types: * {@code Collection} (and therefore also {@code Set} and * {@link Multiset}), {@code List}, {@code Map}, {@link Multimap}, and * {@link Table}. Note that all {@code index} parameters may be negative, in * which case the index indicates the number of positions from the end of * the collection. */ public static class SelectorBuilder extends Base.FunctionBuilder<Object> { protected SelectorBuilder() { } @Override public SelectorBuilder append(Function<? super Object, ? extends Object> function) { super.append(function); return this; } @Override public Base.FunctionBuilder<Object> prepend(Function<? super Object, ? extends Object> function) { super.prepend(function); return this; } /** * Returns true as selection cannot continue on null input. */ @Override protected boolean stopWhenNull() { return true; } /** * unsupported, throws {@code UnsupportedOperationException}. */ @Override public Base.FunctionBuilder<Object> notNull() { throw new UnsupportedOperationException(); } /** * selects the value at the given index, if possible. applies to * collections, maps, multimaps, and tables. if the collection is not a * list, index applies to the iteration order. */ public SelectorBuilder value(int index) { return append(new ValueIndexSelector(index)); } /** * selects the first value that satisfies the specified predicate. * applies to collections, maps, multimaps, and tables. */ public SelectorBuilder value(Predicate<Object> predicate) { return value(0, predicate); } /** * selects the first value that satisfies the specified predicate * <i>after</i> skipping the first {@code index} values that satisfy * the predicate. applies to collections, maps, multimaps, and tables. */ public SelectorBuilder value(int index, Predicate<Object> predicate) { return append(new ValuePredicateSelector(index, predicate)); } /** * selects the value mapped to the key at the specified index in the * map entry set. applies to maps and mulitmaps. */ public SelectorBuilder key(int index) { return append(new KeyIndexSelector(index)); } /** * selects the value mapped to the first key that satisfies the * specified predicate. applies to maps and mulitmaps. */ public SelectorBuilder key(Predicate<Object> predicate) { return key(0, predicate); } /** * selects the value mapped to the first key that satisfies the * specified predicate <i>after</i> skipping the first {@code index} * keys that satisfy the predicate. applies to maps and mulitmaps. */ public SelectorBuilder key(int index, Predicate<Object> predicate) { return append(new KeyPredicateSelector(index, predicate)); } /** * selects the value mapped to the specified key. applies to maps and * mulitmaps. */ public SelectorBuilder key(@Nullable Object key) { return append(new KeySelector(key)); } /** * requires the currently selected value to be a Map or Multimap. */ public SelectorBuilder mapOrMultimap() { return require(MAP_OR_MULTIMAP); } /** * requires the currently selected value to be a Collection. */ public SelectorBuilder collection() { return require(Collection.class); } /** * requires the currently selected value to be a Set. */ public SelectorBuilder set() { return require(Set.class); } /** * requires the currently selected value to be a List. */ public SelectorBuilder list() { return require(List.class); } /** * requires the currently selected value to be an instance of * {@code cls}. */ public SelectorBuilder require(Class<?> cls) { return require(Predicates.instanceOf(cls)); } /** * requires the currently selected value to satisfy the specified * predicate. */ public SelectorBuilder require(Predicate<Object> predicate) { return append(new PredicateSelector(predicate)); } @Override public Selector<Object> get() { return get(Object.class); } public <T> Selector<T> get(Class<T> cls) { return new CheckedSelector<T>(super.get(), cls); } } private static class CheckedSelector<T> implements Selector<T> { final Function<Object, Object> delegate; final Class<T> cls; public CheckedSelector(Function<Object, Object> delegate, Class<T> cls) { this.delegate = checkNotNull(delegate); this.cls = checkNotNull(cls); } @Override public Optional<T> select(Object root) { return Optional.fromNullable(apply(root)); } @Override public T apply(Object input) { input = delegate.apply(input); return cls.isInstance(input) ? cls.cast(input) : null; } } }