• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.collect;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 
22 import com.google.common.annotations.GwtCompatible;
23 import com.google.common.base.Function;
24 import com.google.common.base.Joiner;
25 import com.google.common.base.Predicate;
26 import com.google.common.base.Predicates;
27 import com.google.common.primitives.Ints;
28 
29 import java.util.AbstractCollection;
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.Iterator;
34 import java.util.List;
35 
36 /**
37  * Provides static methods for working with {@code Collection} instances.
38  *
39  * @author Chris Povirk
40  * @author Mike Bostock
41  * @author Jared Levy
42  * @since 2.0 (imported from Google Collections Library)
43  */
44 @GwtCompatible
45 public final class Collections2 {
Collections2()46   private Collections2() {}
47 
48   /**
49    * Returns the elements of {@code unfiltered} that satisfy a predicate. The
50    * returned collection is a live view of {@code unfiltered}; changes to one
51    * affect the other.
52    *
53    * <p>The resulting collection's iterator does not support {@code remove()},
54    * but all other collection methods are supported. When given an element that
55    * doesn't satisfy the predicate, the collection's {@code add()} and {@code
56    * addAll()} methods throw an {@link IllegalArgumentException}. When methods
57    * such as {@code removeAll()} and {@code clear()} are called on the filtered
58    * collection, only elements that satisfy the filter will be removed from the
59    * underlying collection.
60    *
61    * <p>The returned collection isn't threadsafe or serializable, even if
62    * {@code unfiltered} is.
63    *
64    * <p>Many of the filtered collection's methods, such as {@code size()},
65    * iterate across every element in the underlying collection and determine
66    * which elements satisfy the filter. When a live view is <i>not</i> needed,
67    * it may be faster to copy {@code Iterables.filter(unfiltered, predicate)}
68    * and use the copy.
69    *
70    * <p><b>Warning:</b> {@code predicate} must be <i>consistent with equals</i>,
71    * as documented at {@link Predicate#apply}. Do not provide a predicate such
72    * as {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent
73    * with equals. (See {@link Iterables#filter(Iterable, Class)} for related
74    * functionality.)
75    */
76   // TODO(kevinb): how can we omit that Iterables link when building gwt
77   // javadoc?
filter( Collection<E> unfiltered, Predicate<? super E> predicate)78   public static <E> Collection<E> filter(
79       Collection<E> unfiltered, Predicate<? super E> predicate) {
80     if (unfiltered instanceof FilteredCollection) {
81       // Support clear(), removeAll(), and retainAll() when filtering a filtered
82       // collection.
83       return ((FilteredCollection<E>) unfiltered).createCombined(predicate);
84     }
85 
86     return new FilteredCollection<E>(
87         checkNotNull(unfiltered), checkNotNull(predicate));
88   }
89 
90   /**
91    * Delegates to {@link Collection#contains}. Returns {@code false} if the
92    * {@code contains} method throws a {@code ClassCastException}.
93    */
safeContains(Collection<?> collection, Object object)94   static boolean safeContains(Collection<?> collection, Object object) {
95     try {
96       return collection.contains(object);
97     } catch (ClassCastException e) {
98       return false;
99     }
100   }
101 
102   static class FilteredCollection<E> implements Collection<E> {
103     final Collection<E> unfiltered;
104     final Predicate<? super E> predicate;
105 
FilteredCollection(Collection<E> unfiltered, Predicate<? super E> predicate)106     FilteredCollection(Collection<E> unfiltered,
107         Predicate<? super E> predicate) {
108       this.unfiltered = unfiltered;
109       this.predicate = predicate;
110     }
111 
createCombined(Predicate<? super E> newPredicate)112     FilteredCollection<E> createCombined(Predicate<? super E> newPredicate) {
113       return new FilteredCollection<E>(unfiltered,
114           Predicates.<E>and(predicate, newPredicate));
115       // .<E> above needed to compile in JDK 5
116     }
117 
118     @Override
add(E element)119     public boolean add(E element) {
120       checkArgument(predicate.apply(element));
121       return unfiltered.add(element);
122     }
123 
124     @Override
addAll(Collection<? extends E> collection)125     public boolean addAll(Collection<? extends E> collection) {
126       for (E element : collection) {
127         checkArgument(predicate.apply(element));
128       }
129       return unfiltered.addAll(collection);
130     }
131 
132     @Override
clear()133     public void clear() {
134       Iterables.removeIf(unfiltered, predicate);
135     }
136 
137     @Override
contains(Object element)138     public boolean contains(Object element) {
139       try {
140         // unsafe cast can result in a CCE from predicate.apply(), which we
141         // will catch
142         @SuppressWarnings("unchecked")
143         E e = (E) element;
144 
145         /*
146          * We check whether e satisfies the predicate, when we really mean to
147          * check whether the element contained in the set does. This is ok as
148          * long as the predicate is consistent with equals, as required.
149          */
150         return predicate.apply(e) && unfiltered.contains(element);
151       } catch (NullPointerException e) {
152         return false;
153       } catch (ClassCastException e) {
154         return false;
155       }
156     }
157 
158     @Override
containsAll(Collection<?> collection)159     public boolean containsAll(Collection<?> collection) {
160       for (Object element : collection) {
161         if (!contains(element)) {
162           return false;
163         }
164       }
165       return true;
166     }
167 
168     @Override
isEmpty()169     public boolean isEmpty() {
170       return !Iterators.any(unfiltered.iterator(), predicate);
171     }
172 
173     @Override
iterator()174     public Iterator<E> iterator() {
175       return Iterators.filter(unfiltered.iterator(), predicate);
176     }
177 
178     @Override
remove(Object element)179     public boolean remove(Object element) {
180       try {
181         // unsafe cast can result in a CCE from predicate.apply(), which we
182         // will catch
183         @SuppressWarnings("unchecked")
184         E e = (E) element;
185 
186         // See comment in contains() concerning predicate.apply(e)
187         return predicate.apply(e) && unfiltered.remove(element);
188       } catch (NullPointerException e) {
189         return false;
190       } catch (ClassCastException e) {
191         return false;
192       }
193     }
194 
195     @Override
removeAll(final Collection<?> collection)196     public boolean removeAll(final Collection<?> collection) {
197       checkNotNull(collection);
198       Predicate<E> combinedPredicate = new Predicate<E>() {
199         @Override
200         public boolean apply(E input) {
201           return predicate.apply(input) && collection.contains(input);
202         }
203       };
204       return Iterables.removeIf(unfiltered, combinedPredicate);
205     }
206 
207     @Override
retainAll(final Collection<?> collection)208     public boolean retainAll(final Collection<?> collection) {
209       checkNotNull(collection);
210       Predicate<E> combinedPredicate = new Predicate<E>() {
211         @Override
212         public boolean apply(E input) {
213           // See comment in contains() concerning predicate.apply(e)
214           return predicate.apply(input) && !collection.contains(input);
215         }
216       };
217       return Iterables.removeIf(unfiltered, combinedPredicate);
218     }
219 
220     @Override
size()221     public int size() {
222       return Iterators.size(iterator());
223     }
224 
225     @Override
toArray()226     public Object[] toArray() {
227       // creating an ArrayList so filtering happens once
228       return Lists.newArrayList(iterator()).toArray();
229     }
230 
231     @Override
toArray(T[] array)232     public <T> T[] toArray(T[] array) {
233       return Lists.newArrayList(iterator()).toArray(array);
234     }
235 
toString()236     @Override public String toString() {
237       return Iterators.toString(iterator());
238     }
239   }
240 
241   /**
242    * Returns a collection that applies {@code function} to each element of
243    * {@code fromCollection}. The returned collection is a live view of {@code
244    * fromCollection}; changes to one affect the other.
245    *
246    * <p>The returned collection's {@code add()} and {@code addAll()} methods
247    * throw an {@link UnsupportedOperationException}. All other collection
248    * methods are supported, as long as {@code fromCollection} supports them.
249    *
250    * <p>The returned collection isn't threadsafe or serializable, even if
251    * {@code fromCollection} is.
252    *
253    * <p>When a live view is <i>not</i> needed, it may be faster to copy the
254    * transformed collection and use the copy.
255    *
256    * <p>If the input {@code Collection} is known to be a {@code List}, consider
257    * {@link Lists#transform}. If only an {@code Iterable} is available, use
258    * {@link Iterables#transform}.
259    */
transform(Collection<F> fromCollection, Function<? super F, T> function)260   public static <F, T> Collection<T> transform(Collection<F> fromCollection,
261       Function<? super F, T> function) {
262     return new TransformedCollection<F, T>(fromCollection, function);
263   }
264 
265   static class TransformedCollection<F, T> extends AbstractCollection<T> {
266     final Collection<F> fromCollection;
267     final Function<? super F, ? extends T> function;
268 
TransformedCollection(Collection<F> fromCollection, Function<? super F, ? extends T> function)269     TransformedCollection(Collection<F> fromCollection,
270         Function<? super F, ? extends T> function) {
271       this.fromCollection = checkNotNull(fromCollection);
272       this.function = checkNotNull(function);
273     }
274 
clear()275     @Override public void clear() {
276       fromCollection.clear();
277     }
278 
isEmpty()279     @Override public boolean isEmpty() {
280       return fromCollection.isEmpty();
281     }
282 
iterator()283     @Override public Iterator<T> iterator() {
284       return Iterators.transform(fromCollection.iterator(), function);
285     }
286 
size()287     @Override public int size() {
288       return fromCollection.size();
289     }
290   }
291 
292   /**
293    * Returns {@code true} if the collection {@code self} contains all of the
294    * elements in the collection {@code c}.
295    *
296    * <p>This method iterates over the specified collection {@code c}, checking
297    * each element returned by the iterator in turn to see if it is contained in
298    * the specified collection {@code self}. If all elements are so contained,
299    * {@code true} is returned, otherwise {@code false}.
300    *
301    * @param self a collection which might contain all elements in {@code c}
302    * @param c a collection whose elements might be contained by {@code self}
303    */
containsAllImpl(Collection<?> self, Collection<?> c)304   static boolean containsAllImpl(Collection<?> self, Collection<?> c) {
305     checkNotNull(self);
306     for (Object o : c) {
307       if (!self.contains(o)) {
308         return false;
309       }
310     }
311     return true;
312   }
313 
314   /**
315    * An implementation of {@link Collection#toString()}.
316    */
toStringImpl(final Collection<?> collection)317   static String toStringImpl(final Collection<?> collection) {
318     StringBuilder sb
319         = newStringBuilderForCollection(collection.size()).append('[');
320     STANDARD_JOINER.appendTo(
321         sb, Iterables.transform(collection, new Function<Object, Object>() {
322           @Override public Object apply(Object input) {
323             return input == collection ? "(this Collection)" : input;
324           }
325         }));
326     return sb.append(']').toString();
327   }
328 
329   /**
330    * Returns best-effort-sized StringBuilder based on the given collection size.
331    */
newStringBuilderForCollection(int size)332   static StringBuilder newStringBuilderForCollection(int size) {
333     checkArgument(size >= 0, "size must be non-negative");
334     return new StringBuilder((int) Math.min(size * 8L, Ints.MAX_POWER_OF_TWO));
335   }
336 
337   /**
338    * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557
339    */
cast(Iterable<T> iterable)340   static <T> Collection<T> cast(Iterable<T> iterable) {
341     return (Collection<T>) iterable;
342   }
343 
344   static final Joiner STANDARD_JOINER = Joiner.on(", ");
345 
346   // TODO(user): Maybe move the mathematical methods to a separate
347   // package-permission class.
348 }
349