diff --git a/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingBiConsumer.java b/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingBiConsumer.java new file mode 100644 index 0000000..b791a02 --- /dev/null +++ b/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingBiConsumer.java @@ -0,0 +1,29 @@ +package org.zeplinko.commons.lang.ext.util.function; + +/** + * A {@link java.util.function.BiConsumer}-like functional interface whose + * {@link #accept(Object, Object)} method is allowed to throw a checked + * {@link Exception}. + * + *

+ * This is useful when you want to use lambdas or method references that can + * throw checked exceptions in contexts where a {@code BiConsumer} would + * normally be used. + *

+ * + * @author Shivam Nagpal + * + * @param the type of the first argument to the operation + * @param the type of the second argument to the operation + */ +@FunctionalInterface +public interface ThrowingBiConsumer { + /** + * Performs this operation on the given arguments. + * + * @param t the first input argument + * @param u the second input argument + * @throws Exception if the operation fails + */ + void accept(T t, U u) throws Exception; +} diff --git a/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingBiFunction.java b/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingBiFunction.java new file mode 100644 index 0000000..8c87600 --- /dev/null +++ b/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingBiFunction.java @@ -0,0 +1,31 @@ +package org.zeplinko.commons.lang.ext.util.function; + +/** + * A {@link java.util.function.BiFunction}-like functional interface whose + * {@link #apply(Object, Object)} method is allowed to throw a checked + * {@link Exception}. + * + *

+ * This is useful when you want to use lambdas or method references that can + * throw checked exceptions in contexts where a {@code BiFunction} would + * normally be used. + *

+ * + * @author Shivam Nagpal + * + * @param the type of the first argument to the function + * @param the type of the second argument to the function + * @param the type of the result of the function + */ +@FunctionalInterface +public interface ThrowingBiFunction { + /** + * Applies this function to the given arguments. + * + * @param t the first function argument + * @param u the second function argument + * @return the function result + * @throws Exception if the operation fails + */ + R apply(T t, U u) throws Exception; +} diff --git a/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingConsumer.java b/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingConsumer.java new file mode 100644 index 0000000..4b08b27 --- /dev/null +++ b/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingConsumer.java @@ -0,0 +1,27 @@ +package org.zeplinko.commons.lang.ext.util.function; + +/** + * A {@link java.util.function.Consumer}-like functional interface whose + * {@link #accept(Object)} method is allowed to throw a checked + * {@link Exception}. + * + *

+ * This is useful when you want to use lambdas or method references that can + * throw checked exceptions in contexts where a {@code Consumer} would normally + * be used. + *

+ * + * @author Shivam Nagpal + * + * @param the type of the input to the operation + */ +@FunctionalInterface +public interface ThrowingConsumer { + /** + * Performs this operation on the given argument. + * + * @param t the input argument + * @throws Exception if the operation fails + */ + void accept(T t) throws Exception; +} diff --git a/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingFunction.java b/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingFunction.java new file mode 100644 index 0000000..3b92a13 --- /dev/null +++ b/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingFunction.java @@ -0,0 +1,29 @@ +package org.zeplinko.commons.lang.ext.util.function; + +/** + * A {@link java.util.function.Function}-like functional interface whose + * {@link #apply(Object)} method is allowed to throw a checked + * {@link Exception}. + * + *

+ * This is useful when you want to use lambdas or method references that can + * throw checked exceptions in contexts where a {@code Function} would normally + * be used. + *

+ * + * @author Shivam Nagpal + * + * @param the type of the input to the function + * @param the type of the result of the function + */ +@FunctionalInterface +public interface ThrowingFunction { + /** + * Applies this function to the given argument. + * + * @param t the function argument + * @return the function result + * @throws Exception if the operation fails + */ + R apply(T t) throws Exception; +} diff --git a/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingRunnable.java b/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingRunnable.java new file mode 100644 index 0000000..5abefb9 --- /dev/null +++ b/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingRunnable.java @@ -0,0 +1,24 @@ +package org.zeplinko.commons.lang.ext.util.function; + +/** + * A {@link java.lang.Runnable}-like functional interface whose {@link #run()} + * method is allowed to throw a checked {@link Exception}. + * + *

+ * This is useful when you want to use lambdas or method references that can + * throw checked exceptions in contexts where a {@code Runnable} would normally + * be used. + *

+ * + * @author Shivam Nagpal + * + */ +@FunctionalInterface +public interface ThrowingRunnable { + /** + * Executes this runnable operation. + * + * @throws Exception if the operation fails + */ + void run() throws Exception; +} diff --git a/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingSupplier.java b/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingSupplier.java new file mode 100644 index 0000000..e8888e6 --- /dev/null +++ b/src/main/java/org/zeplinko/commons/lang/ext/util/function/ThrowingSupplier.java @@ -0,0 +1,26 @@ +package org.zeplinko.commons.lang.ext.util.function; + +/** + * A {@link java.util.function.Supplier}-like functional interface whose + * {@link #get()} method is allowed to throw a checked {@link Exception}. + * + *

+ * This is useful when you want to use lambdas or method references that can + * throw checked exceptions in contexts where a {@code Supplier} would normally + * be used. + *

+ * + * @author Shivam Nagpal + * + * @param the type of results supplied by this supplier + */ +@FunctionalInterface +public interface ThrowingSupplier { + /** + * Gets a result. + * + * @return a result + * @throws Exception if the operation fails + */ + T get() throws Exception; +} diff --git a/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingBiConsumerTest.java b/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingBiConsumerTest.java new file mode 100644 index 0000000..dc99cae --- /dev/null +++ b/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingBiConsumerTest.java @@ -0,0 +1,54 @@ +package org.zeplinko.commons.lang.ext.util.function; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.*; + +class ThrowingBiConsumerTest { + + @Test + void test_whenAcceptIsInvoked_thenConsumesBothValues() throws Exception { + Map map = new HashMap<>(); + ThrowingBiConsumer consumer = map::put; + consumer.accept("key", 42); + assertEquals(1, map.size()); + assertEquals(42, map.get("key")); + } + + @Test + void test_whenAcceptIsInvokedWithNullValues_thenConsumesNulls() throws Exception { + Map map = new HashMap<>(); + ThrowingBiConsumer consumer = map::put; + consumer.accept(null, null); + assertEquals(1, map.size()); + assertTrue(map.containsKey(null)); + assertNull(map.get(null)); + } + + @Test + void test_whenAcceptThrowsException_thenExceptionIsPropagated() { + ThrowingBiConsumer consumer = (key, value) -> { + throw new IOException("Test exception"); + }; + Exception exception = assertThrows(Exception.class, () -> consumer.accept("key", 42)); + assertEquals("Test exception", exception.getMessage()); + assertInstanceOf(IOException.class, exception); + } + + @Test + void test_whenAcceptIsInvokedMultipleTimes_thenConsumesAllValues() throws Exception { + Map map = new HashMap<>(); + ThrowingBiConsumer consumer = map::put; + consumer.accept("one", 1); + consumer.accept("two", 2); + consumer.accept("three", 3); + assertEquals(3, map.size()); + assertEquals(1, map.get("one")); + assertEquals(2, map.get("two")); + assertEquals(3, map.get("three")); + } +} diff --git a/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingBiFunctionTest.java b/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingBiFunctionTest.java new file mode 100644 index 0000000..084913a --- /dev/null +++ b/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingBiFunctionTest.java @@ -0,0 +1,58 @@ +package org.zeplinko.commons.lang.ext.util.function; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.*; + +class ThrowingBiFunctionTest { + + @Test + void test_whenApplyIsInvoked_thenCombinesBothValues() throws Exception { + ThrowingBiFunction function = Integer::sum; + Integer result = function.apply(5, 3); + assertEquals(8, result); + } + + @Test + void test_whenApplyIsInvokedWithNullValues_thenHandlesNulls() throws Exception { + ThrowingBiFunction function = (first, second) -> { + if (first == null && second == null) + return "both null"; + if (first == null) + return "first null"; + if (second == null) + return "second null"; + return first + second; + }; + assertEquals("both null", function.apply(null, null)); + assertEquals("first null", function.apply(null, "test")); + assertEquals("second null", function.apply("test", null)); + } + + @Test + void test_whenApplyThrowsException_thenExceptionIsPropagated() { + ThrowingBiFunction function = (first, second) -> { + throw new IOException("Test exception"); + }; + Exception exception = assertThrows(Exception.class, () -> function.apply("a", "b")); + assertEquals("Test exception", exception.getMessage()); + assertInstanceOf(IOException.class, exception); + } + + @Test + void test_whenApplyIsInvokedMultipleTimes_thenTransformsEachPair() throws Exception { + ThrowingBiFunction function = (a, b) -> a * b; + assertEquals(6, function.apply(2, 3)); + assertEquals(20, function.apply(4, 5)); + assertEquals(42, function.apply(6, 7)); + } + + @Test + void test_whenApplyReturnsNull_thenReturnsNull() throws Exception { + ThrowingBiFunction function = (first, second) -> null; + String result = function.apply("a", "b"); + assertNull(result); + } +} diff --git a/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingConsumerTest.java b/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingConsumerTest.java new file mode 100644 index 0000000..bac4843 --- /dev/null +++ b/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingConsumerTest.java @@ -0,0 +1,63 @@ +package org.zeplinko.commons.lang.ext.util.function; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class ThrowingConsumerTest { + + @Test + void test_whenAcceptIsInvoked_thenConsumesValue() throws Exception { + List list = new ArrayList<>(); + ThrowingConsumer consumer = list::add; + consumer.accept("test"); + assertEquals(1, list.size()); + assertEquals("test", list.get(0)); + } + + @Test + void test_whenAcceptIsInvokedWithNull_thenConsumesNull() throws Exception { + List list = new ArrayList<>(); + ThrowingConsumer consumer = list::add; + consumer.accept(null); + assertEquals(1, list.size()); + assertNull(list.get(0)); + } + + @Test + void test_whenAcceptThrowsException_thenExceptionIsPropagated() { + ThrowingConsumer consumer = (value) -> { + throw new IOException("Test exception"); + }; + Exception exception = assertThrows(Exception.class, () -> consumer.accept("test")); + assertEquals("Test exception", exception.getMessage()); + assertInstanceOf(IOException.class, exception); + } + + @Test + void test_whenAcceptIsInvokedMultipleTimes_thenConsumesAllValues() throws Exception { + List list = new ArrayList<>(); + ThrowingConsumer consumer = list::add; + consumer.accept(1); + consumer.accept(2); + consumer.accept(3); + assertEquals(3, list.size()); + assertEquals(1, list.get(0)); + assertEquals(2, list.get(1)); + assertEquals(3, list.get(2)); + } + + @Test + void test_whenAcceptIsInvokedWithComplexObject_thenConsumesObject() throws Exception { + List list = new ArrayList<>(); + ThrowingConsumer consumer = list::add; + String[] array = { "a", "b", "c" }; + consumer.accept(array); + assertEquals(1, list.size()); + assertSame(array, list.get(0)); + } +} diff --git a/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingFunctionTest.java b/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingFunctionTest.java new file mode 100644 index 0000000..9065af2 --- /dev/null +++ b/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingFunctionTest.java @@ -0,0 +1,59 @@ +package org.zeplinko.commons.lang.ext.util.function; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.*; + +class ThrowingFunctionTest { + + @Test + void test_whenApplyIsInvoked_thenTransformsValue() throws Exception { + ThrowingFunction function = String::length; + Integer result = function.apply("test"); + assertEquals(4, result); + } + + @Test + void test_whenApplyIsInvokedWithNull_thenHandlesNull() throws Exception { + ThrowingFunction function = (value) -> value == null ? "null" : value.toUpperCase(); + String result = function.apply(null); + assertEquals("null", result); + } + + @Test + void test_whenApplyThrowsException_thenExceptionIsPropagated() { + ThrowingFunction function = (value) -> { + throw new IOException("Test exception"); + }; + Exception exception = assertThrows(Exception.class, () -> function.apply("test")); + assertEquals("Test exception", exception.getMessage()); + assertInstanceOf(IOException.class, exception); + } + + @Test + void test_whenApplyIsInvokedMultipleTimes_thenTransformsEachValue() throws Exception { + ThrowingFunction function = (value) -> value * 2; + assertEquals(4, function.apply(2)); + assertEquals(10, function.apply(5)); + assertEquals(20, function.apply(10)); + } + + @Test + void test_whenApplyIsInvokedWithComplexTransformation_thenReturnsTransformedValue() throws Exception { + ThrowingFunction function = (value) -> value.split(","); + String[] result = function.apply("a,b,c"); + assertEquals(3, result.length); + assertEquals("a", result[0]); + assertEquals("b", result[1]); + assertEquals("c", result[2]); + } + + @Test + void test_whenApplyReturnsNull_thenReturnsNull() throws Exception { + ThrowingFunction function = (value) -> null; + String result = function.apply("test"); + assertNull(result); + } +} diff --git a/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingRunnableTest.java b/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingRunnableTest.java new file mode 100644 index 0000000..05433f8 --- /dev/null +++ b/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingRunnableTest.java @@ -0,0 +1,55 @@ +package org.zeplinko.commons.lang.ext.util.function; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicInteger; + +import static org.junit.jupiter.api.Assertions.*; + +class ThrowingRunnableTest { + + @Test + void test_whenRunIsInvoked_thenExecutesSuccessfully() throws Exception { + AtomicInteger counter = new AtomicInteger(0); + ThrowingRunnable runnable = counter::incrementAndGet; + runnable.run(); + assertEquals(1, counter.get()); + } + + @Test + void test_whenRunIsInvokedMultipleTimes_thenExecutesEachTime() throws Exception { + AtomicInteger counter = new AtomicInteger(0); + ThrowingRunnable runnable = counter::incrementAndGet; + runnable.run(); + runnable.run(); + runnable.run(); + assertEquals(3, counter.get()); + } + + @Test + void test_whenRunThrowsException_thenExceptionIsPropagated() { + ThrowingRunnable runnable = () -> { + throw new IOException("Test exception"); + }; + Exception exception = assertThrows(Exception.class, runnable::run); + assertEquals("Test exception", exception.getMessage()); + assertInstanceOf(IOException.class, exception); + } + + @Test + void test_whenRunIsInvokedWithSideEffect_thenSideEffectOccurs() throws Exception { + StringBuilder sb = new StringBuilder(); + ThrowingRunnable runnable = () -> sb.append("executed"); + runnable.run(); + assertEquals("executed", sb.toString()); + } + + @Test + void test_whenRunIsInvokedWithNoOperation_thenNoExceptionIsThrown() { + ThrowingRunnable runnable = () -> { + // No operation + }; + assertDoesNotThrow(runnable::run); + } +} diff --git a/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingSupplierTest.java b/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingSupplierTest.java new file mode 100644 index 0000000..f82dd7d --- /dev/null +++ b/src/test/java/org/zeplinko/commons/lang/ext/util/function/ThrowingSupplierTest.java @@ -0,0 +1,51 @@ +package org.zeplinko.commons.lang.ext.util.function; + +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.*; + +class ThrowingSupplierTest { + + @Test + void test_whenGetIsInvoked_thenReturnsExpectedValue() throws Exception { + ThrowingSupplier supplier = () -> "test value"; + String result = supplier.get(); + assertEquals("test value", result); + } + + @Test + void test_whenGetIsInvokedWithNull_thenReturnsNull() throws Exception { + ThrowingSupplier supplier = () -> null; + String result = supplier.get(); + assertNull(result); + } + + @Test + void test_whenGetThrowsException_thenExceptionIsPropagated() { + ThrowingSupplier supplier = () -> { + throw new IOException("Test exception"); + }; + Exception exception = assertThrows(Exception.class, supplier::get); + assertEquals("Test exception", exception.getMessage()); + assertInstanceOf(IOException.class, exception); + } + + @Test + void test_whenGetIsInvokedMultipleTimes_thenReturnsConsistentValue() throws Exception { + ThrowingSupplier supplier = () -> 42; + assertEquals(42, supplier.get()); + assertEquals(42, supplier.get()); + assertEquals(42, supplier.get()); + } + + @Test + void test_whenGetIsInvokedWithComplexObject_thenReturnsObject() throws Exception { + String[] expectedArray = { "a", "b", "c" }; + ThrowingSupplier supplier = () -> expectedArray; + String[] result = supplier.get(); + assertSame(expectedArray, result); + assertArrayEquals(expectedArray, result); + } +}