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