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 */ 017 018package org.apache.commons.io.function; 019 020import java.io.IOException; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Objects; 026import java.util.Optional; 027import java.util.Spliterator; 028import java.util.Spliterators; 029import java.util.concurrent.atomic.AtomicInteger; 030import java.util.concurrent.atomic.AtomicReference; 031import java.util.function.BiFunction; 032import java.util.function.IntFunction; 033import java.util.function.ToDoubleFunction; 034import java.util.function.ToIntFunction; 035import java.util.function.ToLongFunction; 036import java.util.function.UnaryOperator; 037import java.util.stream.Collector; 038import java.util.stream.DoubleStream; 039import java.util.stream.IntStream; 040import java.util.stream.LongStream; 041import java.util.stream.Stream; 042import java.util.stream.StreamSupport; 043 044import org.apache.commons.io.IOExceptionList; 045 046/** 047 * Like {@link Stream} but throws {@link IOException}. 048 * 049 * @param <T> the type of the stream elements. 050 * @since 2.12.0 051 */ 052public interface IOStream<T> extends IOBaseStream<T, IOStream<T>, Stream<T>> { 053 054 /** 055 * Constructs a new IOStream for the given Stream. 056 * 057 * @param <T> the type of the stream elements. 058 * @param stream The stream to delegate. 059 * @return a new IOStream. 060 */ 061 static <T> IOStream<T> adapt(final Stream<T> stream) { 062 return IOStreamAdapter.adapt(stream); 063 } 064 065 /** 066 * This class' version of {@link Stream#empty()}. 067 * 068 * @param <T> the type of the stream elements 069 * @return an empty sequential {@code IOStreamImpl}. 070 * @see Stream#empty() 071 */ 072 static <T> IOStream<T> empty() { 073 return IOStreamAdapter.adapt(Stream.empty()); 074 } 075 076 /** 077 * Like {@link Stream#iterate(Object, UnaryOperator)} but for IO. 078 * 079 * @param <T> the type of stream elements. 080 * @param seed the initial element. 081 * @param f a function to be applied to the previous element to produce a new element. 082 * @return a new sequential {@code IOStream}. 083 */ 084 static <T> IOStream<T> iterate(final T seed, final IOUnaryOperator<T> f) { 085 Objects.requireNonNull(f); 086 final Iterator<T> iterator = new Iterator<T>() { 087 @SuppressWarnings("unchecked") 088 T t = (T) IOStreams.NONE; 089 090 @Override 091 public boolean hasNext() { 092 return true; 093 } 094 095 @Override 096 public T next() { 097 return t = t == IOStreams.NONE ? seed : Erase.apply(f, t); 098 } 099 }; 100 return adapt(StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED | Spliterator.IMMUTABLE), false)); 101 } 102 103 /** 104 * Null-safe version of {@link StreamSupport#stream(java.util.Spliterator, boolean)}. 105 * 106 * Copied from Apache Commons Lang. 107 * 108 * @param <T> the type of stream elements. 109 * @param values the elements of the new stream, may be {@code null}. 110 * @return the new stream on {@code values} or {@link Stream#empty()}. 111 */ 112 @SuppressWarnings("resource") // call to #empty() 113 static <T> IOStream<T> of(final Iterable<T> values) { 114 return values == null ? empty() : adapt(StreamSupport.stream(values.spliterator(), false)); 115 } 116 117 /** 118 * Null-safe version of {@link Stream#of(Object[])} for an IO stream. 119 * 120 * @param <T> the type of stream elements. 121 * @param values the elements of the new stream, may be {@code null}. 122 * @return the new stream on {@code values} or {@link Stream#empty()}. 123 */ 124 @SuppressWarnings("resource") 125 @SafeVarargs // Creating a stream from an array is safe 126 static <T> IOStream<T> of(final T... values) { 127 return values == null || values.length == 0 ? empty() : adapt(Arrays.stream(values)); 128 } 129 130 /** 131 * Returns a sequential {@code IOStreamImpl} containing a single element. 132 * 133 * @param t the single element 134 * @param <T> the type of stream elements 135 * @return a singleton sequential stream 136 */ 137 static <T> IOStream<T> of(final T t) { 138 return adapt(Stream.of(t)); 139 } 140 141 /** 142 * Like {@link Stream#allMatch(java.util.function.Predicate)} but throws {@link IOException}. 143 * 144 * @param predicate {@link Stream#allMatch(java.util.function.Predicate)}. 145 * @return Like {@link Stream#allMatch(java.util.function.Predicate)}. 146 * @throws IOException if an I/O error occurs. 147 */ 148 @SuppressWarnings("unused") // thrown by Erase. 149 default boolean allMatch(final IOPredicate<? super T> predicate) throws IOException { 150 return unwrap().allMatch(t -> Erase.test(predicate, t)); 151 } 152 153 /** 154 * Like {@link Stream#anyMatch(java.util.function.Predicate)} but throws {@link IOException}. 155 * 156 * @param predicate {@link Stream#anyMatch(java.util.function.Predicate)}. 157 * @return Like {@link Stream#anyMatch(java.util.function.Predicate)}. 158 * @throws IOException if an I/O error occurs. 159 */ 160 @SuppressWarnings("unused") // thrown by Erase. 161 default boolean anyMatch(final IOPredicate<? super T> predicate) throws IOException { 162 return unwrap().anyMatch(t -> Erase.test(predicate, t)); 163 } 164 165 /** 166 * TODO Package-private for now, needs IOCollector? 167 * 168 * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It 169 * would be ideal to have only one. 170 * 171 * Like {@link Stream#collect(Collector)}. 172 * 173 * Package private for now. 174 * 175 * @param <R> Like {@link Stream#collect(Collector)}. 176 * @param <A> Like {@link Stream#collect(Collector)}. 177 * @param collector Like {@link Stream#collect(Collector)}. 178 * @return Like {@link Stream#collect(Collector)}. 179 */ 180 default <R, A> R collect(final Collector<? super T, A, R> collector) { 181 return unwrap().collect(collector); 182 } 183 184 /** 185 * Like 186 * {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)}. 187 * 188 * @param <R> Like 189 * {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)}. 190 * @param supplier Like 191 * {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)}. 192 * @param accumulator Like 193 * {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)}. 194 * @param combiner Like 195 * {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)}. 196 * @return Like 197 * {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)}. 198 * @throws IOException if an I/O error occurs. 199 */ 200 @SuppressWarnings("unused") // thrown by Erase. 201 default <R> R collect(final IOSupplier<R> supplier, final IOBiConsumer<R, ? super T> accumulator, final IOBiConsumer<R, R> combiner) throws IOException { 202 return unwrap().collect(() -> Erase.get(supplier), (t, u) -> Erase.accept(accumulator, t, u), (t, u) -> Erase.accept(combiner, t, u)); 203 } 204 205 /** 206 * Like {@link Stream#count()}. 207 * 208 * @return Like {@link Stream#count()}. 209 */ 210 default long count() { 211 return unwrap().count(); 212 } 213 214 /** 215 * Like {@link Stream#distinct()}. 216 * 217 * @return Like {@link Stream#distinct()}. 218 */ 219 default IOStream<T> distinct() { 220 return adapt(unwrap().distinct()); 221 } 222 223 /** 224 * Like {@link Stream#filter(java.util.function.Predicate)}. 225 * 226 * @param predicate Like {@link Stream#filter(java.util.function.Predicate)}. 227 * @return Like {@link Stream#filter(java.util.function.Predicate)}. 228 * @throws IOException if an I/O error occurs. 229 */ 230 @SuppressWarnings("unused") // thrown by Erase. 231 default IOStream<T> filter(final IOPredicate<? super T> predicate) throws IOException { 232 return adapt(unwrap().filter(t -> Erase.test(predicate, t))); 233 } 234 235 /** 236 * Like {@link Stream#findAny()}. 237 * 238 * @return Like {@link Stream#findAny()}. 239 */ 240 default Optional<T> findAny() { 241 return unwrap().findAny(); 242 } 243 244 /** 245 * Like {@link Stream#findFirst()}. 246 * 247 * @return Like {@link Stream#findFirst()}. 248 */ 249 default Optional<T> findFirst() { 250 return unwrap().findFirst(); 251 } 252 253 /** 254 * Like {@link Stream#flatMap(java.util.function.Function)}. 255 * 256 * @param <R> Like {@link Stream#flatMap(java.util.function.Function)}. 257 * @param mapper Like {@link Stream#flatMap(java.util.function.Function)}. 258 * @return Like {@link Stream#flatMap(java.util.function.Function)}. 259 * @throws IOException if an I/O error occurs. 260 */ 261 @SuppressWarnings("unused") // thrown by Erase. 262 default <R> IOStream<R> flatMap(final IOFunction<? super T, ? extends IOStream<? extends R>> mapper) throws IOException { 263 return adapt(unwrap().flatMap(t -> Erase.apply(mapper, t).unwrap())); 264 } 265 266 /** 267 * TODO Package-private for now, needs IODoubleStream? 268 * 269 * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It 270 * would be ideal to have only one. 271 * 272 * Like {@link Stream#flatMapToDouble(java.util.function.Function)}. 273 * 274 * @param mapper Like {@link Stream#flatMapToDouble(java.util.function.Function)}. 275 * @return Like {@link Stream#flatMapToDouble(java.util.function.Function)}. 276 * @throws IOException if an I/O error occurs. 277 */ 278 @SuppressWarnings("unused") // thrown by Erase. 279 default DoubleStream flatMapToDouble(final IOFunction<? super T, ? extends DoubleStream> mapper) throws IOException { 280 return unwrap().flatMapToDouble(t -> Erase.apply(mapper, t)); 281 } 282 283 /** 284 * TODO Package-private for now, needs IOIntStream? 285 * 286 * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It 287 * would be ideal to have only one. 288 * 289 * Like {@link Stream#flatMapToInt(java.util.function.Function)}. 290 * 291 * @param mapper Like {@link Stream#flatMapToInt(java.util.function.Function)}. 292 * @return Like {@link Stream#flatMapToInt(java.util.function.Function)}. 293 * @throws IOException if an I/O error occurs. 294 */ 295 @SuppressWarnings("unused") // thrown by Erase. 296 default IntStream flatMapToInt(final IOFunction<? super T, ? extends IntStream> mapper) throws IOException { 297 return unwrap().flatMapToInt(t -> Erase.apply(mapper, t)); 298 } 299 300 /** 301 * TODO Package-private for now, needs IOLongStream? 302 * 303 * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It 304 * would be ideal to have only one. 305 * 306 * Like {@link Stream#flatMapToLong(java.util.function.Function)}. 307 * 308 * @param mapper Like {@link Stream#flatMapToLong(java.util.function.Function)}. 309 * @return Like {@link Stream#flatMapToLong(java.util.function.Function)}. 310 * @throws IOException if an I/O error occurs. 311 */ 312 @SuppressWarnings("unused") // thrown by Erase. 313 default LongStream flatMapToLong(final IOFunction<? super T, ? extends LongStream> mapper) throws IOException { 314 return unwrap().flatMapToLong(t -> Erase.apply(mapper, t)); 315 } 316 317 /** 318 * Performs an action for each element gathering any exceptions. 319 * 320 * @param action The action to apply to each element. 321 * @throws IOExceptionList if any I/O errors occur. 322 */ 323 default void forAll(final IOConsumer<T> action) throws IOExceptionList { 324 forAll(action, (i, e) -> e); 325 } 326 327 /** 328 * Performs an action for each element gathering any exceptions. 329 * 330 * @param action The action to apply to each element. 331 * @param exSupplier The exception supplier. 332 * @throws IOExceptionList if any I/O errors occur. 333 */ 334 default void forAll(final IOConsumer<T> action, final BiFunction<Integer, IOException, IOException> exSupplier) throws IOExceptionList { 335 final AtomicReference<List<IOException>> causeList = new AtomicReference<>(); 336 final AtomicInteger index = new AtomicInteger(); 337 final IOConsumer<T> safeAction = IOStreams.toIOConsumer(action); 338 unwrap().forEach(e -> { 339 try { 340 safeAction.accept(e); 341 } catch (final IOException innerEx) { 342 if (causeList.get() == null) { 343 // Only allocate if required 344 causeList.set(new ArrayList<>()); 345 } 346 if (exSupplier != null) { 347 causeList.get().add(exSupplier.apply(index.get(), innerEx)); 348 } 349 } 350 index.incrementAndGet(); 351 }); 352 IOExceptionList.checkEmpty(causeList.get(), null); 353 } 354 355 /** 356 * Like {@link Stream#forEach(java.util.function.Consumer)} but throws {@link IOException}. 357 * 358 * @param action Like {@link Stream#forEach(java.util.function.Consumer)}. 359 * @throws IOException if an I/O error occurs. 360 */ 361 @SuppressWarnings("unused") // thrown by Erase. 362 default void forEach(final IOConsumer<? super T> action) throws IOException { 363 unwrap().forEach(e -> Erase.accept(action, e)); 364 } 365 366 /** 367 * Like {@link Stream#forEachOrdered(java.util.function.Consumer)}. 368 * 369 * @param action Like {@link Stream#forEachOrdered(java.util.function.Consumer)}. 370 * @throws IOException if an I/O error occurs. 371 */ 372 @SuppressWarnings("unused") // thrown by Erase. 373 default void forEachOrdered(final IOConsumer<? super T> action) throws IOException { 374 unwrap().forEachOrdered(e -> Erase.accept(action, e)); 375 } 376 377 /** 378 * Like {@link Stream#limit(long)}. 379 * 380 * @param maxSize Like {@link Stream#limit(long)}. 381 * @return Like {@link Stream#limit(long)}. 382 */ 383 default IOStream<T> limit(final long maxSize) { 384 return adapt(unwrap().limit(maxSize)); 385 } 386 387 /** 388 * Like {@link Stream#map(java.util.function.Function)}. 389 * 390 * @param <R> Like {@link Stream#map(java.util.function.Function)}. 391 * @param mapper Like {@link Stream#map(java.util.function.Function)}. 392 * @return Like {@link Stream#map(java.util.function.Function)}. 393 * @throws IOException if an I/O error occurs. 394 */ 395 @SuppressWarnings("unused") // thrown by Erase. 396 default <R> IOStream<R> map(final IOFunction<? super T, ? extends R> mapper) throws IOException { 397 return adapt(unwrap().map(t -> Erase.apply(mapper, t))); 398 } 399 400 /** 401 * TODO Package-private for now, needs IOToDoubleFunction? 402 * 403 * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It 404 * would be ideal to have only one. 405 * 406 * Like {@link Stream#mapToDouble(ToDoubleFunction)}. 407 * 408 * Package private for now. 409 * 410 * @param mapper Like {@link Stream#mapToDouble(ToDoubleFunction)}. 411 * @return Like {@link Stream#mapToDouble(ToDoubleFunction)}. 412 */ 413 default DoubleStream mapToDouble(final ToDoubleFunction<? super T> mapper) { 414 return unwrap().mapToDouble(mapper); 415 } 416 417 /** 418 * TODO Package-private for now, needs IOToIntFunction? 419 * 420 * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It 421 * would be ideal to have only one. 422 * 423 * Like {@link Stream#mapToInt(ToIntFunction)}. 424 * 425 * Package private for now. 426 * 427 * @param mapper Like {@link Stream#mapToInt(ToIntFunction)}. 428 * @return Like {@link Stream#mapToInt(ToIntFunction)}. 429 */ 430 default IntStream mapToInt(final ToIntFunction<? super T> mapper) { 431 return unwrap().mapToInt(mapper); 432 } 433 434 /** 435 * TODO Package-private for now, needs IOToLongFunction? 436 * 437 * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It 438 * would be ideal to have only one. 439 * 440 * Like {@link Stream#mapToLong(ToLongFunction)}. 441 * 442 * Package private for now. 443 * 444 * @param mapper Like {@link Stream#mapToLong(ToLongFunction)}. 445 * @return Like {@link Stream#mapToLong(ToLongFunction)}. 446 */ 447 default LongStream mapToLong(final ToLongFunction<? super T> mapper) { 448 return unwrap().mapToLong(mapper); 449 } 450 451 /** 452 * Like {@link Stream#max(java.util.Comparator)}. 453 * 454 * @param comparator Like {@link Stream#max(java.util.Comparator)}. 455 * @return Like {@link Stream#max(java.util.Comparator)}. 456 * @throws IOException if an I/O error occurs. 457 */ 458 @SuppressWarnings("unused") // thrown by Erase. 459 default Optional<T> max(final IOComparator<? super T> comparator) throws IOException { 460 return unwrap().max((t, u) -> Erase.compare(comparator, t, u)); 461 } 462 463 /** 464 * Like {@link Stream#min(java.util.Comparator)}. 465 * 466 * @param comparator Like {@link Stream#min(java.util.Comparator)}. 467 * @return Like {@link Stream#min(java.util.Comparator)}. 468 * @throws IOException if an I/O error occurs. 469 */ 470 @SuppressWarnings("unused") // thrown by Erase. 471 default Optional<T> min(final IOComparator<? super T> comparator) throws IOException { 472 return unwrap().min((t, u) -> Erase.compare(comparator, t, u)); 473 } 474 475 /** 476 * Like {@link Stream#noneMatch(java.util.function.Predicate)}. 477 * 478 * @param predicate Like {@link Stream#noneMatch(java.util.function.Predicate)}. 479 * @return Like {@link Stream#noneMatch(java.util.function.Predicate)}. 480 * @throws IOException if an I/O error occurs. 481 */ 482 @SuppressWarnings("unused") // thrown by Erase. 483 default boolean noneMatch(final IOPredicate<? super T> predicate) throws IOException { 484 return unwrap().noneMatch(t -> Erase.test(predicate, t)); 485 } 486 487 /** 488 * Like {@link Stream#peek(java.util.function.Consumer)}. 489 * 490 * @param action Like {@link Stream#peek(java.util.function.Consumer)}. 491 * @return Like {@link Stream#peek(java.util.function.Consumer)}. 492 * @throws IOException if an I/O error occurs. 493 */ 494 @SuppressWarnings("unused") // thrown by Erase. 495 default IOStream<T> peek(final IOConsumer<? super T> action) throws IOException { 496 return adapt(unwrap().peek(t -> Erase.accept(action, t))); 497 } 498 499 /** 500 * Like {@link Stream#reduce(java.util.function.BinaryOperator)}. 501 * 502 * @param accumulator Like {@link Stream#reduce(java.util.function.BinaryOperator)}. 503 * @return Like {@link Stream#reduce(java.util.function.BinaryOperator)}. 504 * @throws IOException if an I/O error occurs. 505 */ 506 @SuppressWarnings("unused") // thrown by Erase. 507 default Optional<T> reduce(final IOBinaryOperator<T> accumulator) throws IOException { 508 return unwrap().reduce((t, u) -> Erase.apply(accumulator, t, u)); 509 } 510 511 /** 512 * Like {@link Stream#reduce(Object, java.util.function.BinaryOperator)}. 513 * 514 * @param identity Like {@link Stream#reduce(Object, java.util.function.BinaryOperator)}. 515 * @param accumulator Like {@link Stream#reduce(Object, java.util.function.BinaryOperator)}. 516 * @return Like {@link Stream#reduce(Object, java.util.function.BinaryOperator)}. 517 * @throws IOException if an I/O error occurs. 518 */ 519 @SuppressWarnings("unused") // thrown by Erase. 520 default T reduce(final T identity, final IOBinaryOperator<T> accumulator) throws IOException { 521 return unwrap().reduce(identity, (t, u) -> Erase.apply(accumulator, t, u)); 522 } 523 524 /** 525 * Like {@link Stream#reduce(Object, BiFunction, java.util.function.BinaryOperator)}. 526 * 527 * @param <U> Like {@link Stream#reduce(Object, BiFunction, java.util.function.BinaryOperator)}. 528 * @param identity Like {@link Stream#reduce(Object, BiFunction, java.util.function.BinaryOperator)}. 529 * @param accumulator Like {@link Stream#reduce(Object, BiFunction, java.util.function.BinaryOperator)}. 530 * @param combiner Like {@link Stream#reduce(Object, BiFunction, java.util.function.BinaryOperator)}. 531 * @return Like {@link Stream#reduce(Object, BiFunction, java.util.function.BinaryOperator)}. 532 * @throws IOException if an I/O error occurs. 533 */ 534 @SuppressWarnings("unused") // thrown by Erase. 535 default <U> U reduce(final U identity, final IOBiFunction<U, ? super T, U> accumulator, final IOBinaryOperator<U> combiner) throws IOException { 536 return unwrap().reduce(identity, (t, u) -> Erase.apply(accumulator, t, u), (t, u) -> Erase.apply(combiner, t, u)); 537 } 538 539 /** 540 * Like {@link Stream#skip(long)}. 541 * 542 * @param n Like {@link Stream#skip(long)}. 543 * @return Like {@link Stream#skip(long)}. 544 */ 545 default IOStream<T> skip(final long n) { 546 return adapt(unwrap().skip(n)); 547 } 548 549 /** 550 * Like {@link Stream#sorted()}. 551 * 552 * @return Like {@link Stream#sorted()}. 553 */ 554 default IOStream<T> sorted() { 555 return adapt(unwrap().sorted()); 556 } 557 558 /** 559 * Like {@link Stream#sorted(java.util.Comparator)}. 560 * 561 * @param comparator Like {@link Stream#sorted(java.util.Comparator)}. 562 * @return Like {@link Stream#sorted(java.util.Comparator)}. 563 * @throws IOException if an I/O error occurs. 564 */ 565 @SuppressWarnings("unused") // thrown by Erase. 566 default IOStream<T> sorted(final IOComparator<? super T> comparator) throws IOException { 567 return adapt(unwrap().sorted((t, u) -> Erase.compare(comparator, t, u))); 568 } 569 570 /** 571 * Like {@link Stream#toArray()}. 572 * 573 * @return {@link Stream#toArray()}. 574 */ 575 default Object[] toArray() { 576 return unwrap().toArray(); 577 } 578 579 /** 580 * TODO Package-private for now, needs IOIntFunction? 581 * 582 * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It 583 * would be ideal to have only one. 584 * 585 * Like {@link Stream#toArray(IntFunction)}. 586 * 587 * Package private for now. 588 * 589 * @param <A> Like {@link Stream#toArray(IntFunction)}. 590 * @param generator Like {@link Stream#toArray(IntFunction)}. 591 * @return Like {@link Stream#toArray(IntFunction)}. 592 */ 593 default <A> A[] toArray(final IntFunction<A[]> generator) { 594 return unwrap().toArray(generator); 595 } 596 597}