001 /* 002 * Copyright (C) 2008 The Guava Authors 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package com.google.common.collect; 018 019 import static com.google.common.base.Preconditions.checkArgument; 020 import static com.google.common.base.Preconditions.checkNotNull; 021 022 import com.google.common.annotations.GwtCompatible; 023 import com.google.common.base.Function; 024 import com.google.common.base.Joiner; 025 import com.google.common.base.Predicate; 026 import com.google.common.base.Predicates; 027 028 import java.util.AbstractCollection; 029 import java.util.ArrayList; 030 import java.util.Collection; 031 import java.util.Collections; 032 import java.util.Iterator; 033 034 /** 035 * Provides static methods for working with {@code Collection} instances. 036 * 037 * @author Chris Povirk 038 * @author Mike Bostock 039 * @author Jared Levy 040 * @since 2 (imported from Google Collections Library) 041 */ 042 @GwtCompatible 043 public final class Collections2 { 044 private Collections2() {} 045 046 /** 047 * Returns the elements of {@code unfiltered} that satisfy a predicate. The 048 * returned collection is a live view of {@code unfiltered}; changes to one 049 * affect the other. 050 * 051 * <p>The resulting collection's iterator does not support {@code remove()}, 052 * but all other collection methods are supported. When given an element that 053 * doesn't satisfy the predicate, the collection's {@code add()} and {@code 054 * addAll()} methods throw an {@link IllegalArgumentException}. When methods 055 * such as {@code removeAll()} and {@code clear()} are called on the filtered 056 * collection, only elements that satisfy the filter will be removed from the 057 * underlying collection. 058 * 059 * <p>The returned collection isn't threadsafe or serializable, even if 060 * {@code unfiltered} is. 061 * 062 * <p>Many of the filtered collection's methods, such as {@code size()}, 063 * iterate across every element in the underlying collection and determine 064 * which elements satisfy the filter. When a live view is <i>not</i> needed, 065 * it may be faster to copy {@code Iterables.filter(unfiltered, predicate)} 066 * and use the copy. 067 * 068 * <p><b>Warning:</b> {@code predicate} must be <i>consistent with equals</i>, 069 * as documented at {@link Predicate#apply}. Do not provide a predicate such 070 * as {@code Predicates.instanceOf(ArrayList.class)}, which is inconsistent 071 * with equals. (See {@link Iterables#filter(Iterable, Class)} for related 072 * functionality.) 073 */ 074 public static <E> Collection<E> filter( 075 Collection<E> unfiltered, Predicate<? super E> predicate) { 076 if (unfiltered instanceof FilteredCollection) { 077 // Support clear(), removeAll(), and retainAll() when filtering a filtered 078 // collection. 079 return ((FilteredCollection<E>) unfiltered).createCombined(predicate); 080 } 081 082 return new FilteredCollection<E>( 083 checkNotNull(unfiltered), checkNotNull(predicate)); 084 } 085 086 /** 087 * Delegates to {@link Collection#contains}. Returns {@code false} on {@code 088 * ClassCastException} 089 */ 090 static boolean safeContains(Collection<?> collection, Object object) { 091 try { 092 return collection.contains(object); 093 } catch (ClassCastException e) { 094 return false; 095 } 096 } 097 098 static class FilteredCollection<E> implements Collection<E> { 099 final Collection<E> unfiltered; 100 final Predicate<? super E> predicate; 101 102 FilteredCollection(Collection<E> unfiltered, 103 Predicate<? super E> predicate) { 104 this.unfiltered = unfiltered; 105 this.predicate = predicate; 106 } 107 108 FilteredCollection<E> createCombined(Predicate<? super E> newPredicate) { 109 return new FilteredCollection<E>(unfiltered, 110 Predicates.<E>and(predicate, newPredicate)); 111 // .<E> above needed to compile in JDK 5 112 } 113 114 @Override 115 public boolean add(E element) { 116 checkArgument(predicate.apply(element)); 117 return unfiltered.add(element); 118 } 119 120 @Override 121 public boolean addAll(Collection<? extends E> collection) { 122 for (E element : collection) { 123 checkArgument(predicate.apply(element)); 124 } 125 return unfiltered.addAll(collection); 126 } 127 128 @Override 129 public void clear() { 130 Iterables.removeIf(unfiltered, predicate); 131 } 132 133 @Override 134 public boolean contains(Object element) { 135 try { 136 // unsafe cast can result in a CCE from predicate.apply(), which we 137 // will catch 138 @SuppressWarnings("unchecked") 139 E e = (E) element; 140 141 /* 142 * We check whether e satisfies the predicate, when we really mean to 143 * check whether the element contained in the set does. This is ok as 144 * long as the predicate is consistent with equals, as required. 145 */ 146 return predicate.apply(e) && unfiltered.contains(element); 147 } catch (NullPointerException e) { 148 return false; 149 } catch (ClassCastException e) { 150 return false; 151 } 152 } 153 154 @Override 155 public boolean containsAll(Collection<?> collection) { 156 for (Object element : collection) { 157 if (!contains(element)) { 158 return false; 159 } 160 } 161 return true; 162 } 163 164 @Override 165 public boolean isEmpty() { 166 return !Iterators.any(unfiltered.iterator(), predicate); 167 } 168 169 @Override 170 public Iterator<E> iterator() { 171 return Iterators.filter(unfiltered.iterator(), predicate); 172 } 173 174 @Override 175 public boolean remove(Object element) { 176 try { 177 // unsafe cast can result in a CCE from predicate.apply(), which we 178 // will catch 179 @SuppressWarnings("unchecked") 180 E e = (E) element; 181 182 // See comment in contains() concerning predicate.apply(e) 183 return predicate.apply(e) && unfiltered.remove(element); 184 } catch (NullPointerException e) { 185 return false; 186 } catch (ClassCastException e) { 187 return false; 188 } 189 } 190 191 @Override 192 public boolean removeAll(final Collection<?> collection) { 193 checkNotNull(collection); 194 Predicate<E> combinedPredicate = new Predicate<E>() { 195 @Override 196 public boolean apply(E input) { 197 return predicate.apply(input) && collection.contains(input); 198 } 199 }; 200 return Iterables.removeIf(unfiltered, combinedPredicate); 201 } 202 203 @Override 204 public boolean retainAll(final Collection<?> collection) { 205 checkNotNull(collection); 206 Predicate<E> combinedPredicate = new Predicate<E>() { 207 @Override 208 public boolean apply(E input) { 209 // See comment in contains() concerning predicate.apply(e) 210 return predicate.apply(input) && !collection.contains(input); 211 } 212 }; 213 return Iterables.removeIf(unfiltered, combinedPredicate); 214 } 215 216 @Override 217 public int size() { 218 return Iterators.size(iterator()); 219 } 220 221 @Override 222 public Object[] toArray() { 223 // creating an ArrayList so filtering happens once 224 return Lists.newArrayList(iterator()).toArray(); 225 } 226 227 @Override 228 public <T> T[] toArray(T[] array) { 229 return Lists.newArrayList(iterator()).toArray(array); 230 } 231 232 @Override public String toString() { 233 return Iterators.toString(iterator()); 234 } 235 } 236 237 /** 238 * Returns a collection that applies {@code function} to each element of 239 * {@code fromCollection}. The returned collection is a live view of {@code 240 * fromCollection}; changes to one affect the other. 241 * 242 * <p>The returned collection's {@code add()} and {@code addAll()} methods 243 * throw an {@link UnsupportedOperationException}. All other collection 244 * methods are supported, as long as {@code fromCollection} supports them. 245 * 246 * <p>The returned collection isn't threadsafe or serializable, even if 247 * {@code fromCollection} is. 248 * 249 * <p>When a live view is <i>not</i> needed, it may be faster to copy the 250 * transformed collection and use the copy. 251 */ 252 public static <F, T> Collection<T> transform(Collection<F> fromCollection, 253 Function<? super F, T> function) { 254 return new TransformedCollection<F, T>(fromCollection, function); 255 } 256 257 static class TransformedCollection<F, T> extends AbstractCollection<T> { 258 final Collection<F> fromCollection; 259 final Function<? super F, ? extends T> function; 260 261 TransformedCollection(Collection<F> fromCollection, 262 Function<? super F, ? extends T> function) { 263 this.fromCollection = checkNotNull(fromCollection); 264 this.function = checkNotNull(function); 265 } 266 267 @Override public void clear() { 268 fromCollection.clear(); 269 } 270 271 @Override public boolean isEmpty() { 272 return fromCollection.isEmpty(); 273 } 274 275 @Override public Iterator<T> iterator() { 276 return Iterators.transform(fromCollection.iterator(), function); 277 } 278 279 @Override public int size() { 280 return fromCollection.size(); 281 } 282 } 283 284 /** 285 * Returns {@code true} if the collection {@code self} contains all of the 286 * elements in the collection {@code c}. 287 * 288 * <p>This method iterates over the specified collection {@code c}, checking 289 * each element returned by the iterator in turn to see if it is contained in 290 * the specified collection {@code self}. If all elements are so contained, 291 * {@code true} is returned, otherwise {@code false}. 292 * 293 * @param self a collection which might contain all elements in {@code c} 294 * @param c a collection whose elements might be contained by {@code self} 295 */ 296 static boolean containsAllImpl(Collection<?> self, Collection<?> c) { 297 checkNotNull(self); 298 for (Object o : c) { 299 if (!self.contains(o)) { 300 return false; 301 } 302 } 303 return true; 304 } 305 306 /** 307 * An implementation of {@link Collection#toString()}. 308 */ 309 static String toStringImpl(final Collection<?> collection) { 310 StringBuilder sb 311 = newStringBuilderForCollection(collection.size()).append('['); 312 STANDARD_JOINER.appendTo( 313 sb, Iterables.transform(collection, new Function<Object, Object>() { 314 @Override public Object apply(Object input) { 315 return input == collection ? "(this Collection)" : input; 316 } 317 })); 318 return sb.append(']').toString(); 319 } 320 321 /** 322 * Returns best-effort-sized StringBuilder based on the given collection size. 323 */ 324 static StringBuilder newStringBuilderForCollection(int size) { 325 checkArgument(size >= 0, "size must be non-negative"); 326 return new StringBuilder((int) Math.min(size * 8L, 1 << 30)); 327 } 328 329 /** 330 * Used to avoid http://bugs.sun.com/view_bug.do?bug_id=6558557 331 */ 332 static <T> Collection<T> cast(Iterable<T> iterable) { 333 return (Collection<T>) iterable; 334 } 335 336 static final Joiner STANDARD_JOINER = Joiner.on(", "); 337 338 // TODO(user): Maybe move the mathematical methods to a separate 339 // package-permission class. 340 }