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() {

Reply via email to