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