001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.collections4; 018 019import java.util.Arrays; 020import java.util.Collection; 021import java.util.Comparator; 022import java.util.Enumeration; 023import java.util.Iterator; 024import java.util.List; 025 026import org.apache.commons.collections4.iterators.SingletonIterator; 027 028/** 029 * A FluentIterable provides a powerful yet simple API for manipulating 030 * Iterable instances in a fluent manner. 031 * <p> 032 * A FluentIterable can be created either from an Iterable or from a set 033 * of elements. The following types of methods are provided: 034 * </p> 035 * <ul> 036 * <li>fluent methods which return a new {@code FluentIterable} instance, 037 * providing a view of the original iterable (e.g. filter(Predicate)); 038 * <li>conversion methods which copy the FluentIterable's contents into a 039 * new collection or array (e.g. toList()); 040 * <li>utility methods which answer questions about the FluentIterable's 041 * contents (e.g. size(), anyMatch(Predicate)). 042 * <li> 043 * </ul> 044 * <p> 045 * The following example outputs the first 3 even numbers in the range [1, 10] 046 * into a list: 047 * </p> 048 * <pre> 049 * List<String> result = 050 * FluentIterable 051 * .of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) 052 * .filter(new Predicate<Integer>() { 053 * public boolean evaluate(Integer number) { 054 * return number % 2 == 0; 055 * } 056 * ) 057 * .transform(TransformerUtils.stringValueTransformer()) 058 * .limit(3) 059 * .toList(); 060 * </pre> 061 * The resulting list will contain the following elements: 062 * <pre>[2, 4, 6]</pre> 063 * 064 * @param <E> the element type 065 * @since 4.1 066 */ 067public class FluentIterable<E> implements Iterable<E> { 068 069 /** A reference to the wrapped iterable. */ 070 private final Iterable<E> iterable; 071 072 // Static factory methods 073 // ---------------------------------------------------------------------- 074 075 /** 076 * Creates a new empty FluentIterable. 077 * 078 * @param <T> the element type 079 * @return a new empty FluentIterable 080 */ 081 public static <T> FluentIterable<T> empty() { 082 return IterableUtils.EMPTY_ITERABLE; 083 } 084 085 /** 086 * Creates a new FluentIterable of the single provided element. 087 * <p> 088 * The returned iterable's iterator does not support {@code remove()}. 089 * 090 * @param <T> the element type 091 * @param singleton the singleton element 092 * @return a new FluentIterable containing the singleton 093 */ 094 public static <T> FluentIterable<T> of(final T singleton) { 095 return of(IteratorUtils.asIterable(new SingletonIterator<>(singleton, false))); 096 } 097 098 /** 099 * Creates a new FluentIterable from the provided elements. 100 * <p> 101 * The returned iterable's iterator does not support {@code remove()}. 102 * 103 * @param <T> the element type 104 * @param elements the elements to be contained in the FluentIterable 105 * @return a new FluentIterable containing the provided elements 106 */ 107 public static <T> FluentIterable<T> of(final T... elements) { 108 return of(Arrays.asList(elements)); 109 } 110 111 /** 112 * Construct a new FluentIterable from the provided iterable. If the 113 * iterable is already an instance of FluentIterable, the instance 114 * will be returned instead. 115 * <p> 116 * The returned iterable's iterator supports {@code remove()} when the 117 * corresponding input iterator supports it. 118 * 119 * @param <T> the element type 120 * @param iterable the iterable to wrap into a FluentIterable, may not be null 121 * @return a new FluentIterable wrapping the provided iterable 122 * @throws NullPointerException if iterable is null 123 */ 124 public static <T> FluentIterable<T> of(final Iterable<T> iterable) { 125 IterableUtils.checkNotNull(iterable); 126 if (iterable instanceof FluentIterable<?>) { 127 return (FluentIterable<T>) iterable; 128 } 129 return new FluentIterable<>(iterable); 130 } 131 132 // Constructor 133 // ---------------------------------------------------------------------- 134 135 /** 136 * Package-private constructor, used by IterableUtils. 137 */ 138 FluentIterable() { 139 this.iterable = this; 140 } 141 142 /** 143 * Create a new FluentIterable by wrapping the provided iterable. 144 * @param iterable the iterable to wrap 145 */ 146 private FluentIterable(final Iterable<E> iterable) { 147 this.iterable = iterable; 148 } 149 150 // fluent construction methods 151 // ---------------------------------------------------------------------- 152 153 /** 154 * Returns a new FluentIterable whose iterator will first traverse 155 * the elements of the current iterable, followed by the provided 156 * elements. 157 * 158 * @param elements the elements to append to the iterable 159 * @return a new iterable, combining this iterable with the elements 160 */ 161 public FluentIterable<E> append(final E... elements) { 162 return append(Arrays.asList(elements)); 163 } 164 165 /** 166 * Returns a new FluentIterable whose iterator will first traverse 167 * the elements of the current iterable, followed by the elements 168 * of the provided iterable. 169 * 170 * @param other the other iterable to combine, may not be null 171 * @return a new iterable, combining this iterable with other 172 * @throws NullPointerException if other is null 173 */ 174 public FluentIterable<E> append(final Iterable<? extends E> other) { 175 return of(IterableUtils.chainedIterable(iterable, other)); 176 } 177 178 /** 179 * Returns a new FluentIterable whose iterator will traverse the 180 * elements of the current and provided iterable in natural order. 181 * <p> 182 * Example: natural ordering 183 * <ul> 184 * <li>this contains elements [1, 3, 5, 7] 185 * <li>other contains elements [2, 4, 6, 8] 186 * </ul> 187 * <p> 188 * The returned iterable will traverse the elements in the following 189 * order: [1, 2, 3, 4, 5, 6, 7, 8] 190 * 191 * @param other the other iterable to collate, may not be null 192 * @return a new iterable, collating this iterable with the other in natural order 193 * @throws NullPointerException if other is null 194 * @see org.apache.commons.collections4.iterators.CollatingIterator 195 */ 196 public FluentIterable<E> collate(final Iterable<? extends E> other) { 197 return of(IterableUtils.collatedIterable(iterable, other)); 198 } 199 200 /** 201 * Returns a new FluentIterable whose iterator will traverse the 202 * elements of the current and provided iterable according to the 203 * ordering defined by an comparator. 204 * <p> 205 * Example: descending order 206 * <ul> 207 * <li>this contains elements [7, 5, 3, 1] 208 * <li>other contains elements [8, 6, 4, 2] 209 * </ul> 210 * <p> 211 * The returned iterable will traverse the elements in the following 212 * order: [8, 7, 6, 5, 4, 3, 2, 1] 213 * 214 * @param comparator the comparator to define an ordering, may be null, 215 * in which case natural ordering will be used 216 * @param other the other iterable to collate, may not be null 217 * @return a new iterable, collating this iterable with the other in natural order 218 * @throws NullPointerException if other is null 219 * @see org.apache.commons.collections4.iterators.CollatingIterator 220 */ 221 public FluentIterable<E> collate(final Iterable<? extends E> other, 222 final Comparator<? super E> comparator) { 223 return of(IterableUtils.collatedIterable(comparator, iterable, other)); 224 } 225 226 /** 227 * This method fully traverses an iterator of this iterable and returns 228 * a new iterable with the same contents, but without any reference 229 * to the originating iterables and/or iterators. 230 * <p> 231 * Calling this method is equivalent to: 232 * <pre> 233 * FluentIterable<E> someIterable = ...; 234 * FluentIterable.of(someIterable.toList()); 235 * </pre> 236 * 237 * @return a new iterable with the same contents as this iterable 238 */ 239 public FluentIterable<E> eval() { 240 return of(toList()); 241 } 242 243 /** 244 * Returns a new FluentIterable whose iterator will only return 245 * elements from this iterable matching the provided predicate. 246 * 247 * @param predicate the predicate used to filter elements 248 * @return a new iterable, providing a filtered view of this iterable 249 * @throws NullPointerException if predicate is null 250 */ 251 public FluentIterable<E> filter(final Predicate<? super E> predicate) { 252 return of(IterableUtils.filteredIterable(iterable, predicate)); 253 } 254 255 /** 256 * Returns a new FluentIterable whose iterator will return at most 257 * the provided maximum number of elements from this iterable. 258 * 259 * @param maxSize the maximum number of elements 260 * @return a new iterable, providing a bounded view of this iterable 261 * @throws IllegalArgumentException if maxSize is negative 262 */ 263 public FluentIterable<E> limit(final long maxSize) { 264 return of(IterableUtils.boundedIterable(iterable, maxSize)); 265 } 266 267 /** 268 * Returns a new FluentIterable whose iterator will loop infinitely 269 * over the elements from this iterable. 270 * 271 * @return a new iterable, providing a looping view of this iterable 272 */ 273 public FluentIterable<E> loop() { 274 return of(IterableUtils.loopingIterable(iterable)); 275 } 276 277 /** 278 * Returns a new FluentIterable whose iterator will traverse the 279 * elements from this iterable in reverse order. 280 * 281 * @return a new iterable, providing a reversed view of this iterable 282 */ 283 public FluentIterable<E> reverse() { 284 return of(IterableUtils.reversedIterable(iterable)); 285 } 286 287 /** 288 * Returns a new FluentIterable whose iterator will skip the first 289 * N elements from this iterable. 290 * 291 * @param elementsToSkip the number of elements to skip 292 * @return a new iterable, providing a view of this iterable by skipping 293 * the first N elements 294 * @throws IllegalArgumentException if elementsToSkip is negative 295 */ 296 public FluentIterable<E> skip(final long elementsToSkip) { 297 return of(IterableUtils.skippingIterable(iterable, elementsToSkip)); 298 } 299 300 /** 301 * Returns a new FluentIterable whose iterator will return all elements 302 * of this iterable transformed by the provided transformer. 303 * 304 * @param <O> the output element type 305 * @param transformer the transformer applied to each element 306 * @return a new iterable, providing a transformed view of this iterable 307 * @throws NullPointerException if transformer is null 308 */ 309 public <O> FluentIterable<O> transform(final Transformer<? super E, ? extends O> transformer) { 310 return of(IterableUtils.transformedIterable(iterable, transformer)); 311 } 312 313 /** 314 * Returns a new FluentIterable whose iterator will return a unique view 315 * of this iterable. 316 * 317 * @return a new iterable, providing a unique view of this iterable 318 */ 319 public FluentIterable<E> unique() { 320 return of(IterableUtils.uniqueIterable(iterable)); 321 } 322 323 /** 324 * Returns a new FluentIterable whose iterator will return an unmodifiable 325 * view of this iterable. 326 * 327 * @return a new iterable, providing an unmodifiable view of this iterable 328 */ 329 public FluentIterable<E> unmodifiable() { 330 return of(IterableUtils.unmodifiableIterable(iterable)); 331 } 332 333 /** 334 * Returns a new FluentIterable whose iterator will traverse 335 * the elements of this iterable and the other iterable in 336 * alternating order. 337 * 338 * @param other the other iterable to interleave, may not be null 339 * @return a new iterable, interleaving this iterable with others 340 * @throws NullPointerException if other is null 341 */ 342 public FluentIterable<E> zip(final Iterable<? extends E> other) { 343 return of(IterableUtils.zippingIterable(iterable, other)); 344 } 345 346 /** 347 * Returns a new FluentIterable whose iterator will traverse 348 * the elements of this iterable and the other iterables in 349 * alternating order. 350 * 351 * @param others the iterables to interleave, may not be null 352 * @return a new iterable, interleaving this iterable with others 353 * @throws NullPointerException if either of the provided iterables is null 354 */ 355 public FluentIterable<E> zip(final Iterable<? extends E>... others) { 356 return of(IterableUtils.zippingIterable(iterable, others)); 357 } 358 359 // convenience methods 360 // ---------------------------------------------------------------------- 361 362 /** {@inheritDoc} */ 363 @Override 364 public Iterator<E> iterator() { 365 return iterable.iterator(); 366 } 367 368 /** 369 * Returns an Enumeration that will enumerate all elements contained 370 * in this iterable. 371 * 372 * @return an Enumeration over the elements of this iterable 373 */ 374 public Enumeration<E> asEnumeration() { 375 return IteratorUtils.asEnumeration(iterator()); 376 } 377 378 /** 379 * Checks if all elements contained in this iterable are matching the 380 * provided predicate. 381 * <p> 382 * A <code>null</code> or empty iterable returns true. 383 * 384 * @param predicate the predicate to use, may not be null 385 * @return true if all elements contained in this iterable match the predicate, 386 * false otherwise 387 * @throws NullPointerException if predicate is null 388 */ 389 public boolean allMatch(final Predicate<? super E> predicate) { 390 return IterableUtils.matchesAll(iterable, predicate); 391 } 392 393 /** 394 * Checks if this iterable contains any element matching the provided predicate. 395 * <p> 396 * A <code>null</code> or empty iterable returns false. 397 * 398 * @param predicate the predicate to use, may not be null 399 * @return true if at least one element contained in this iterable matches the predicate, 400 * false otherwise 401 * @throws NullPointerException if predicate is null 402 */ 403 public boolean anyMatch(final Predicate<? super E> predicate) { 404 return IterableUtils.matchesAny(iterable, predicate); 405 } 406 407 /** 408 * Checks if this iterable is empty. 409 * 410 * @return true if this iterable does not contain any elements, false otherwise 411 */ 412 public boolean isEmpty() { 413 return IterableUtils.isEmpty(iterable); 414 } 415 416 /** 417 * Checks if the object is contained in this iterable. 418 * 419 * @param object the object to check 420 * @return true if the object is contained in this iterable, false otherwise 421 */ 422 public boolean contains(final Object object) { 423 return IterableUtils.contains(iterable, object); 424 } 425 426 /** 427 * Applies the closure to all elements contained in this iterable. 428 * 429 * @param closure the closure to apply to each element, may not be null 430 * @throws NullPointerException if closure is null 431 */ 432 public void forEach(final Closure<? super E> closure) { 433 IterableUtils.forEach(iterable, closure); 434 } 435 436 /** 437 * Returns the element at the provided position in this iterable. 438 * In order to return the element, an iterator needs to be traversed 439 * up to the requested position. 440 * 441 * @param position the position of the element to return 442 * @return the element 443 * @throws IndexOutOfBoundsException if the provided position is outside the 444 * valid range of this iterable: [0, size) 445 */ 446 public E get(final int position) { 447 return IterableUtils.get(iterable, position); 448 } 449 450 /** 451 * Returns the number of elements that are contained in this iterable. 452 * In order to determine the size, an iterator needs to be traversed. 453 * 454 * @return the size of this iterable 455 */ 456 public int size() { 457 return IterableUtils.size(iterable); 458 } 459 460 /** 461 * Traverses an iterator of this iterable and adds all elements 462 * to the provided collection. 463 * 464 * @param collection the collection to add the elements 465 * @throws NullPointerException if collection is null 466 */ 467 public void copyInto(final Collection<? super E> collection) { 468 if (collection == null) { 469 throw new NullPointerException("Collection must not be null"); 470 } 471 CollectionUtils.addAll(collection, iterable); 472 } 473 474 /** 475 * Returns an array containing all elements of this iterable by traversing 476 * its iterator. 477 * 478 * @param arrayClass the class of array to create 479 * @return an array of the iterable contents 480 * @throws ArrayStoreException if arrayClass is invalid 481 */ 482 public E[] toArray(final Class<E> arrayClass) { 483 return IteratorUtils.toArray(iterator(), arrayClass); 484 } 485 486 /** 487 * Returns a mutable list containing all elements of this iterable 488 * by traversing its iterator. 489 * <p> 490 * The returned list is guaranteed to be mutable. 491 * 492 * @return a list of the iterable contents 493 */ 494 public List<E> toList() { 495 return IterableUtils.toList(iterable); 496 } 497 498 /** {@inheritDoc} */ 499 @Override 500 public String toString() { 501 return IterableUtils.toString(iterable); 502 } 503 504}