IOStream.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */

  17. package org.apache.commons.io.function;

  18. import java.io.IOException;
  19. import java.util.ArrayList;
  20. import java.util.Arrays;
  21. import java.util.Iterator;
  22. import java.util.List;
  23. import java.util.NoSuchElementException;
  24. import java.util.Objects;
  25. import java.util.Optional;
  26. import java.util.Spliterator;
  27. import java.util.Spliterators;
  28. import java.util.concurrent.atomic.AtomicInteger;
  29. import java.util.concurrent.atomic.AtomicReference;
  30. import java.util.function.BiFunction;
  31. import java.util.function.IntFunction;
  32. import java.util.function.ToDoubleFunction;
  33. import java.util.function.ToIntFunction;
  34. import java.util.function.ToLongFunction;
  35. import java.util.function.UnaryOperator;
  36. import java.util.stream.Collector;
  37. import java.util.stream.DoubleStream;
  38. import java.util.stream.IntStream;
  39. import java.util.stream.LongStream;
  40. import java.util.stream.Stream;
  41. import java.util.stream.StreamSupport;

  42. import org.apache.commons.io.IOExceptionList;

  43. /**
  44.  * Like {@link Stream} but throws {@link IOException}.
  45.  *
  46.  * @param <T> the type of the stream elements.
  47.  * @since 2.12.0
  48.  */
  49. public interface IOStream<T> extends IOBaseStream<T, IOStream<T>, Stream<T>> {

  50.     /**
  51.      * Constructs a new IOStream for the given Stream.
  52.      *
  53.      * @param <T> the type of the stream elements.
  54.      * @param stream The stream to delegate.
  55.      * @return a new IOStream.
  56.      */
  57.     static <T> IOStream<T> adapt(final Stream<T> stream) {
  58.         return IOStreamAdapter.adapt(stream);
  59.     }

  60.     /**
  61.      * This class' version of {@link Stream#empty()}.
  62.      *
  63.      * @param <T> the type of the stream elements
  64.      * @return an empty sequential {@code IOStreamImpl}.
  65.      * @see Stream#empty()
  66.      */
  67.     static <T> IOStream<T> empty() {
  68.         return IOStreamAdapter.adapt(Stream.empty());
  69.     }

  70.     /**
  71.      * Like {@link Stream#iterate(Object, UnaryOperator)} but for IO.
  72.      *
  73.      * @param <T> the type of stream elements.
  74.      * @param seed the initial element.
  75.      * @param f a function to be applied to the previous element to produce a new element.
  76.      * @return a new sequential {@code IOStream}.
  77.      */
  78.     static <T> IOStream<T> iterate(final T seed, final IOUnaryOperator<T> f) {
  79.         Objects.requireNonNull(f);
  80.         final Iterator<T> iterator = new Iterator<T>() {
  81.             @SuppressWarnings("unchecked")
  82.             T t = (T) IOStreams.NONE;

  83.             @Override
  84.             public boolean hasNext() {
  85.                 return true;
  86.             }

  87.             @Override
  88.             public T next() throws NoSuchElementException {
  89.                 try {
  90.                     return t = t == IOStreams.NONE ? seed : f.apply(t);
  91.                 } catch (final IOException e) {
  92.                     final NoSuchElementException nsee = new NoSuchElementException();
  93.                     nsee.initCause(e);
  94.                     throw nsee;
  95.                 }
  96.             }
  97.         };
  98.         return adapt(StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED | Spliterator.IMMUTABLE), false));
  99.     }

  100.     /**
  101.      * Null-safe version of {@link StreamSupport#stream(java.util.Spliterator, boolean)}.
  102.      *
  103.      * Copied from Apache Commons Lang.
  104.      *
  105.      * @param <T> the type of stream elements.
  106.      * @param values the elements of the new stream, may be {@code null}.
  107.      * @return the new stream on {@code values} or {@link Stream#empty()}.
  108.      */
  109.     static <T> IOStream<T> of(final Iterable<T> values) {
  110.         return values == null ? empty() : adapt(StreamSupport.stream(values.spliterator(), false));
  111.     }

  112.     /**
  113.      * Null-safe version of {@link Stream#of(Object[])} for an IO stream.
  114.      *
  115.      * @param <T> the type of stream elements.
  116.      * @param values the elements of the new stream, may be {@code null}.
  117.      * @return the new stream on {@code values} or {@link Stream#empty()}.
  118.      */
  119.     @SafeVarargs // Creating a stream from an array is safe
  120.     static <T> IOStream<T> of(final T... values) {
  121.         return values == null || values.length == 0 ? empty() : adapt(Arrays.stream(values));
  122.     }

  123.     /**
  124.      * Returns a sequential {@code IOStreamImpl} containing a single element.
  125.      *
  126.      * @param t the single element
  127.      * @param <T> the type of stream elements
  128.      * @return a singleton sequential stream
  129.      */
  130.     static <T> IOStream<T> of(final T t) {
  131.         return adapt(Stream.of(t));
  132.     }

  133.     /**
  134.      * Like {@link Stream#allMatch(java.util.function.Predicate)} but throws {@link IOException}.
  135.      *
  136.      * @param predicate {@link Stream#allMatch(java.util.function.Predicate)}.
  137.      * @return Like {@link Stream#allMatch(java.util.function.Predicate)}.
  138.      * @throws IOException if an I/O error occurs.
  139.      */
  140.     @SuppressWarnings("unused") // thrown by Erase.
  141.     default boolean allMatch(final IOPredicate<? super T> predicate) throws IOException {
  142.         return unwrap().allMatch(t -> Erase.test(predicate, t));
  143.     }

  144.     /**
  145.      * Like {@link Stream#anyMatch(java.util.function.Predicate)} but throws {@link IOException}.
  146.      *
  147.      * @param predicate {@link Stream#anyMatch(java.util.function.Predicate)}.
  148.      * @return Like {@link Stream#anyMatch(java.util.function.Predicate)}.
  149.      * @throws IOException if an I/O error occurs.
  150.      */
  151.     @SuppressWarnings("unused") // thrown by Erase.
  152.     default boolean anyMatch(final IOPredicate<? super T> predicate) throws IOException {
  153.         return unwrap().anyMatch(t -> Erase.test(predicate, t));
  154.     }

  155.     /**
  156.      * TODO Package-private for now, needs IOCollector?
  157.      *
  158.      * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It
  159.      * would be ideal to have only one.
  160.      *
  161.      * Like {@link Stream#collect(Collector)}.
  162.      *
  163.      * Package private for now.
  164.      *
  165.      * @param <R> Like {@link Stream#collect(Collector)}.
  166.      * @param <A> Like {@link Stream#collect(Collector)}.
  167.      * @param collector Like {@link Stream#collect(Collector)}.
  168.      * @return Like {@link Stream#collect(Collector)}.
  169.      */
  170.     default <R, A> R collect(final Collector<? super T, A, R> collector) {
  171.         return unwrap().collect(collector);
  172.     }

  173.     /**
  174.      * Like
  175.      * {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)}.
  176.      *
  177.      * @param <R> Like
  178.      *        {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)}.
  179.      * @param supplier Like
  180.      *        {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)}.
  181.      * @param accumulator Like
  182.      *        {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)}.
  183.      * @param combiner Like
  184.      *        {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)}.
  185.      * @return Like
  186.      *         {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer)}.
  187.      * @throws IOException if an I/O error occurs.
  188.      */
  189.     @SuppressWarnings("unused") // thrown by Erase.
  190.     default <R> R collect(final IOSupplier<R> supplier, final IOBiConsumer<R, ? super T> accumulator, final IOBiConsumer<R, R> combiner) throws IOException {
  191.         return unwrap().collect(() -> Erase.get(supplier), (t, u) -> Erase.accept(accumulator, t, u), (t, u) -> Erase.accept(combiner, t, u));
  192.     }

  193.     /**
  194.      * Like {@link Stream#count()}.
  195.      *
  196.      * @return Like {@link Stream#count()}.
  197.      */
  198.     default long count() {
  199.         return unwrap().count();
  200.     }

  201.     /**
  202.      * Like {@link Stream#distinct()}.
  203.      *
  204.      * @return Like {@link Stream#distinct()}.
  205.      */
  206.     default IOStream<T> distinct() {
  207.         return adapt(unwrap().distinct());
  208.     }

  209.     /**
  210.      * Like {@link Stream#filter(java.util.function.Predicate)}.
  211.      *
  212.      * @param predicate Like {@link Stream#filter(java.util.function.Predicate)}.
  213.      * @return Like {@link Stream#filter(java.util.function.Predicate)}.
  214.      * @throws IOException if an I/O error occurs.
  215.      */
  216.     @SuppressWarnings("unused") // thrown by Erase.
  217.     default IOStream<T> filter(final IOPredicate<? super T> predicate) throws IOException {
  218.         return adapt(unwrap().filter(t -> Erase.test(predicate, t)));
  219.     }

  220.     /**
  221.      * Like {@link Stream#findAny()}.
  222.      *
  223.      * @return Like {@link Stream#findAny()}.
  224.      */
  225.     default Optional<T> findAny() {
  226.         return unwrap().findAny();
  227.     }

  228.     /**
  229.      * Like {@link Stream#findFirst()}.
  230.      *
  231.      * @return Like {@link Stream#findFirst()}.
  232.      */
  233.     default Optional<T> findFirst() {
  234.         return unwrap().findFirst();
  235.     }

  236.     /**
  237.      * Like {@link Stream#flatMap(java.util.function.Function)}.
  238.      *
  239.      * @param <R> Like {@link Stream#flatMap(java.util.function.Function)}.
  240.      * @param mapper Like {@link Stream#flatMap(java.util.function.Function)}.
  241.      * @return Like {@link Stream#flatMap(java.util.function.Function)}.
  242.      * @throws IOException if an I/O error occurs.
  243.      */
  244.     @SuppressWarnings({ "unused", "resource" }) // thrown by Erase; resource closed by caller.
  245.     default <R> IOStream<R> flatMap(final IOFunction<? super T, ? extends IOStream<? extends R>> mapper) throws IOException {
  246.         return adapt(unwrap().flatMap(t -> Erase.apply(mapper, t).unwrap()));
  247.     }

  248.     /**
  249.      * TODO Package-private for now, needs IODoubleStream?
  250.      *
  251.      * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It
  252.      * would be ideal to have only one.
  253.      *
  254.      * Like {@link Stream#flatMapToDouble(java.util.function.Function)}.
  255.      *
  256.      * @param mapper Like {@link Stream#flatMapToDouble(java.util.function.Function)}.
  257.      * @return Like {@link Stream#flatMapToDouble(java.util.function.Function)}.
  258.      * @throws IOException if an I/O error occurs.
  259.      */
  260.     @SuppressWarnings("unused") // thrown by Erase.
  261.     default DoubleStream flatMapToDouble(final IOFunction<? super T, ? extends DoubleStream> mapper) throws IOException {
  262.         return unwrap().flatMapToDouble(t -> Erase.apply(mapper, t));
  263.     }

  264.     /**
  265.      * TODO Package-private for now, needs IOIntStream?
  266.      *
  267.      * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It
  268.      * would be ideal to have only one.
  269.      *
  270.      * Like {@link Stream#flatMapToInt(java.util.function.Function)}.
  271.      *
  272.      * @param mapper Like {@link Stream#flatMapToInt(java.util.function.Function)}.
  273.      * @return Like {@link Stream#flatMapToInt(java.util.function.Function)}.
  274.      * @throws IOException if an I/O error occurs.
  275.      */
  276.     @SuppressWarnings("unused") // thrown by Erase.
  277.     default IntStream flatMapToInt(final IOFunction<? super T, ? extends IntStream> mapper) throws IOException {
  278.         return unwrap().flatMapToInt(t -> Erase.apply(mapper, t));
  279.     }

  280.     /**
  281.      * TODO Package-private for now, needs IOLongStream?
  282.      *
  283.      * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It
  284.      * would be ideal to have only one.
  285.      *
  286.      * Like {@link Stream#flatMapToLong(java.util.function.Function)}.
  287.      *
  288.      * @param mapper Like {@link Stream#flatMapToLong(java.util.function.Function)}.
  289.      * @return Like {@link Stream#flatMapToLong(java.util.function.Function)}.
  290.      * @throws IOException if an I/O error occurs.
  291.      */
  292.     @SuppressWarnings("unused") // thrown by Erase.
  293.     default LongStream flatMapToLong(final IOFunction<? super T, ? extends LongStream> mapper) throws IOException {
  294.         return unwrap().flatMapToLong(t -> Erase.apply(mapper, t));
  295.     }

  296.     /**
  297.      * Performs an action for each element gathering any exceptions.
  298.      *
  299.      * @param action The action to apply to each element.
  300.      * @throws IOExceptionList if any I/O errors occur.
  301.      */
  302.     default void forAll(final IOConsumer<T> action) throws IOExceptionList {
  303.         forAll(action, (i, e) -> e);
  304.     }

  305.     /**
  306.      * Performs an action for each element gathering any exceptions.
  307.      *
  308.      * @param action The action to apply to each element.
  309.      * @param exSupplier The exception supplier.
  310.      * @throws IOExceptionList if any I/O errors occur.
  311.      */
  312.     default void forAll(final IOConsumer<T> action, final BiFunction<Integer, IOException, IOException> exSupplier) throws IOExceptionList {
  313.         final AtomicReference<List<IOException>> causeList = new AtomicReference<>();
  314.         final AtomicInteger index = new AtomicInteger();
  315.         final IOConsumer<T> safeAction = IOStreams.toIOConsumer(action);
  316.         unwrap().forEach(e -> {
  317.             try {
  318.                 safeAction.accept(e);
  319.             } catch (final IOException innerEx) {
  320.                 if (causeList.get() == null) {
  321.                     // Only allocate if required
  322.                     causeList.set(new ArrayList<>());
  323.                 }
  324.                 if (exSupplier != null) {
  325.                     causeList.get().add(exSupplier.apply(index.get(), innerEx));
  326.                 }
  327.             }
  328.             index.incrementAndGet();
  329.         });
  330.         IOExceptionList.checkEmpty(causeList.get(), null);
  331.     }

  332.     /**
  333.      * Like {@link Stream#forEach(java.util.function.Consumer)} but throws {@link IOException}.
  334.      *
  335.      * @param action Like {@link Stream#forEach(java.util.function.Consumer)}.
  336.      * @throws IOException if an I/O error occurs.
  337.      */
  338.     @SuppressWarnings("unused") // thrown by Erase.
  339.     default void forEach(final IOConsumer<? super T> action) throws IOException {
  340.         unwrap().forEach(e -> Erase.accept(action, e));
  341.     }

  342.     /**
  343.      * Like {@link Stream#forEachOrdered(java.util.function.Consumer)}.
  344.      *
  345.      * @param action Like {@link Stream#forEachOrdered(java.util.function.Consumer)}.
  346.      * @throws IOException if an I/O error occurs.
  347.      */
  348.     @SuppressWarnings("unused") // thrown by Erase.
  349.     default void forEachOrdered(final IOConsumer<? super T> action) throws IOException {
  350.         unwrap().forEachOrdered(e -> Erase.accept(action, e));
  351.     }

  352.     /**
  353.      * Like {@link Stream#limit(long)}.
  354.      *
  355.      * @param maxSize Like {@link Stream#limit(long)}.
  356.      * @return Like {@link Stream#limit(long)}.
  357.      */
  358.     default IOStream<T> limit(final long maxSize) {
  359.         return adapt(unwrap().limit(maxSize));
  360.     }

  361.     /**
  362.      * Like {@link Stream#map(java.util.function.Function)}.
  363.      *
  364.      * @param <R> Like {@link Stream#map(java.util.function.Function)}.
  365.      * @param mapper Like {@link Stream#map(java.util.function.Function)}.
  366.      * @return Like {@link Stream#map(java.util.function.Function)}.
  367.      * @throws IOException if an I/O error occurs.
  368.      */
  369.     @SuppressWarnings("unused") // thrown by Erase.
  370.     default <R> IOStream<R> map(final IOFunction<? super T, ? extends R> mapper) throws IOException {
  371.         return adapt(unwrap().map(t -> Erase.apply(mapper, t)));
  372.     }

  373.     /**
  374.      * TODO Package-private for now, needs IOToDoubleFunction?
  375.      *
  376.      * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It
  377.      * would be ideal to have only one.
  378.      *
  379.      * Like {@link Stream#mapToDouble(ToDoubleFunction)}.
  380.      *
  381.      * Package private for now.
  382.      *
  383.      * @param mapper Like {@link Stream#mapToDouble(ToDoubleFunction)}.
  384.      * @return Like {@link Stream#mapToDouble(ToDoubleFunction)}.
  385.      */
  386.     default DoubleStream mapToDouble(final ToDoubleFunction<? super T> mapper) {
  387.         return unwrap().mapToDouble(mapper);
  388.     }

  389.     /**
  390.      * TODO Package-private for now, needs IOToIntFunction?
  391.      *
  392.      * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It
  393.      * would be ideal to have only one.
  394.      *
  395.      * Like {@link Stream#mapToInt(ToIntFunction)}.
  396.      *
  397.      * Package private for now.
  398.      *
  399.      * @param mapper Like {@link Stream#mapToInt(ToIntFunction)}.
  400.      * @return Like {@link Stream#mapToInt(ToIntFunction)}.
  401.      */
  402.     default IntStream mapToInt(final ToIntFunction<? super T> mapper) {
  403.         return unwrap().mapToInt(mapper);
  404.     }

  405.     /**
  406.      * TODO Package-private for now, needs IOToLongFunction?
  407.      *
  408.      * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It
  409.      * would be ideal to have only one.
  410.      *
  411.      * Like {@link Stream#mapToLong(ToLongFunction)}.
  412.      *
  413.      * Package private for now.
  414.      *
  415.      * @param mapper Like {@link Stream#mapToLong(ToLongFunction)}.
  416.      * @return Like {@link Stream#mapToLong(ToLongFunction)}.
  417.      */
  418.     default LongStream mapToLong(final ToLongFunction<? super T> mapper) {
  419.         return unwrap().mapToLong(mapper);
  420.     }

  421.     /**
  422.      * Like {@link Stream#max(java.util.Comparator)}.
  423.      *
  424.      * @param comparator Like {@link Stream#max(java.util.Comparator)}.
  425.      * @return Like {@link Stream#max(java.util.Comparator)}.
  426.      * @throws IOException if an I/O error occurs.
  427.      */
  428.     @SuppressWarnings("unused") // thrown by Erase.
  429.     default Optional<T> max(final IOComparator<? super T> comparator) throws IOException {
  430.         return unwrap().max((t, u) -> Erase.compare(comparator, t, u));
  431.     }

  432.     /**
  433.      * Like {@link Stream#min(java.util.Comparator)}.
  434.      *
  435.      * @param comparator Like {@link Stream#min(java.util.Comparator)}.
  436.      * @return Like {@link Stream#min(java.util.Comparator)}.
  437.      * @throws IOException if an I/O error occurs.
  438.      */
  439.     @SuppressWarnings("unused") // thrown by Erase.
  440.     default Optional<T> min(final IOComparator<? super T> comparator) throws IOException {
  441.         return unwrap().min((t, u) -> Erase.compare(comparator, t, u));
  442.     }

  443.     /**
  444.      * Like {@link Stream#noneMatch(java.util.function.Predicate)}.
  445.      *
  446.      * @param predicate Like {@link Stream#noneMatch(java.util.function.Predicate)}.
  447.      * @return Like {@link Stream#noneMatch(java.util.function.Predicate)}.
  448.      * @throws IOException if an I/O error occurs.
  449.      */
  450.     @SuppressWarnings("unused") // thrown by Erase.
  451.     default boolean noneMatch(final IOPredicate<? super T> predicate) throws IOException {
  452.         return unwrap().noneMatch(t -> Erase.test(predicate, t));
  453.     }

  454.     /**
  455.      * Like {@link Stream#peek(java.util.function.Consumer)}.
  456.      *
  457.      * @param action Like {@link Stream#peek(java.util.function.Consumer)}.
  458.      * @return Like {@link Stream#peek(java.util.function.Consumer)}.
  459.      * @throws IOException if an I/O error occurs.
  460.      */
  461.     @SuppressWarnings("unused") // thrown by Erase.
  462.     default IOStream<T> peek(final IOConsumer<? super T> action) throws IOException {
  463.         return adapt(unwrap().peek(t -> Erase.accept(action, t)));
  464.     }

  465.     /**
  466.      * Like {@link Stream#reduce(java.util.function.BinaryOperator)}.
  467.      *
  468.      * @param accumulator Like {@link Stream#reduce(java.util.function.BinaryOperator)}.
  469.      * @return Like {@link Stream#reduce(java.util.function.BinaryOperator)}.
  470.      * @throws IOException if an I/O error occurs.
  471.      */
  472.     @SuppressWarnings("unused") // thrown by Erase.
  473.     default Optional<T> reduce(final IOBinaryOperator<T> accumulator) throws IOException {
  474.         return unwrap().reduce((t, u) -> Erase.apply(accumulator, t, u));
  475.     }

  476.     /**
  477.      * Like {@link Stream#reduce(Object, java.util.function.BinaryOperator)}.
  478.      *
  479.      * @param identity Like {@link Stream#reduce(Object, java.util.function.BinaryOperator)}.
  480.      * @param accumulator Like {@link Stream#reduce(Object, java.util.function.BinaryOperator)}.
  481.      * @return Like {@link Stream#reduce(Object, java.util.function.BinaryOperator)}.
  482.      * @throws IOException if an I/O error occurs.
  483.      */
  484.     @SuppressWarnings("unused") // thrown by Erase.
  485.     default T reduce(final T identity, final IOBinaryOperator<T> accumulator) throws IOException {
  486.         return unwrap().reduce(identity, (t, u) -> Erase.apply(accumulator, t, u));
  487.     }

  488.     /**
  489.      * Like {@link Stream#reduce(Object, BiFunction, java.util.function.BinaryOperator)}.
  490.      *
  491.      * @param <U> Like {@link Stream#reduce(Object, BiFunction, java.util.function.BinaryOperator)}.
  492.      * @param identity Like {@link Stream#reduce(Object, BiFunction, java.util.function.BinaryOperator)}.
  493.      * @param accumulator Like {@link Stream#reduce(Object, BiFunction, java.util.function.BinaryOperator)}.
  494.      * @param combiner Like {@link Stream#reduce(Object, BiFunction, java.util.function.BinaryOperator)}.
  495.      * @return Like {@link Stream#reduce(Object, BiFunction, java.util.function.BinaryOperator)}.
  496.      * @throws IOException if an I/O error occurs.
  497.      */
  498.     @SuppressWarnings("unused") // thrown by Erase.
  499.     default <U> U reduce(final U identity, final IOBiFunction<U, ? super T, U> accumulator, final IOBinaryOperator<U> combiner) throws IOException {
  500.         return unwrap().reduce(identity, (t, u) -> Erase.apply(accumulator, t, u), (t, u) -> Erase.apply(combiner, t, u));
  501.     }

  502.     /**
  503.      * Like {@link Stream#skip(long)}.
  504.      *
  505.      * @param n Like {@link Stream#skip(long)}.
  506.      * @return Like {@link Stream#skip(long)}.
  507.      */
  508.     default IOStream<T> skip(final long n) {
  509.         return adapt(unwrap().skip(n));
  510.     }

  511.     /**
  512.      * Like {@link Stream#sorted()}.
  513.      *
  514.      * @return Like {@link Stream#sorted()}.
  515.      */
  516.     default IOStream<T> sorted() {
  517.         return adapt(unwrap().sorted());
  518.     }

  519.     /**
  520.      * Like {@link Stream#sorted(java.util.Comparator)}.
  521.      *
  522.      * @param comparator Like {@link Stream#sorted(java.util.Comparator)}.
  523.      * @return Like {@link Stream#sorted(java.util.Comparator)}.
  524.      * @throws IOException if an I/O error occurs.
  525.      */
  526.     @SuppressWarnings("unused") // thrown by Erase.
  527.     default IOStream<T> sorted(final IOComparator<? super T> comparator) throws IOException {
  528.         return adapt(unwrap().sorted((t, u) -> Erase.compare(comparator, t, u)));
  529.     }

  530.     /**
  531.      * Like {@link Stream#toArray()}.
  532.      *
  533.      * @return {@link Stream#toArray()}.
  534.      */
  535.     default Object[] toArray() {
  536.         return unwrap().toArray();
  537.     }

  538.     /**
  539.      * TODO Package-private for now, needs IOIntFunction?
  540.      *
  541.      * Adding this method now and an IO version later is an issue because call sites would have to type-cast to pick one. It
  542.      * would be ideal to have only one.
  543.      *
  544.      * Like {@link Stream#toArray(IntFunction)}.
  545.      *
  546.      * Package private for now.
  547.      *
  548.      * @param <A> Like {@link Stream#toArray(IntFunction)}.
  549.      * @param generator Like {@link Stream#toArray(IntFunction)}.
  550.      * @return Like {@link Stream#toArray(IntFunction)}.
  551.      */
  552.     default <A> A[] toArray(final IntFunction<A[]> generator) {
  553.         return unwrap().toArray(generator);
  554.     }

  555. }