diff --git a/src/main/java/org/apache/commons/lang3/function/FailableBiFunction.java b/src/main/java/org/apache/commons/lang3/function/FailableBiFunction.java index be0e4704b..3173c73b7 100644 --- a/src/main/java/org/apache/commons/lang3/function/FailableBiFunction.java +++ b/src/main/java/org/apache/commons/lang3/function/FailableBiFunction.java @@ -57,7 +57,7 @@ public interface FailableBiFunction { * @param after the operation to perform after this one. * @return a composed {@code FailableBiFunction} that like {@link BiFunction#andThen(Function)}. * @throws E Thrown when a consumer fails. - * @throws NullPointerException if after is null. + * @throws NullPointerException if {@code after} is null. */ default FailableBiFunction andThen(final FailableFunction after) throws E { Objects.requireNonNull(after); diff --git a/src/main/java/org/apache/commons/lang3/function/FailableConsumer.java b/src/main/java/org/apache/commons/lang3/function/FailableConsumer.java index acb73cc51..c2f2de8a9 100644 --- a/src/main/java/org/apache/commons/lang3/function/FailableConsumer.java +++ b/src/main/java/org/apache/commons/lang3/function/FailableConsumer.java @@ -17,17 +17,33 @@ package org.apache.commons.lang3.function; +import java.util.Objects; import java.util.function.Consumer; /** * A functional interface like {@link Consumer} that declares a {@code Throwable}. * - * @param Consumed type 1. + * @param Consumed type 1. * @param Thrown exception. * @since 3.11 */ @FunctionalInterface -public interface FailableConsumer { +public interface FailableConsumer { + + /** NOP singleton */ + @SuppressWarnings("rawtypes") + final FailableConsumer NOP = t -> {/* NOP */}; + + /** + * Returns The NOP singleton. + * + * @param Consumed type 1. + * @param Thrown exception. + * @return The NOP singleton. + */ + static FailableConsumer nop() { + return NOP; + } /** * Accepts the consumer. @@ -35,5 +51,21 @@ public interface FailableConsumer { * @param object the parameter for the consumable to accept * @throws E Thrown when the consumer fails. */ - void accept(O object) throws E; + void accept(T object) throws E; + + /** + * Returns a composed {@code Consumer} like {@link Consumer#andThen(Consumer)}. + * + * @param after the operation to perform after this operation + * @return a composed {@code Consumer} like {@link Consumer#andThen(Consumer)}. + * @throws E Thrown when a consumer fails. + * @throws NullPointerException if {@code after} is null + */ + default FailableConsumer andThen(final FailableConsumer after) throws E { + Objects.requireNonNull(after); + return (final T t) -> { + accept(t); + after.accept(t); + }; + } } diff --git a/src/test/java/org/apache/commons/lang3/function/FailableFunctionsTest.java b/src/test/java/org/apache/commons/lang3/function/FailableFunctionsTest.java index 81da56e11..24a1054cd 100644 --- a/src/test/java/org/apache/commons/lang3/function/FailableFunctionsTest.java +++ b/src/test/java/org/apache/commons/lang3/function/FailableFunctionsTest.java @@ -269,7 +269,7 @@ public class FailableFunctionsTest { private static final IllegalStateException ILLEGAL_STATE_EXCEPTION = new IllegalStateException(); @Test - void testAcceptBiConsumer() { + public void testAcceptBiConsumer() { final Testable testable = new Testable<>(null); Throwable e = assertThrows(IllegalStateException.class, () -> Failable.accept(Testable::test, testable, ILLEGAL_STATE_EXCEPTION)); @@ -290,7 +290,7 @@ public class FailableFunctionsTest { } @Test - void testAcceptConsumer() { + public void testAcceptConsumer() { final Testable testable = new Testable<>(ILLEGAL_STATE_EXCEPTION); Throwable e = assertThrows(IllegalStateException.class, () -> Failable.accept(Testable::test, testable)); assertSame(ILLEGAL_STATE_EXCEPTION, e); @@ -311,7 +311,7 @@ public class FailableFunctionsTest { } @Test - void testAcceptDoubleConsumer() { + public void testAcceptDoubleConsumer() { final Testable testable = new Testable<>(ILLEGAL_STATE_EXCEPTION); Throwable e = assertThrows(IllegalStateException.class, () -> Failable.accept(testable::testDouble, 1d)); assertSame(ILLEGAL_STATE_EXCEPTION, e); @@ -336,7 +336,7 @@ public class FailableFunctionsTest { } @Test - void testAcceptIntConsumer() { + public void testAcceptIntConsumer() { final Testable testable = new Testable<>(ILLEGAL_STATE_EXCEPTION); Throwable e = assertThrows(IllegalStateException.class, () -> Failable.accept(testable::testInt, 1)); assertSame(ILLEGAL_STATE_EXCEPTION, e); @@ -361,7 +361,7 @@ public class FailableFunctionsTest { } @Test - void testAcceptLongConsumer() { + public void testAcceptLongConsumer() { final Testable testable = new Testable<>(ILLEGAL_STATE_EXCEPTION); Throwable e = assertThrows(IllegalStateException.class, () -> Failable.accept(testable::testLong, 1L)); assertSame(ILLEGAL_STATE_EXCEPTION, e); @@ -386,7 +386,7 @@ public class FailableFunctionsTest { } @Test - void testAcceptObjDoubleConsumer() { + public void testAcceptObjDoubleConsumer() { final Testable testable = new Testable<>(ILLEGAL_STATE_EXCEPTION); Throwable e = assertThrows(IllegalStateException.class, () -> Failable.accept(testable::testObjDouble, "X", 1d)); @@ -416,7 +416,7 @@ public class FailableFunctionsTest { } @Test - void testAcceptObjIntConsumer() { + public void testAcceptObjIntConsumer() { final Testable testable = new Testable<>(ILLEGAL_STATE_EXCEPTION); Throwable e = assertThrows(IllegalStateException.class, () -> Failable.accept(testable::testObjInt, "X", 1)); assertSame(ILLEGAL_STATE_EXCEPTION, e); @@ -445,7 +445,7 @@ public class FailableFunctionsTest { } @Test - void testAcceptObjLongConsumer() { + public void testAcceptObjLongConsumer() { final Testable testable = new Testable<>(ILLEGAL_STATE_EXCEPTION); Throwable e = assertThrows(IllegalStateException.class, () -> Failable.accept(testable::testObjLong, "X", 1L)); assertSame(ILLEGAL_STATE_EXCEPTION, e); @@ -531,7 +531,7 @@ public class FailableFunctionsTest { } @Test - void testAsCallable() { + public void testAsCallable() { FailureOnOddInvocations.invocations = 0; final FailableCallable failableCallable = FailureOnOddInvocations::new; final Callable callable = Failable.asCallable(failableCallable); @@ -550,7 +550,7 @@ public class FailableFunctionsTest { } @Test - void testAsConsumer() { + public void testAsConsumer() { final Testable testable = new Testable<>(ILLEGAL_STATE_EXCEPTION); final Consumer> consumer = Failable.asConsumer(Testable::test); Throwable e = assertThrows(IllegalStateException.class, () -> consumer.accept(testable)); @@ -572,7 +572,7 @@ public class FailableFunctionsTest { } @Test - void testAsRunnable() { + public void testAsRunnable() { FailureOnOddInvocations.invocations = 0; final Runnable runnable = Failable.asRunnable(FailureOnOddInvocations::new); final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, runnable::run); @@ -599,7 +599,7 @@ public class FailableFunctionsTest { } @Test - void testBiConsumer() throws Throwable { + public void testBiConsumer() throws Throwable { final Testable testable = new Testable<>(null); final FailableBiConsumer, Throwable, Throwable> failableBiConsumer = (t, th) -> { t.setThrowable(th); @@ -627,7 +627,7 @@ public class FailableFunctionsTest { } @Test - void testBiConsumerAndThen() throws Throwable { + public void testBiConsumerAndThen() throws Throwable { final Testable testable = new Testable<>(null); final FailableBiConsumer, Throwable, Throwable> failableBiConsumer = (t, th) -> { t.setThrowable(th); @@ -710,7 +710,7 @@ public class FailableFunctionsTest { } @Test - void testCallable() { + public void testCallable() { FailureOnOddInvocations.invocations = 0; final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, () -> Failable.run(FailureOnOddInvocations::new)); @@ -729,6 +729,23 @@ public class FailableFunctionsTest { new Functions(); } + @Test + public void testConsumerAndThen() throws Throwable { + final Testable testable = new Testable<>(null); + final FailableConsumer failableConsumer = (th) -> { + testable.setThrowable(th); + testable.test(); + }; + final FailableConsumer nop = FailableConsumer.nop(); + final Throwable e = assertThrows(OutOfMemoryError.class, + () -> nop.andThen(failableConsumer).accept(ERROR)); + assertSame(ERROR, e); + // Does not throw + nop.andThen(nop); + // Documented in Javadoc edge-case. + assertThrows(NullPointerException.class, () -> failableConsumer.andThen(null)); + } + @Test public void testDoublePredicate() throws Throwable { FailureOnOddInvocations.invocations = 0; @@ -920,7 +937,7 @@ public class FailableFunctionsTest { } @Test - void testRunnable() { + public void testRunnable() { FailureOnOddInvocations.invocations = 0; final UndeclaredThrowableException e = assertThrows(UndeclaredThrowableException.class, () -> Failable.run(FailureOnOddInvocations::new)); @@ -938,7 +955,7 @@ public class FailableFunctionsTest { * Object and Throwable. */ @Test - void testThrows_FailableBiConsumer_Object_Throwable() { + public void testThrows_FailableBiConsumer_Object_Throwable() { new FailableBiConsumer() { @Override @@ -953,7 +970,7 @@ public class FailableFunctionsTest { * generic test types. */ @Test - void testThrows_FailableBiConsumer_String_IOException() { + public void testThrows_FailableBiConsumer_String_IOException() { new FailableBiConsumer() { @Override @@ -969,7 +986,7 @@ public class FailableFunctionsTest { * Object and Throwable. */ @Test - void testThrows_FailableBiFunction_Object_Throwable() { + public void testThrows_FailableBiFunction_Object_Throwable() { new FailableBiFunction() { @Override @@ -984,7 +1001,7 @@ public class FailableFunctionsTest { * generic test types. */ @Test - void testThrows_FailableBiFunction_String_IOException() { + public void testThrows_FailableBiFunction_String_IOException() { new FailableBiFunction() { @Override @@ -999,7 +1016,7 @@ public class FailableFunctionsTest { * Object and Throwable. */ @Test - void testThrows_FailableBiPredicate_Object_Throwable() { + public void testThrows_FailableBiPredicate_Object_Throwable() { new FailableBiPredicate() { @Override @@ -1014,7 +1031,7 @@ public class FailableFunctionsTest { * generic test types. */ @Test - void testThrows_FailableBiPredicate_String_IOException() { + public void testThrows_FailableBiPredicate_String_IOException() { new FailableBiPredicate() { @Override @@ -1061,7 +1078,7 @@ public class FailableFunctionsTest { * Object and Throwable. */ @Test - void testThrows_FailableCallable_Object_Throwable() { + public void testThrows_FailableCallable_Object_Throwable() { new FailableCallable() { @Override @@ -1076,7 +1093,7 @@ public class FailableFunctionsTest { * generic test types. */ @Test - void testThrows_FailableCallable_String_IOException() { + public void testThrows_FailableCallable_String_IOException() { new FailableCallable() { @Override @@ -1091,7 +1108,7 @@ public class FailableFunctionsTest { * Object and Throwable. */ @Test - void testThrows_FailableConsumer_Object_Throwable() { + public void testThrows_FailableConsumer_Object_Throwable() { new FailableConsumer() { @Override @@ -1107,7 +1124,7 @@ public class FailableFunctionsTest { * generic test types. */ @Test - void testThrows_FailableConsumer_String_IOException() { + public void testThrows_FailableConsumer_String_IOException() { new FailableConsumer() { @Override