This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-io.git
commit 323d376b4a934a5a6ebdc552dc923db9e267e569 Author: Gary Gregory <[email protected]> AuthorDate: Wed Jul 20 13:03:56 2022 -0400 Add and reuse IOConsumer forAll(*), forEach(*) --- src/changes/changes.xml | 2 +- src/main/java/org/apache/commons/io/FileUtils.java | 4 +- src/main/java/org/apache/commons/io/IOUtils.java | 2 +- .../org/apache/commons/io/function/IOConsumer.java | 57 ++++++++++---- .../org/apache/commons/io/function/IOStreams.java | 88 ++++++++++++++++------ .../commons/io/input/ObservableInputStream.java | 2 +- .../commons/io/output/FilterCollectionWriter.java | 24 +++--- 7 files changed, 123 insertions(+), 56 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index cf8400d3..ebf5819d 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -357,7 +357,7 @@ The <action> type attribute can be add,update,fix,remove. Add IOBiConsumer. </action> <action dev="ggregory" type="add" due-to="Gary Gregory"> - Add and reuse IOConsumer.forEach(*) and forEachIndexed(*). + Add and reuse IOConsumer forAll(*), forEach(*), and forEachIndexed(*). </action> <action dev="ggregory" type="add" due-to="Gary Gregory"> Add CharsetEncoders. diff --git a/src/main/java/org/apache/commons/io/FileUtils.java b/src/main/java/org/apache/commons/io/FileUtils.java index 03fabb75..58ae0ff7 100644 --- a/src/main/java/org/apache/commons/io/FileUtils.java +++ b/src/main/java/org/apache/commons/io/FileUtils.java @@ -344,7 +344,7 @@ public class FileUtils { * @see #forceDelete(File) */ public static void cleanDirectory(final File directory) throws IOException { - IOConsumer.forEach(listFiles(directory, null), FileUtils::forceDelete); + IOConsumer.forAll(listFiles(directory, null), FileUtils::forceDelete); } /** @@ -357,7 +357,7 @@ public class FileUtils { * @see #forceDeleteOnExit(File) */ private static void cleanDirectoryOnExit(final File directory) throws IOException { - IOConsumer.forEach(listFiles(directory, null), FileUtils::forceDeleteOnExit); + IOConsumer.forAll(listFiles(directory, null), FileUtils::forceDeleteOnExit); } /** diff --git a/src/main/java/org/apache/commons/io/IOUtils.java b/src/main/java/org/apache/commons/io/IOUtils.java index fde29d42..fda772ec 100644 --- a/src/main/java/org/apache/commons/io/IOUtils.java +++ b/src/main/java/org/apache/commons/io/IOUtils.java @@ -395,7 +395,7 @@ public class IOUtils { * @since 2.8.0 */ public static void close(final Closeable... closeables) throws IOException { - IOConsumer.forEach(closeables, IOUtils::close); + IOConsumer.forAll(closeables, IOUtils::close); } /** diff --git a/src/main/java/org/apache/commons/io/function/IOConsumer.java b/src/main/java/org/apache/commons/io/function/IOConsumer.java index a8492d2b..66f9c062 100644 --- a/src/main/java/org/apache/commons/io/function/IOConsumer.java +++ b/src/main/java/org/apache/commons/io/function/IOConsumer.java @@ -18,7 +18,6 @@ package org.apache.commons.io.function; import java.io.IOException; -import java.util.Collection; import java.util.Objects; import java.util.function.Consumer; import java.util.stream.Stream; @@ -41,55 +40,81 @@ public interface IOConsumer<T> { IOConsumer<?> NOOP_IO_CONSUMER = t -> {/* noop */}; /** - * Performs an action for each element of the collection. + * Performs an action for each element of the collection gathering any exceptions. * * @param <T> The element type. * @param collection The input to stream. * @param action The action to apply to each input element. - * @throws IOException if an I/O error occurs. + * @throws IOExceptionList if any I/O errors occur. * @since 2.12.0 */ - static <T> void forEach(final Collection<T> collection, final IOConsumer<T> action) throws IOException { - IOStreams.forEach(IOStreams.of(collection), action); + static <T> void forAll(final Iterable<T> collection, final IOConsumer<T> action) throws IOExceptionList { + IOStreams.forAll(IOStreams.of(collection), action); } /** - * Performs an action for each element of the stream. + * Performs an action for each element of the collection gathering any exceptions. * * @param <T> The element type. * @param stream The input to stream. * @param action The action to apply to each input element. - * @throws IOException if an I/O error occurs. + * @throws IOExceptionList if any I/O errors occur. * @since 2.12.0 */ - static <T> void forEach(final Stream<T> stream, final IOConsumer<T> action) throws IOException { - IOStreams.forEach(stream, action); + static <T> void forAll(final Stream<T> stream, final IOConsumer<T> action) throws IOExceptionList { + IOStreams.forAll(stream, action, IOIndexedException::new); } /** - * Performs an action for each element of this array. + * Performs an action for each element of the array gathering any exceptions. * * @param <T> The element type. * @param array The input to stream. * @param action The action to apply to each input element. + * @throws IOExceptionList if any I/O errors occur. + * @since 2.12.0 + */ + static <T> void forAll(final T[] array, final IOConsumer<T> action) throws IOExceptionList { + IOStreams.forAll(IOStreams.of(array), action); + } + + /** + * Performs an action for each element of the collection, stopping at the first exception. + * + * @param <T> The element type. + * @param collection The input to stream. + * @param action The action to apply to each input element. * @throws IOException if an I/O error occurs. * @since 2.12.0 */ - static <T> void forEach(final T[] array, final IOConsumer<T> action) throws IOException { - IOStreams.forEach(IOStreams.of(array), action); + static <T> void forEach(final Iterable<T> collection, final IOConsumer<T> action) throws IOException { + IOStreams.forEach(IOStreams.of(collection), action); } /** - * Performs an action for each element of the stream. + * Performs an action for each element of the stream, stopping at the first exception. * * @param <T> The element type. * @param stream The input to stream. * @param action The action to apply to each input element. - * @throws IOExceptionList if an I/O error occurs. + * @throws IOException if an I/O error occurs. + * @since 2.12.0 + */ + static <T> void forEach(final Stream<T> stream, final IOConsumer<T> action) throws IOException { + IOStreams.forEach(stream, action); + } + + /** + * Performs an action for each element of this array, stopping at the first exception. + * + * @param <T> The element type. + * @param array The input to stream. + * @param action The action to apply to each input element. + * @throws IOException if an I/O error occurs. * @since 2.12.0 */ - static <T> void forEachIndexed(final Stream<T> stream, final IOConsumer<T> action) throws IOExceptionList { - IOStreams.forEachIndexed(stream, action, IOIndexedException::new); + static <T> void forEach(final T[] array, final IOConsumer<T> action) throws IOException { + IOStreams.forEach(IOStreams.of(array), action); } /** diff --git a/src/main/java/org/apache/commons/io/function/IOStreams.java b/src/main/java/org/apache/commons/io/function/IOStreams.java index 21f344bd..5dfd107f 100644 --- a/src/main/java/org/apache/commons/io/function/IOStreams.java +++ b/src/main/java/org/apache/commons/io/function/IOStreams.java @@ -19,12 +19,12 @@ package org.apache.commons.io.function; import java.io.IOException; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiFunction; import java.util.stream.Stream; +import java.util.stream.StreamSupport; import org.apache.commons.io.IOExceptionList; @@ -33,34 +33,56 @@ import org.apache.commons.io.IOExceptionList; */ class IOStreams { - static <T> void forEach(final Stream<T> stream, final IOConsumer<T> action) throws IOException { - forEachIndexed(stream, action, (i, e) -> e); + /** + * Accepts and throws an IOException. + * + * @param <T> The consumer type. + * @param consumer The consumer to accept. + * @param t the input argument. + * @throws IOException if an I/O error occurs; erased for the compiler. + */ + static <T> void accept(final IOConsumer<T> consumer, T t) { + try { + consumer.accept(t); + } catch (IOException ex) { + rethrow(ex); + } + } + + static <T> void forAll(final Stream<T> stream, final IOConsumer<T> action) throws IOExceptionList { + forAll(stream, action, (i, e) -> e); } - static <T> void forEachIndexed(final Stream<T> stream, final IOConsumer<T> action, final BiFunction<Integer, IOException, IOException> exSupplier) + static <T> void forAll(final Stream<T> stream, final IOConsumer<T> action, final BiFunction<Integer, IOException, IOException> exSupplier) throws IOExceptionList { final AtomicReference<List<IOException>> causeList = new AtomicReference<>(); final AtomicInteger index = new AtomicInteger(); - final IOConsumer<T> actualAction = action != null ? action : IOConsumer.noop(); - if (stream != null) { - stream.forEach(e -> { - try { - actualAction.accept(e); - } catch (final IOException ioex) { - if (causeList.get() == null) { - causeList.set(new ArrayList<>()); - } - if (exSupplier != null) { - causeList.get().add(exSupplier.apply(index.get(), ioex)); - } + final IOConsumer<T> actualAction = toIOConsumer(action); + of(stream).forEach(e -> { + try { + actualAction.accept(e); + } catch (IOException ex) { + if (causeList.get() == null) { + // Only allocate if required + causeList.set(new ArrayList<>()); + } + if (exSupplier != null) { + causeList.get().add(exSupplier.apply(index.get(), ex)); } - index.incrementAndGet(); - }); - IOExceptionList.checkEmpty(causeList.get(), null); - }} + } + index.incrementAndGet(); + }); + IOExceptionList.checkEmpty(causeList.get(), null); + } + + @SuppressWarnings("unused") // IOStreams.rethrow() throws + static <T> void forEach(final Stream<T> stream, final IOConsumer<T> action) throws IOException { + final IOConsumer<T> actualAction = toIOConsumer(action); + of(stream).forEach(e -> accept(actualAction, e)); + } /** - * Null-safe version of {@link Collection#stream()}. + * Null-safe version of {@link StreamSupport#stream(java.util.Spliterator, boolean)}. * * Copied from Apache Commons Lang. * @@ -68,8 +90,12 @@ class IOStreams { * @param values the elements of the new stream, may be {@code null}. * @return the new stream on {@code values} or {@link Stream#empty()}. */ - static <T> Stream<T> of(final Collection<T> values) { - return values == null ? Stream.empty() : values.stream(); + static <T> Stream<T> of(final Iterable<T> values) { + return values == null ? Stream.empty() : StreamSupport.stream(values.spliterator(), false); + } + + static <T> Stream<T> of(final Stream<T> stream) { + return stream == null ? Stream.empty() : stream; } /** @@ -86,4 +112,20 @@ class IOStreams { return values == null ? Stream.empty() : Stream.of(values); } + /** + * Throws the given throwable. + * + * @param <T> The throwable cast type. + * @param throwable The throwable to rethrow. + * @return nothing because we throw. + * @throws T Always thrown. + */ + @SuppressWarnings("unchecked") + static <T extends Throwable> RuntimeException rethrow(final Throwable throwable) throws T { + throw (T) throwable; // hack + } + + static <T> IOConsumer<T> toIOConsumer(final IOConsumer<T> action) { + return action != null ? action : IOConsumer.noop(); + } } diff --git a/src/main/java/org/apache/commons/io/input/ObservableInputStream.java b/src/main/java/org/apache/commons/io/input/ObservableInputStream.java index 3acf9938..837d0f1f 100644 --- a/src/main/java/org/apache/commons/io/input/ObservableInputStream.java +++ b/src/main/java/org/apache/commons/io/input/ObservableInputStream.java @@ -175,7 +175,7 @@ public class ObservableInputStream extends ProxyInputStream { } private void forEachObserver(final IOConsumer<Observer> action) throws IOException { - IOConsumer.forEach(observers, Objects.requireNonNull(action)); + IOConsumer.forAll(observers, Objects.requireNonNull(action)); } /** diff --git a/src/main/java/org/apache/commons/io/output/FilterCollectionWriter.java b/src/main/java/org/apache/commons/io/output/FilterCollectionWriter.java index 6bc7d38f..579951aa 100644 --- a/src/main/java/org/apache/commons/io/output/FilterCollectionWriter.java +++ b/src/main/java/org/apache/commons/io/output/FilterCollectionWriter.java @@ -85,25 +85,25 @@ public class FilterCollectionWriter extends Writer { @Override public Writer append(final char c) throws IOException { - forEachWriter(w -> w.append(c)); + forAllWriters(w -> w.append(c)); return this; } @Override public Writer append(final CharSequence csq) throws IOException { - forEachWriter(w -> w.append(csq)); + forAllWriters(w -> w.append(csq)); return this; } @Override public Writer append(final CharSequence csq, final int start, final int end) throws IOException { - forEachWriter(w -> w.append(csq, start, end)); + forAllWriters(w -> w.append(csq, start, end)); return this; } @Override public void close() throws IOException { - forEachWriter(Writer::close); + forAllWriters(Writer::close); } /** @@ -113,16 +113,16 @@ public class FilterCollectionWriter extends Writer { */ @Override public void flush() throws IOException { - forEachWriter(Writer::flush); + forAllWriters(Writer::flush); } - private void forEachWriter(final IOConsumer<Writer> action) throws IOExceptionList { - IOConsumer.forEachIndexed(writers(), action); + private void forAllWriters(final IOConsumer<Writer> action) throws IOExceptionList { + IOConsumer.forAll(writers(), action); } @Override public void write(final char[] cbuf) throws IOException { - forEachWriter(w -> w.write(cbuf)); + forAllWriters(w -> w.write(cbuf)); } /** @@ -136,7 +136,7 @@ public class FilterCollectionWriter extends Writer { */ @Override public void write(final char[] cbuf, final int off, final int len) throws IOException { - forEachWriter(w -> w.write(cbuf, off, len)); + forAllWriters(w -> w.write(cbuf, off, len)); } /** @@ -146,12 +146,12 @@ public class FilterCollectionWriter extends Writer { */ @Override public void write(final int c) throws IOException { - forEachWriter(w -> w.write(c)); + forAllWriters(w -> w.write(c)); } @Override public void write(final String str) throws IOException { - forEachWriter(w -> w.write(str)); + forAllWriters(w -> w.write(str)); } /** @@ -165,7 +165,7 @@ public class FilterCollectionWriter extends Writer { */ @Override public void write(final String str, final int off, final int len) throws IOException { - forEachWriter(w -> w.write(str, off, len)); + forAllWriters(w -> w.write(str, off, len)); } private Stream<Writer> writers() {
