This is an automated email from the ASF dual-hosted git repository.

garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git


The following commit(s) were added to refs/heads/master by this push:
     new eb202b0b9 Add FailableConsumer.accept(FailableConsumer<T, E>, T) 
(#1641)
eb202b0b9 is described below

commit eb202b0b905ac3bbea742f1aad426f5a6c7d604d
Author: Gary Gregory <[email protected]>
AuthorDate: Sat May 9 12:48:19 2026 -0400

    Add FailableConsumer.accept(FailableConsumer<T, E>, T) (#1641)
    
    Add missing test class
---
 .../commons/lang3/function/FailableConsumer.java   |  24 +++-
 .../lang3/function/FailableConsumerTest.java       | 129 +++++++++++++++++++++
 2 files changed, 149 insertions(+), 4 deletions(-)

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 b66431428..6a9df5f64 100644
--- a/src/main/java/org/apache/commons/lang3/function/FailableConsumer.java
+++ b/src/main/java/org/apache/commons/lang3/function/FailableConsumer.java
@@ -28,8 +28,8 @@
  * This is a functional interface whose functional method is {@link 
#accept(Object)}.
  * </p>
  *
- * @param <T> the type of the input to the operation
- * @param <E> Thrown exception type.
+ * @param <T> the type of the argument the consumer accepts.
+ * @param <E> The thrown exception type.
  * @since 3.11
  */
 @FunctionalInterface
@@ -39,11 +39,27 @@ public interface FailableConsumer<T, E extends Throwable> {
     @SuppressWarnings("rawtypes")
     FailableConsumer NOP = Function.identity()::apply;
 
+    /**
+     * Applies the given {@link FailableConsumer} action to the object if the 
consumer is not {@code null}. Otherwise, does nothing.
+     *
+     * @param consumer the consumer to consume.
+     * @param object   the object to be consumed.
+     * @param <T>      the type of the argument the consumer accepts.
+     * @param <E>      The thrown exception type.
+     * @throws E Thrown when the consumer fails.
+     * @since 3.21.0
+     */
+    static <T, E extends Throwable> void accept(final FailableConsumer<T, E> 
consumer, final T object) throws E {
+        if (consumer != null) {
+            consumer.accept(object);
+        }
+    }
+
     /**
      * Gets the NOP singleton.
      *
-     * @param <T> Consumed type 1.
-     * @param <E> The kind of thrown exception or error.
+     * @param <T> the type of the argument the consumer accepts.
+     * @param <E> The thrown exception type.
      * @return The NOP singleton.
      */
     @SuppressWarnings("unchecked")
diff --git 
a/src/test/java/org/apache/commons/lang3/function/FailableConsumerTest.java 
b/src/test/java/org/apache/commons/lang3/function/FailableConsumerTest.java
new file mode 100644
index 000000000..07c2be174
--- /dev/null
+++ b/src/test/java/org/apache/commons/lang3/function/FailableConsumerTest.java
@@ -0,0 +1,129 @@
+/*
+ * 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
+ *
+ *      https://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.lang3.function;
+
+import static 
org.apache.commons.lang3.LangAssertions.assertNullPointerException;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.io.IOException;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.commons.lang3.AbstractLangTest;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link FailableConsumer}.
+ */
+class FailableConsumerTest extends AbstractLangTest {
+
+    @Test
+    void testAccept_invokesConsumer() throws IOException {
+        final AtomicReference<String> ref = new AtomicReference<>();
+        final FailableConsumer<String, IOException> consumer = ref::set;
+        consumer.accept("world");
+        assertEquals("world", ref.get());
+    }
+
+    @Test
+    void testAccept_throwsCheckedExceptionOnFailure() {
+        final IOException expected = new IOException("fail");
+        final FailableConsumer<String, IOException> consumer = s -> {
+            throw expected;
+        };
+        final IOException thrown = assertThrows(IOException.class, () -> 
consumer.accept("x"));
+        assertEquals(expected, thrown);
+    }
+
+    @Test
+    void testAndThen_bothInvoked() throws IOException {
+        final AtomicReference<String> ref1 = new AtomicReference<>();
+        final AtomicReference<String> ref2 = new AtomicReference<>();
+        final FailableConsumer<String, IOException> first = ref1::set;
+        final FailableConsumer<String, IOException> second = ref2::set;
+        first.andThen(second).accept("value");
+        assertEquals("value", ref1.get());
+        assertEquals("value", ref2.get());
+    }
+
+    @Test
+    void testAndThen_firstThrows_secondNotInvoked() {
+        final IOException expected = new IOException("first");
+        final AtomicReference<String> ref = new AtomicReference<>();
+        final FailableConsumer<String, IOException> throwing = s -> {
+            throw expected;
+        };
+        final FailableConsumer<String, IOException> second = ref::set;
+        final IOException thrown = assertThrows(IOException.class, () -> 
throwing.andThen(second).accept("x"));
+        assertEquals(expected, thrown);
+        assertEquals(null, ref.get(), "Second consumer should not have been 
invoked");
+    }
+
+    @Test
+    void testAndThen_nullAfter_throwsNullPointerException() throws Throwable {
+        final FailableConsumer<String, IOException> consumer = s -> {
+        };
+        assertNullPointerException(() -> consumer.andThen(null));
+    }
+
+    @Test
+    void testAndThen_secondThrows_propagatesException() {
+        final IOException expected = new IOException("second");
+        final AtomicReference<String> ref = new AtomicReference<>();
+        final FailableConsumer<String, IOException> first = ref::set;
+        final FailableConsumer<String, IOException> throwing = s -> {
+            throw expected;
+        };
+        final IOException thrown = assertThrows(IOException.class, () -> 
first.andThen(throwing).accept("v"));
+        assertEquals(expected, thrown);
+        assertEquals("v", ref.get(), "First consumer should have been 
invoked");
+    }
+
+    @Test
+    void testNop_acceptDoesNothing() throws Throwable {
+        FailableConsumer.nop().accept("anything");
+    }
+
+    @Test
+    void testNop_returnsNonNull() {
+        assertNotNull(FailableConsumer.nop());
+    }
+
+    @Test
+    void testStaticAccept_consumerThrows_propagatesException() {
+        final IOException expected = new IOException("boom");
+        final FailableConsumer<String, IOException> throwing = s -> {
+            throw expected;
+        };
+        final IOException thrown = assertThrows(IOException.class, () -> 
FailableConsumer.accept(throwing, "x"));
+        assertEquals(expected, thrown);
+    }
+
+    @Test
+    void testStaticAccept_nonNullConsumer_invokesConsumer() throws Exception {
+        final AtomicReference<String> ref = new AtomicReference<>();
+        FailableConsumer.accept(ref::set, "hello");
+        assertEquals("hello", ref.get());
+    }
+
+    @Test
+    void testStaticAccept_nullConsumer_doesNothing() throws Exception {
+        FailableConsumer.accept(null, "value");
+    }
+}

Reply via email to