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
The following commit(s) were added to refs/heads/master by this push:
new 4aab769c Reduce boilerplate through new UncheckedIO class and friends
in org.apache.commons.io.function.
4aab769c is described below
commit 4aab769c3279ea63b7bcdaa163c50761bc540f8c
Author: Gary Gregory <[email protected]>
AuthorDate: Fri May 13 17:55:10 2022 -0400
Reduce boilerplate through new UncheckedIO class and friends in
org.apache.commons.io.function.
---
src/changes/changes.xml | 3 +
src/main/java/org/apache/commons/io/FileUtils.java | 108 +++-----------
.../java/org/apache/commons/io/UncheckedIO.java | 158 +++++++++++++++++++++
.../apache/commons/io/UncheckedIOExceptions.java | 9 +-
.../java/org/apache/commons/io/file/PathUtils.java | 8 +-
.../apache/commons/io/function/IOBiFunction.java | 81 +++++++++++
.../org/apache/commons/io/function/IORunnable.java | 36 +++++
.../apache/commons/io/function/IOTriFunction.java | 83 +++++++++++
.../commons/io/input/UncheckedBufferedReader.java | 66 ++-------
.../io/input/UncheckedFilterInputStream.java | 48 ++-----
.../commons/io/input/UncheckedFilterReader.java | 60 ++------
.../commons/io/output/UncheckedAppendableImpl.java | 22 +--
.../commons/io/UncheckedIOExceptionsTest.java | 16 ++-
.../org/apache/commons/io/UncheckedIOTest.java | 102 +++++++++++++
.../commons/io/function/IOBiFunctionTest.java | 92 ++++++++++++
.../IORunnableTest.java} | 41 +++---
.../commons/io/function/IOTriFunctionTest.java | 112 +++++++++++++++
17 files changed, 761 insertions(+), 284 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 936d9bb7..817b953d 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -353,6 +353,9 @@ The <action> type attribute can be add,update,fix,remove.
<action issue="IO-680" dev="ggregory" type="add" due-to="XenoAmess,
sebbASF, Gary Gregory">
Add more tests for IOUtils.contentEqualsIgnoreEOL #137.
</action>
+ <action dev="ggregory" type="add" due-to="Gary Gregory">
+ Reduce boilerplate through new UncheckedIO class and friends in
org.apache.commons.io.function.
+ </action>
<!-- UPDATE -->
<action dev="ggregory" type="update" due-to="Dependabot">
Bump actions/checkout from 2.3.4 to 3 #286, #298, #330.
diff --git a/src/main/java/org/apache/commons/io/FileUtils.java
b/src/main/java/org/apache/commons/io/FileUtils.java
index a4cbdfe7..f5a04f16 100644
--- a/src/main/java/org/apache/commons/io/FileUtils.java
+++ b/src/main/java/org/apache/commons/io/FileUtils.java
@@ -1632,12 +1632,9 @@ public class FileUtils {
* @since 2.8.0
*/
public static boolean isFileNewer(final File file, final
ChronoZonedDateTime<?> chronoZonedDateTime) {
+ Objects.requireNonNull(file, "file");
Objects.requireNonNull(chronoZonedDateTime, "chronoZonedDateTime");
- try {
- return PathUtils.isNewer(file.toPath(), chronoZonedDateTime);
- } catch (final IOException e) {
- throw new UncheckedIOException(e);
- }
+ return UncheckedIO.get(() -> PathUtils.isNewer(file.toPath(),
chronoZonedDateTime));
}
/**
@@ -1666,11 +1663,7 @@ public class FileUtils {
*/
public static boolean isFileNewer(final File file, final File reference) {
requireExists(reference, "reference");
- try {
- return PathUtils.isNewer(file.toPath(), reference.toPath());
- } catch (final IOException e) {
- throw new UncheckedIOException(e);
- }
+ return UncheckedIO.get(() -> PathUtils.isNewer(file.toPath(),
reference.toPath()));
}
/**
@@ -1699,11 +1692,7 @@ public class FileUtils {
*/
public static boolean isFileNewer(final File file, final Instant instant) {
Objects.requireNonNull(instant, "instant");
- try {
- return PathUtils.isNewer(file.toPath(), instant);
- } catch (final IOException e) {
- throw new UncheckedIOException(e);
- }
+ return UncheckedIO.get(() -> PathUtils.isNewer(file.toPath(),
instant));
}
/**
@@ -1717,11 +1706,7 @@ public class FileUtils {
*/
public static boolean isFileNewer(final File file, final long timeMillis) {
Objects.requireNonNull(file, "file");
- try {
- return PathUtils.isNewer(file.toPath(), timeMillis);
- } catch (final IOException e) {
- throw new UncheckedIOException(e);
- }
+ return UncheckedIO.get(() -> PathUtils.isNewer(file.toPath(),
timeMillis));
}
/**
@@ -1854,11 +1839,7 @@ public class FileUtils {
*/
public static boolean isFileOlder(final File file, final File reference) {
requireExists(reference, "reference");
- try {
- return PathUtils.isOlder(file.toPath(), reference.toPath());
- } catch (final IOException e) {
- throw new UncheckedIOException(e);
- }
+ return UncheckedIO.get(() -> PathUtils.isOlder(file.toPath(),
reference.toPath()));
}
/**
@@ -1887,11 +1868,7 @@ public class FileUtils {
*/
public static boolean isFileOlder(final File file, final Instant instant) {
Objects.requireNonNull(instant, "instant");
- try {
- return PathUtils.isOlder(file.toPath(), instant);
- } catch (final IOException e) {
- throw new UncheckedIOException(e);
- }
+ return UncheckedIO.get(() -> PathUtils.isOlder(file.toPath(),
instant));
}
/**
@@ -1905,11 +1882,7 @@ public class FileUtils {
*/
public static boolean isFileOlder(final File file, final long timeMillis) {
Objects.requireNonNull(file, "file");
- try {
- return PathUtils.isOlder(file.toPath(), timeMillis);
- } catch (final IOException e) {
- throw new UncheckedIOException(e);
- }
+ return UncheckedIO.get(() -> PathUtils.isOlder(file.toPath(),
timeMillis));
}
/**
@@ -1984,11 +1957,7 @@ public class FileUtils {
* @since 1.2
*/
public static Iterator<File> iterateFiles(final File directory, final
String[] extensions, final boolean recursive) {
- try {
- return StreamIterator.iterator(streamFiles(directory, recursive,
extensions));
- } catch (final IOException e) {
- throw UncheckedIOExceptions.create(directory, e);
- }
+ return UncheckedIO.apply(d -> StreamIterator.iterator(streamFiles(d,
recursive, extensions)), directory);
}
/**
@@ -2084,11 +2053,7 @@ public class FileUtils {
// https://bugs.openjdk.java.net/browse/JDK-8177809
// File.lastModified() is losing milliseconds (always ends in 000)
// This bug is in OpenJDK 8 and 9, and fixed in 10.
- try {
- return lastModified(file);
- } catch (final IOException e) {
- throw UncheckedIOExceptions.create(file, e);
- }
+ return UncheckedIO.apply(FileUtils::lastModified, file);
}
/**
@@ -2217,12 +2182,9 @@ public class FileUtils {
* @see org.apache.commons.io.filefilter.NameFileFilter
*/
public static Collection<File> listFiles(final File directory, final
IOFileFilter fileFilter, final IOFileFilter dirFilter) {
- try {
- final AccumulatorPathVisitor visitor = listAccumulate(directory,
FileFileFilter.INSTANCE.and(fileFilter), dirFilter,
FileVisitOption.FOLLOW_LINKS);
- return
visitor.getFileList().stream().map(Path::toFile).collect(Collectors.toList());
- } catch (final IOException e) {
- throw UncheckedIOExceptions.create(directory, e);
- }
+ final AccumulatorPathVisitor visitor = UncheckedIO
+ .apply(d -> listAccumulate(d,
FileFileFilter.INSTANCE.and(fileFilter), dirFilter,
FileVisitOption.FOLLOW_LINKS), directory);
+ return
visitor.getFileList().stream().map(Path::toFile).collect(Collectors.toList());
}
/**
@@ -2236,11 +2198,7 @@ public class FileUtils {
* @return a collection of java.io.File with the matching files
*/
public static Collection<File> listFiles(final File directory, final
String[] extensions, final boolean recursive) {
- try {
- return toList(streamFiles(directory, recursive, extensions));
- } catch (final IOException e) {
- throw UncheckedIOExceptions.create(directory, e);
- }
+ return UncheckedIO.apply(d -> toList(streamFiles(d, recursive,
extensions)), directory);
}
/**
@@ -2263,14 +2221,11 @@ public class FileUtils {
* @since 2.2
*/
public static Collection<File> listFilesAndDirs(final File directory,
final IOFileFilter fileFilter, final IOFileFilter dirFilter) {
- try {
- final AccumulatorPathVisitor visitor = listAccumulate(directory,
fileFilter, dirFilter, FileVisitOption.FOLLOW_LINKS);
- final List<Path> list = visitor.getFileList();
- list.addAll(visitor.getDirList());
- return
list.stream().map(Path::toFile).collect(Collectors.toList());
- } catch (final IOException e) {
- throw UncheckedIOExceptions.create(directory, e);
- }
+ final AccumulatorPathVisitor visitor = UncheckedIO.apply(d ->
listAccumulate(d, fileFilter, dirFilter, FileVisitOption.FOLLOW_LINKS),
+ directory);
+ final List<Path> list = visitor.getFileList();
+ list.addAll(visitor.getDirList());
+ return list.stream().map(Path::toFile).collect(Collectors.toList());
}
/**
@@ -2921,11 +2876,7 @@ public class FileUtils {
*/
public static long sizeOf(final File file) {
requireExists(file, "file");
- try {
- return PathUtils.sizeOf(file.toPath());
- } catch (final IOException e) {
- throw new UncheckedIOException(e);
- }
+ return UncheckedIO.get(() -> PathUtils.sizeOf(file.toPath()));
}
/**
@@ -2949,11 +2900,7 @@ public class FileUtils {
*/
public static BigInteger sizeOfAsBigInteger(final File file) {
requireExists(file, "file");
- try {
- return PathUtils.sizeOfAsBigInteger(file.toPath());
- } catch (final IOException e) {
- throw new UncheckedIOException(e);
- }
+ return UncheckedIO.get(() ->
PathUtils.sizeOfAsBigInteger(file.toPath()));
}
/**
@@ -2972,11 +2919,7 @@ public class FileUtils {
*/
public static long sizeOfDirectory(final File directory) {
requireDirectoryExists(directory, "directory");
- try {
- return PathUtils.sizeOfDirectory(directory.toPath());
- } catch (final IOException e) {
- throw new UncheckedIOException(e);
- }
+ return UncheckedIO.get(() ->
PathUtils.sizeOfDirectory(directory.toPath()));
}
/**
@@ -2990,12 +2933,7 @@ public class FileUtils {
*/
public static BigInteger sizeOfDirectoryAsBigInteger(final File directory)
{
requireDirectoryExists(directory, "directory");
- try {
- return PathUtils.sizeOfDirectoryAsBigInteger(directory.toPath());
- } catch (final IOException e) {
- throw new UncheckedIOException(e);
- }
-
+ return UncheckedIO.get(() ->
PathUtils.sizeOfDirectoryAsBigInteger(directory.toPath()));
}
/**
diff --git a/src/main/java/org/apache/commons/io/UncheckedIO.java
b/src/main/java/org/apache/commons/io/UncheckedIO.java
new file mode 100644
index 00000000..c8e0791b
--- /dev/null
+++ b/src/main/java/org/apache/commons/io/UncheckedIO.java
@@ -0,0 +1,158 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.io;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+
+import org.apache.commons.io.function.IOBiFunction;
+import org.apache.commons.io.function.IOConsumer;
+import org.apache.commons.io.function.IOFunction;
+import org.apache.commons.io.function.IORunnable;
+import org.apache.commons.io.function.IOSupplier;
+import org.apache.commons.io.function.IOTriFunction;
+
+/**
+ * Helps use lambdas that throw {@link IOException} rethrow as {@link
UncheckedIOException}.
+ *
+ * @since 2.12.0
+ */
+public class UncheckedIO {
+
+ /**
+ * Accepts an IO consumer with the given argument.
+ *
+ * @param <T> the return type of the operations.
+ * @param t the consumer argument.
+ * @param consumer Consumes the value.
+ * @throws UncheckedIOException if an I/O error occurs.
+ */
+ public static <T> void accept(final IOConsumer<T> consumer, final T t) {
+ try {
+ consumer.accept(t);
+ } catch (final IOException e) {
+ throw wrap(e);
+ }
+ }
+
+ /**
+ * Applies an IO bi-function with the given arguments.
+ *
+ * @param biFunction the function.
+ * @param <T> the first function argument type.
+ * @param <U> the second function argument type.
+ * @param <R> the return type.
+ *
+ * @param t the first function argument
+ * @param u the second function argument
+ * @return the function result
+ * @throws UncheckedIOException if an I/O error occurs.
+ */
+ public static <T, U, R> R apply(final IOBiFunction<T, U, R> biFunction,
final T t, final U u) {
+ try {
+ return biFunction.apply(t, u);
+ } catch (final IOException e) {
+ throw wrap(e);
+ }
+ }
+
+ /**
+ * Applies an IO function with the given arguments.
+ *
+ * @param function the function.
+ * @param <T> the first function argument type.
+ * @param <R> the return type.
+ *
+ * @param t the first function argument
+ * @return the function result
+ * @throws UncheckedIOException if an I/O error occurs.
+ */
+ public static <T, R> R apply(final IOFunction<T, R> function, final T t) {
+ try {
+ return function.apply(t);
+ } catch (final IOException e) {
+ throw wrap(e);
+ }
+ }
+
+ /**
+ * Applies an IO tri-function with the given arguments.
+ *
+ * @param triFunction the function.
+ * @param <T> the first function argument type.
+ * @param <U> the second function argument type.
+ * @param <V> the third function argument type.
+ * @param <R> the return type.
+ *
+ * @param t the first function argument
+ * @param u the second function argument
+ * @param v the third function argument
+ * @return the function result
+ * @throws UncheckedIOException if an I/O error occurs.
+ */
+ public static <T, U, V, R> R apply(final IOTriFunction<T, U, V, R>
triFunction, final T t, final U u, final V v) {
+ try {
+ return triFunction.apply(t, u, v);
+ } catch (final IOException e) {
+ throw wrap(e);
+ }
+ }
+
+ /**
+ * Creates a new UncheckedIOException for the given detail message.
+ * <p>
+ * This method exists because there is no String constructor in {@link
UncheckedIOException}.
+ * </p>
+ *
+ * @param e The exception to wrap.
+ * @return a new {@link UncheckedIOException}.
+ */
+ private static UncheckedIOException wrap(final IOException e) {
+ return new UncheckedIOException(e);
+ }
+
+ /**
+ * Gets the result from an IO supplier.
+ *
+ * @param <T> the return type of the operations.
+ * @param supplier Supplies the return value.
+ * @return result from the supplier.
+ * @throws UncheckedIOException if an I/O error occurs.
+ */
+ public static <T> T get(final IOSupplier<T> supplier) {
+ try {
+ return supplier.get();
+ } catch (final IOException e) {
+ throw wrap(e);
+ }
+ }
+
+ /**
+ * Runs an IO runnable.
+ *
+ * @param runnable The runnable to run.
+ * @throws UncheckedIOException if an I/O error occurs.
+ */
+ public static void run(final IORunnable runnable) {
+ try {
+ runnable.run();
+ } catch (final IOException e) {
+ throw wrap(e);
+ }
+ }
+}
diff --git a/src/main/java/org/apache/commons/io/UncheckedIOExceptions.java
b/src/main/java/org/apache/commons/io/UncheckedIOExceptions.java
index 4173c0d4..f8f2c500 100644
--- a/src/main/java/org/apache/commons/io/UncheckedIOExceptions.java
+++ b/src/main/java/org/apache/commons/io/UncheckedIOExceptions.java
@@ -22,7 +22,7 @@ import java.io.UncheckedIOException;
import java.util.Objects;
/**
- * Helps use {@link UncheckedIOException}.
+ * Helps use lambdas that throw {@link IOException} rethrow as {@link
UncheckedIOException}.
*
* @since 2.12.0
*/
@@ -47,13 +47,12 @@ public class UncheckedIOExceptions {
* <p>
* This method exists because there is no String constructor in {@link
UncheckedIOException}.
* </p>
- *
- * @param message the detail message.
* @param e cause the {@code IOException}.
+ * @param message the detail message.
+ *
* @return a new {@link UncheckedIOException}.
*/
- public static UncheckedIOException create(final Object message, final
IOException e) {
+ public static UncheckedIOException wrap(final IOException e, final Object
message) {
return new UncheckedIOException(Objects.toString(message), e);
}
-
}
diff --git a/src/main/java/org/apache/commons/io/file/PathUtils.java
b/src/main/java/org/apache/commons/io/file/PathUtils.java
index ebcbf4df..ef45a8c5 100644
--- a/src/main/java/org/apache/commons/io/file/PathUtils.java
+++ b/src/main/java/org/apache/commons/io/file/PathUtils.java
@@ -69,7 +69,7 @@ import java.util.stream.Stream;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
-import org.apache.commons.io.UncheckedIOExceptions;
+import org.apache.commons.io.UncheckedIO;
import org.apache.commons.io.file.Counters.PathCounters;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.function.IOFunction;
@@ -1136,7 +1136,7 @@ public final class PathUtils {
/**
* Reads the BasicFileAttributes from the given path. Returns null instead
of throwing
- * {@link UnsupportedOperationException}. Throws {@link
UncheckedIOExceptions} instead of {@link IOException}.
+ * {@link UnsupportedOperationException}. Throws {@link UncheckedIO}
instead of {@link IOException}.
*
* @param <A> The {@code BasicFileAttributes} type
* @param path The Path to test.
@@ -1148,12 +1148,10 @@ public final class PathUtils {
*/
public static <A extends BasicFileAttributes> A readAttributes(final Path
path, final Class<A> type, final LinkOption... options) {
try {
- return path == null ? null : Files.readAttributes(path, type,
options);
+ return path == null ? null :
UncheckedIO.apply(Files::readAttributes, path, type, options);
} catch (final UnsupportedOperationException e) {
// For example, on Windows.
return null;
- } catch (final IOException e) {
- throw UncheckedIOExceptions.create(path, e);
}
}
diff --git a/src/main/java/org/apache/commons/io/function/IOBiFunction.java
b/src/main/java/org/apache/commons/io/function/IOBiFunction.java
new file mode 100644
index 00000000..c3e8e556
--- /dev/null
+++ b/src/main/java/org/apache/commons/io/function/IOBiFunction.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.io.function;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.function.Function;
+
+/**
+ * Represents a function that accepts two arguments and produces a result.
This is the two-arity specialization of
+ * {@link IOFunction}.
+ *
+ * <p>
+ * This is a <a href="package-summary.html">functional interface</a> whose
functional method is
+ * {@link #apply(Object, Object)}.
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 2.12.0
+ */
+@FunctionalInterface
+public interface IOBiFunction<T, U, R> {
+
+ /**
+ * Applies this function to the given arguments.
+ *
+ * @param t the first function argument
+ * @param u the second function argument
+ * @return the function result
+ * @throws IOException if an I/O error occurs.
+ */
+ R apply(T t, U u) throws IOException;
+
+ /**
+ * Returns a composed function that first applies this function to its
input, and then applies the {@code after}
+ * function to the result. If evaluation of either function throws an
exception, it is relayed to the caller of the
+ * composed function.
+ *
+ * @param <V> the type of output of the {@code after} function, and of the
composed function
+ * @param after the function to apply after this function is applied
+ * @return a composed function that first applies this function and then
applies the {@code after} function
+ * @throws NullPointerException if after is null
+ */
+ default <V> IOBiFunction<T, U, V> andThen(final Function<? super R, ?
extends V> after) {
+ Objects.requireNonNull(after);
+ return (final T t, final U u) -> after.apply(apply(t, u));
+ }
+
+ /**
+ * Returns a composed function that first applies this function to its
input, and then applies the {@code after}
+ * function to the result. If evaluation of either function throws an
exception, it is relayed to the caller of the
+ * composed function.
+ *
+ * @param <V> the type of output of the {@code after} function, and of the
composed function
+ * @param after the function to apply after this function is applied
+ * @return a composed function that first applies this function and then
applies the {@code after} function
+ * @throws NullPointerException if after is null
+ */
+ default <V> IOBiFunction<T, U, V> andThen(final IOFunction<? super R, ?
extends V> after) {
+ Objects.requireNonNull(after);
+ return (final T t, final U u) -> after.apply(apply(t, u));
+ }
+}
diff --git a/src/main/java/org/apache/commons/io/function/IORunnable.java
b/src/main/java/org/apache/commons/io/function/IORunnable.java
new file mode 100644
index 00000000..01403ef7
--- /dev/null
+++ b/src/main/java/org/apache/commons/io/function/IORunnable.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.io.function;
+
+import java.io.IOException;
+
+/**
+ * Like {@link Runnable} but throws {@link IOException}.
+ *
+ * @since 2.12.0
+ */
+@FunctionalInterface
+public interface IORunnable {
+
+ /**
+ * Like {@link Runnable#run()} but throws {@link IOException}.
+ *
+ * @throws IOException if an I/O error occurs.
+ */
+ void run() throws IOException;
+}
diff --git a/src/main/java/org/apache/commons/io/function/IOTriFunction.java
b/src/main/java/org/apache/commons/io/function/IOTriFunction.java
new file mode 100644
index 00000000..a7c4e11b
--- /dev/null
+++ b/src/main/java/org/apache/commons/io/function/IOTriFunction.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.io.function;
+
+import java.io.IOException;
+import java.util.Objects;
+import java.util.function.Function;
+
+/**
+ * Represents a function that accepts three arguments and produces a result.
This is the three-arity specialization of
+ * {@link IOFunction}.
+ *
+ * <p>
+ * This is a <a href="package-summary.html">functional interface</a> whose
functional method is
+ * {@link #apply(Object, Object, Object)}.
+ * </p>
+ *
+ * @param <T> the type of the first argument to the function
+ * @param <U> the type of the second argument to the function
+ * @param <V> the type of the third argument to the function
+ * @param <R> the type of the result of the function
+ *
+ * @see Function
+ * @since 2.12.0
+ */
+@FunctionalInterface
+public interface IOTriFunction<T, U, V, R> {
+
+ /**
+ * Applies this function to the given arguments.
+ *
+ * @param t the first function argument
+ * @param u the second function argument
+ * @param v the third function argument
+ * @return the function result
+ * @throws IOException if an I/O error occurs.
+ */
+ R apply(T t, U u, V v) throws IOException;
+
+ /**
+ * Returns a composed function that first applies this function to its
input, and then applies the {@code after}
+ * function to the result. If evaluation of either function throws an
exception, it is relayed to the caller of the
+ * composed function.
+ *
+ * @param <W> the type of output of the {@code after} function, and of the
composed function
+ * @param after the function to apply after this function is applied
+ * @return a composed function that first applies this function and then
applies the {@code after} function
+ * @throws NullPointerException if after is null
+ */
+ default <W> IOTriFunction<T, U, V, W> andThen(final IOFunction<? super R,
? extends W> after) {
+ Objects.requireNonNull(after);
+ return (final T t, final U u, final V v) -> after.apply(apply(t, u,
v));
+ }
+
+ /**
+ * Returns a composed function that first applies this function to its
input, and then applies the {@code after}
+ * function to the result. If evaluation of either function throws an
exception, it is relayed to the caller of the
+ * composed function.
+ *
+ * @param <W> the type of output of the {@code after} function, and of the
composed function
+ * @param after the function to apply after this function is applied
+ * @return a composed function that first applies this function and then
applies the {@code after} function
+ * @throws NullPointerException if after is null
+ */
+ default <W> IOTriFunction<T, U, V, W> andThen(final Function<? super R, ?
extends W> after) {
+ Objects.requireNonNull(after);
+ return (final T t, final U u, final V v) -> after.apply(apply(t, u,
v));
+ }
+}
diff --git
a/src/main/java/org/apache/commons/io/input/UncheckedBufferedReader.java
b/src/main/java/org/apache/commons/io/input/UncheckedBufferedReader.java
index f6c6a9c3..a73b73cd 100644
--- a/src/main/java/org/apache/commons/io/input/UncheckedBufferedReader.java
+++ b/src/main/java/org/apache/commons/io/input/UncheckedBufferedReader.java
@@ -23,6 +23,8 @@ import java.io.Reader;
import java.io.UncheckedIOException;
import java.nio.CharBuffer;
+import org.apache.commons.io.UncheckedIO;
+
/**
* A {@link BufferedReader} that throws {@link UncheckedIOException} instead
of {@link IOException}.
*
@@ -70,11 +72,7 @@ public class UncheckedBufferedReader extends BufferedReader {
*/
@Override
public void close() throws UncheckedIOException {
- try {
- super.close();
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ UncheckedIO.run(super::close);
}
/**
@@ -82,11 +80,7 @@ public class UncheckedBufferedReader extends BufferedReader {
*/
@Override
public void mark(final int readAheadLimit) throws UncheckedIOException {
- try {
- super.mark(readAheadLimit);
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ UncheckedIO.accept(super::mark, readAheadLimit);
}
/**
@@ -94,11 +88,7 @@ public class UncheckedBufferedReader extends BufferedReader {
*/
@Override
public int read() throws UncheckedIOException {
- try {
- return super.read();
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.get(super::read);
}
/**
@@ -106,11 +96,7 @@ public class UncheckedBufferedReader extends BufferedReader
{
*/
@Override
public int read(final char[] cbuf) throws UncheckedIOException {
- try {
- return super.read(cbuf);
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.apply(super::read, cbuf);
}
/**
@@ -118,11 +104,7 @@ public class UncheckedBufferedReader extends
BufferedReader {
*/
@Override
public int read(final char[] cbuf, final int off, final int len) throws
UncheckedIOException {
- try {
- return super.read(cbuf, off, len);
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.apply(super::read, cbuf, off, len);
}
/**
@@ -130,11 +112,7 @@ public class UncheckedBufferedReader extends
BufferedReader {
*/
@Override
public int read(final CharBuffer target) throws UncheckedIOException {
- try {
- return super.read(target);
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.apply(super::read, target);
}
/**
@@ -142,11 +120,7 @@ public class UncheckedBufferedReader extends
BufferedReader {
*/
@Override
public String readLine() throws UncheckedIOException {
- try {
- return super.readLine();
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.get(super::readLine);
}
/**
@@ -154,11 +128,7 @@ public class UncheckedBufferedReader extends
BufferedReader {
*/
@Override
public boolean ready() throws UncheckedIOException {
- try {
- return super.ready();
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.get(super::ready);
}
/**
@@ -166,11 +136,7 @@ public class UncheckedBufferedReader extends
BufferedReader {
*/
@Override
public void reset() throws UncheckedIOException {
- try {
- super.reset();
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ UncheckedIO.run(super::reset);
}
/**
@@ -178,15 +144,7 @@ public class UncheckedBufferedReader extends
BufferedReader {
*/
@Override
public long skip(final long n) throws UncheckedIOException {
- try {
- return super.skip(n);
- } catch (final IOException e) {
- throw uncheck(e);
- }
- }
-
- private UncheckedIOException uncheck(final IOException e) {
- return new UncheckedIOException(e);
+ return UncheckedIO.apply(super::skip, n);
}
}
diff --git
a/src/main/java/org/apache/commons/io/input/UncheckedFilterInputStream.java
b/src/main/java/org/apache/commons/io/input/UncheckedFilterInputStream.java
index 85f3d6c0..9f0fccfa 100644
--- a/src/main/java/org/apache/commons/io/input/UncheckedFilterInputStream.java
+++ b/src/main/java/org/apache/commons/io/input/UncheckedFilterInputStream.java
@@ -24,6 +24,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
+import org.apache.commons.io.UncheckedIO;
+
/**
* A {@link BufferedReader} that throws {@link UncheckedIOException} instead
of {@link IOException}.
*
@@ -60,11 +62,7 @@ public class UncheckedFilterInputStream extends
FilterInputStream {
*/
@Override
public int available() throws UncheckedIOException {
- try {
- return super.available();
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.get(super::available);
}
/**
@@ -72,11 +70,7 @@ public class UncheckedFilterInputStream extends
FilterInputStream {
*/
@Override
public void close() throws UncheckedIOException {
- try {
- super.close();
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ UncheckedIO.run(super::close);
}
/**
@@ -84,11 +78,7 @@ public class UncheckedFilterInputStream extends
FilterInputStream {
*/
@Override
public int read() throws UncheckedIOException {
- try {
- return super.read();
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.get(super::read);
}
/**
@@ -96,11 +86,7 @@ public class UncheckedFilterInputStream extends
FilterInputStream {
*/
@Override
public int read(final byte[] b) throws UncheckedIOException {
- try {
- return super.read(b);
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.apply(super::read, b);
}
/**
@@ -108,11 +94,7 @@ public class UncheckedFilterInputStream extends
FilterInputStream {
*/
@Override
public int read(final byte[] b, final int off, final int len) throws
UncheckedIOException {
- try {
- return super.read(b, off, len);
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.apply(super::read, b, off, len);
}
/**
@@ -120,11 +102,7 @@ public class UncheckedFilterInputStream extends
FilterInputStream {
*/
@Override
public synchronized void reset() throws UncheckedIOException {
- try {
- super.reset();
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ UncheckedIO.run(super::reset);
}
/**
@@ -132,15 +110,7 @@ public class UncheckedFilterInputStream extends
FilterInputStream {
*/
@Override
public long skip(final long n) throws UncheckedIOException {
- try {
- return super.skip(n);
- } catch (final IOException e) {
- throw uncheck(e);
- }
- }
-
- private UncheckedIOException uncheck(final IOException e) {
- return new UncheckedIOException(e);
+ return UncheckedIO.apply(super::skip, n);
}
}
diff --git
a/src/main/java/org/apache/commons/io/input/UncheckedFilterReader.java
b/src/main/java/org/apache/commons/io/input/UncheckedFilterReader.java
index 285bc94d..f0a68a12 100644
--- a/src/main/java/org/apache/commons/io/input/UncheckedFilterReader.java
+++ b/src/main/java/org/apache/commons/io/input/UncheckedFilterReader.java
@@ -23,6 +23,8 @@ import java.io.Reader;
import java.io.UncheckedIOException;
import java.nio.CharBuffer;
+import org.apache.commons.io.UncheckedIO;
+
/**
* A {@link FilterReader} that throws {@link UncheckedIOException} instead of
{@link IOException}.
*
@@ -59,11 +61,7 @@ public class UncheckedFilterReader extends FilterReader {
*/
@Override
public void close() throws UncheckedIOException {
- try {
- super.close();
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ UncheckedIO.run(super::close);
}
/**
@@ -71,11 +69,7 @@ public class UncheckedFilterReader extends FilterReader {
*/
@Override
public void mark(final int readAheadLimit) throws UncheckedIOException {
- try {
- super.mark(readAheadLimit);
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ UncheckedIO.accept(super::mark, readAheadLimit);
}
/**
@@ -83,11 +77,7 @@ public class UncheckedFilterReader extends FilterReader {
*/
@Override
public int read() throws UncheckedIOException {
- try {
- return super.read();
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.get(super::read);
}
/**
@@ -95,11 +85,7 @@ public class UncheckedFilterReader extends FilterReader {
*/
@Override
public int read(final char[] cbuf) throws UncheckedIOException {
- try {
- return super.read(cbuf);
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.apply(super::read, cbuf);
}
/**
@@ -107,11 +93,7 @@ public class UncheckedFilterReader extends FilterReader {
*/
@Override
public int read(final char[] cbuf, final int off, final int len) throws
UncheckedIOException {
- try {
- return super.read(cbuf, off, len);
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.apply(super::read, cbuf, off, len);
}
/**
@@ -119,11 +101,7 @@ public class UncheckedFilterReader extends FilterReader {
*/
@Override
public int read(final CharBuffer target) throws UncheckedIOException {
- try {
- return super.read(target);
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.apply(super::read, target);
}
/**
@@ -131,11 +109,7 @@ public class UncheckedFilterReader extends FilterReader {
*/
@Override
public boolean ready() throws UncheckedIOException {
- try {
- return super.ready();
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ return UncheckedIO.get(super::ready);
}
/**
@@ -143,11 +117,7 @@ public class UncheckedFilterReader extends FilterReader {
*/
@Override
public void reset() throws UncheckedIOException {
- try {
- super.reset();
- } catch (final IOException e) {
- throw uncheck(e);
- }
+ UncheckedIO.run(super::reset);
}
/**
@@ -155,15 +125,7 @@ public class UncheckedFilterReader extends FilterReader {
*/
@Override
public long skip(final long n) throws UncheckedIOException {
- try {
- return super.skip(n);
- } catch (final IOException e) {
- throw uncheck(e);
- }
- }
-
- private UncheckedIOException uncheck(final IOException e) {
- return new UncheckedIOException(e);
+ return UncheckedIO.apply(super::skip, n);
}
}
diff --git
a/src/main/java/org/apache/commons/io/output/UncheckedAppendableImpl.java
b/src/main/java/org/apache/commons/io/output/UncheckedAppendableImpl.java
index 8776fb34..48aa3e00 100644
--- a/src/main/java/org/apache/commons/io/output/UncheckedAppendableImpl.java
+++ b/src/main/java/org/apache/commons/io/output/UncheckedAppendableImpl.java
@@ -21,7 +21,7 @@ import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Objects;
-import org.apache.commons.io.UncheckedIOExceptions;
+import org.apache.commons.io.UncheckedIO;
/**
* An {@link Appendable} implementation that throws {@link
UncheckedIOException} instead of {@link IOException}.
@@ -41,31 +41,19 @@ class UncheckedAppendableImpl implements
UncheckedAppendable {
@Override
public UncheckedAppendable append(final char c) {
- try {
- appendable.append(c);
- } catch (final IOException e) {
- throw UncheckedIOExceptions.create(c, e);
- }
+ UncheckedIO.apply(appendable::append, c);
return this;
}
@Override
public UncheckedAppendable append(final CharSequence csq) {
- try {
- appendable.append(csq);
- } catch (final IOException e) {
- throw UncheckedIOExceptions.create(csq, e);
- }
+ UncheckedIO.apply(appendable::append, csq);
return this;
}
@Override
public UncheckedAppendable append(final CharSequence csq, final int start,
final int end) {
- try {
- appendable.append(csq, start, end);
- } catch (final IOException e) {
- throw UncheckedIOExceptions.create(csq, e);
- }
+ UncheckedIO.apply(appendable::append, csq, start, end);
return this;
}
@@ -74,4 +62,4 @@ class UncheckedAppendableImpl implements UncheckedAppendable {
return appendable.toString();
}
-}
\ No newline at end of file
+}
diff --git a/src/test/java/org/apache/commons/io/UncheckedIOExceptionsTest.java
b/src/test/java/org/apache/commons/io/UncheckedIOExceptionsTest.java
index 09c393c2..160d38ea 100644
--- a/src/test/java/org/apache/commons/io/UncheckedIOExceptionsTest.java
+++ b/src/test/java/org/apache/commons/io/UncheckedIOExceptionsTest.java
@@ -24,8 +24,14 @@ import java.io.UncheckedIOException;
import org.junit.jupiter.api.Test;
+/**
+ * Tests {@link UncheckedIO}.
+ */
public class UncheckedIOExceptionsTest {
+ /**
+ * Tests {@link UncheckedIOExceptions#create(Object)}.
+ */
@Test
public void testCreate() {
final Object message = "test";
@@ -35,20 +41,20 @@ public class UncheckedIOExceptionsTest {
assertEquals(message, e.getMessage());
assertEquals(message, e.getCause().getMessage());
}
-
}
+ /**
+ * Tests {@link UncheckedIOExceptions#wrap(IOException, Object)}.
+ */
@Test
- public void testCreateWithException() {
+ public void testWrap() {
final Object message1 = "test1";
final Object message2 = "test2";
- final IOException ioe = new IOException(message2.toString());
try {
- throw UncheckedIOExceptions.create(message1, ioe);
+ throw UncheckedIOExceptions.wrap(new
IOException(message2.toString()), message1);
} catch (final UncheckedIOException e) {
assertEquals(message1, e.getMessage());
assertEquals(message2, e.getCause().getMessage());
}
-
}
}
diff --git a/src/test/java/org/apache/commons/io/UncheckedIOTest.java
b/src/test/java/org/apache/commons/io/UncheckedIOTest.java
new file mode 100644
index 00000000..6628d83d
--- /dev/null
+++ b/src/test/java/org/apache/commons/io/UncheckedIOTest.java
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.io;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.ByteArrayInputStream;
+
+import org.apache.commons.io.function.IOBiFunction;
+import org.apache.commons.io.function.IOConsumer;
+import org.apache.commons.io.function.IOFunction;
+import org.apache.commons.io.function.IORunnable;
+import org.apache.commons.io.function.IOSupplier;
+import org.apache.commons.io.function.IOTriFunction;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link UncheckedIO}.
+ */
+public class UncheckedIOTest {
+
+ private static final byte[] BYTES = {'a', 'b'};
+
+ private ByteArrayInputStream newInputStream() {
+ return new ByteArrayInputStream(BYTES);
+ }
+
+ /**
+ * Tests {@link UncheckedIO#accept(IOConsumer, Object)}.
+ */
+ @Test
+ public void testAccept() {
+ final ByteArrayInputStream stream = newInputStream();
+ UncheckedIO.accept(n -> stream.skip(n), 1);
+ assertEquals('b', UncheckedIO.get(stream::read).intValue());
+ }
+
+ /**
+ * Tests {@link UncheckedIO#apply(IOFunction, Object)}.
+ */
+ @Test
+ public void testApply1() {
+ final ByteArrayInputStream stream = newInputStream();
+ assertEquals(1, UncheckedIO.apply(n -> stream.skip(n), 1).intValue());
+ assertEquals('b', UncheckedIO.get(stream::read).intValue());
+ }
+
+ /**
+ * Tests {@link UncheckedIO#apply(IOBiFunction, Object, Object)}.
+ */
+ @Test
+ public void testApply2() {
+ final ByteArrayInputStream stream = newInputStream();
+ final byte[] buf = new byte[BYTES.length];
+ assertEquals(1, UncheckedIO.apply((o, l) -> stream.read(buf, o, l), 0,
1).intValue());
+ assertEquals('a', buf[0]);
+ }
+
+ /**
+ * Tests {@link UncheckedIO#apply(IOTriFunction, Object, Object, Object)}.
+ */
+ @Test
+ public void testApply3() {
+ final ByteArrayInputStream stream = newInputStream();
+ final byte[] buf = new byte[BYTES.length];
+ assertEquals(1, UncheckedIO.apply((b, o, l) -> stream.read(b, o, l),
buf, 0, 1).intValue());
+ assertEquals('a', buf[0]);
+ }
+
+ /**
+ * Tests {@link UncheckedIO#get(IOSupplier)}.
+ */
+ @Test
+ public void testGet() {
+ assertEquals('a', UncheckedIO.get(() ->
newInputStream().read()).intValue());
+ }
+
+ /**
+ * Tests {@link UncheckedIO#run(IORunnable)}.
+ */
+ @Test
+ public void testRun() {
+ final ByteArrayInputStream stream = newInputStream();
+ UncheckedIO.run(() -> stream.skip(1));
+ assertEquals('b', UncheckedIO.get(stream::read).intValue());
+ }
+}
diff --git a/src/test/java/org/apache/commons/io/function/IOBiFunctionTest.java
b/src/test/java/org/apache/commons/io/function/IOBiFunctionTest.java
new file mode 100644
index 00000000..ac75d502
--- /dev/null
+++ b/src/test/java/org/apache/commons/io/function/IOBiFunctionTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.io.function;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.util.function.Function;
+
+import org.apache.commons.io.file.PathUtils;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link IOBiFunction}.
+ */
+public class IOBiFunctionTest {
+
+ @SuppressWarnings("unused")
+ private boolean not(final boolean value) throws IOException {
+ return !value;
+ }
+
+ /**
+ * Tests {@link IOBiFunction#andThen(Function)}.
+ *
+ * @throws IOException thrown on test failure
+ */
+ @Test
+ public void testAndThenFunction() throws IOException {
+ final IOBiFunction<Path, LinkOption[], Boolean> isDirectory =
Files::isDirectory;
+ final Function<Boolean, Boolean> not = b -> !b;
+ assertEquals(true, isDirectory.apply(PathUtils.current(),
PathUtils.EMPTY_LINK_OPTION_ARRAY));
+ final IOBiFunction<Path, LinkOption[], Boolean> andThen =
isDirectory.andThen(not);
+ assertEquals(false, andThen.apply(PathUtils.current(),
PathUtils.EMPTY_LINK_OPTION_ARRAY));
+ }
+
+ /**
+ * Tests {@link IOBiFunction#andThen(IOFunction)}.
+ *
+ * @throws IOException thrown on test failure
+ */
+ @Test
+ public void testAndThenIOFunction() throws IOException {
+ final IOBiFunction<Path, LinkOption[], Boolean> isDirectory =
Files::isDirectory;
+ final IOFunction<Boolean, Boolean> not = this::not;
+ assertEquals(true, isDirectory.apply(PathUtils.current(),
PathUtils.EMPTY_LINK_OPTION_ARRAY));
+ final IOBiFunction<Path, LinkOption[], Boolean> andThen =
isDirectory.andThen(not);
+ assertEquals(false, andThen.apply(PathUtils.current(),
PathUtils.EMPTY_LINK_OPTION_ARRAY));
+ }
+
+ /**
+ * Tests {@link IOBiFunction#apply(Object, Object)}.
+ *
+ * @throws IOException thrown on test failure
+ */
+ @Test
+ public void testApply() throws IOException {
+ final IOBiFunction<Path, LinkOption[], Boolean> isDirectory =
Files::isDirectory;
+ assertEquals(true, isDirectory.apply(PathUtils.current(),
PathUtils.EMPTY_LINK_OPTION_ARRAY));
+ }
+
+ /**
+ * Tests {@link IOBiFunction#apply(Object, Object)}.
+ */
+ @Test
+ public void testApplyThrowsException() {
+ final IOBiFunction<Path, LinkOption[], Boolean> isDirectory = (t, u)
-> {
+ throw new IOException("Boom!");
+ };
+ assertThrows(IOException.class, () ->
isDirectory.apply(PathUtils.current(), PathUtils.EMPTY_LINK_OPTION_ARRAY));
+ }
+
+}
diff --git a/src/test/java/org/apache/commons/io/UncheckedIOExceptionsTest.java
b/src/test/java/org/apache/commons/io/function/IORunnableTest.java
similarity index 51%
copy from src/test/java/org/apache/commons/io/UncheckedIOExceptionsTest.java
copy to src/test/java/org/apache/commons/io/function/IORunnableTest.java
index 09c393c2..2a77d6ea 100644
--- a/src/test/java/org/apache/commons/io/UncheckedIOExceptionsTest.java
+++ b/src/test/java/org/apache/commons/io/function/IORunnableTest.java
@@ -15,40 +15,31 @@
* limitations under the License.
*/
-package org.apache.commons.io;
+package org.apache.commons.io.function;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.IOException;
-import java.io.UncheckedIOException;
+import java.util.concurrent.atomic.AtomicReference;
import org.junit.jupiter.api.Test;
-public class UncheckedIOExceptionsTest {
+/**
+ * Tests {@link IORunnable}.
+ */
+public class IORunnableTest {
+ /**
+ * Tests {@link IORunnable#run()}.
+ *
+ * @throws IOException thrown on test failure
+ */
@Test
- public void testCreate() {
- final Object message = "test";
- try {
- throw UncheckedIOExceptions.create(message);
- } catch (final UncheckedIOException e) {
- assertEquals(message, e.getMessage());
- assertEquals(message, e.getCause().getMessage());
- }
-
+ public void testAccept() throws IOException {
+ final AtomicReference<String> ref = new AtomicReference<>();
+ final IORunnable runnable = () -> ref.set("A1");
+ runnable.run();
+ assertEquals("A1", ref.get());
}
- @Test
- public void testCreateWithException() {
- final Object message1 = "test1";
- final Object message2 = "test2";
- final IOException ioe = new IOException(message2.toString());
- try {
- throw UncheckedIOExceptions.create(message1, ioe);
- } catch (final UncheckedIOException e) {
- assertEquals(message1, e.getMessage());
- assertEquals(message2, e.getCause().getMessage());
- }
-
- }
}
diff --git
a/src/test/java/org/apache/commons/io/function/IOTriFunctionTest.java
b/src/test/java/org/apache/commons/io/function/IOTriFunctionTest.java
new file mode 100644
index 00000000..9f5ce36e
--- /dev/null
+++ b/src/test/java/org/apache/commons/io/function/IOTriFunctionTest.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.io.function;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.io.IOException;
+import java.math.BigInteger;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Function;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link IOTriFunction}.
+ */
+public class IOTriFunctionTest {
+
+ /**
+ * Tests {@link IOTriFunction#apply(Object, Object, Object)}.
+ *
+ * @throws IOException thrown on test failure
+ */
+ @Test
+ public void testAccept() throws IOException {
+ final AtomicReference<Character> ref1 = new AtomicReference<>();
+ final AtomicReference<Short> ref2 = new AtomicReference<>();
+ final AtomicReference<String> ref3 = new AtomicReference<>();
+ final IOTriFunction<AtomicReference<Character>,
AtomicReference<Short>, AtomicReference<String>, String> tri = (t, u, v) -> {
+ ref1.set(Character.valueOf('a'));
+ ref2.set(Short.valueOf((short) 1));
+ ref3.set("z");
+ return "ABC";
+ };
+ assertEquals("ABC", tri.apply(ref1, ref2, ref3));
+ assertEquals(Character.valueOf('a'), ref1.get());
+ assertEquals(Short.valueOf((short) 1), ref2.get());
+ assertEquals("z", ref3.get());
+ }
+
+ /**
+ * Tests {@link IOTriFunction#andThen(Function)}.
+ *
+ * @throws IOException thrown on test failure
+ */
+ @Test
+ public void testAndThenFunction() throws IOException {
+ final AtomicReference<Character> ref1 = new AtomicReference<>();
+ final AtomicReference<Short> ref2 = new AtomicReference<>();
+ final AtomicReference<String> ref3 = new AtomicReference<>();
+ final IOTriFunction<AtomicReference<Character>,
AtomicReference<Short>, AtomicReference<String>, String> tri = (t, u, v) -> {
+ ref1.set(Character.valueOf('a'));
+ ref2.set(Short.valueOf((short) 1));
+ ref3.set("z");
+ return "9";
+ };
+ final Function<String, BigInteger> after = t -> {
+ ref1.set(Character.valueOf('b'));
+ ref2.set(Short.valueOf((short) 2));
+ ref3.set("zz");
+ return BigInteger.valueOf(Long.parseLong(t)).add(BigInteger.ONE);
+ };
+ assertEquals(BigInteger.TEN, tri.andThen(after).apply(ref1, ref2,
ref3));
+ assertEquals(Character.valueOf('b'), ref1.get());
+ assertEquals(Short.valueOf((short) 2), ref2.get());
+ assertEquals("zz", ref3.get());
+ }
+
+ /**
+ * Tests {@link IOTriFunction#andThen(IOFunction)}.
+ *
+ * @throws IOException thrown on test failure
+ */
+ @Test
+ public void testAndThenIOFunction() throws IOException {
+ final AtomicReference<Character> ref1 = new AtomicReference<>();
+ final AtomicReference<Short> ref2 = new AtomicReference<>();
+ final AtomicReference<String> ref3 = new AtomicReference<>();
+ final IOTriFunction<AtomicReference<Character>,
AtomicReference<Short>, AtomicReference<String>, String> tri = (t, u, v) -> {
+ ref1.set(Character.valueOf('a'));
+ ref2.set(Short.valueOf((short) 1));
+ ref3.set("z");
+ return "9";
+ };
+ final IOFunction<String, BigInteger> after = t -> {
+ ref1.set(Character.valueOf('b'));
+ ref2.set(Short.valueOf((short) 2));
+ ref3.set("zz");
+ return BigInteger.valueOf(Long.parseLong(t)).add(BigInteger.ONE);
+ };
+ assertEquals(BigInteger.TEN, tri.andThen(after).apply(ref1, ref2,
ref3));
+ assertEquals(Character.valueOf('b'), ref1.get());
+ assertEquals(Short.valueOf((short) 2), ref2.get());
+ assertEquals("zz", ref3.get());
+ }
+
+}