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-lang.git


The following commit(s) were added to refs/heads/master by this push:
     new 389fb37  Add Memoizer(Function) and Memoizer(Function, boolean).
389fb37 is described below

commit 389fb37c56d82473ae925d3c8cbb1d4c40819722
Author: Gary Gregory <[email protected]>
AuthorDate: Mon Mar 21 10:00:41 2022 -0400

    Add Memoizer(Function) and Memoizer(Function, boolean).
---
 src/changes/changes.xml                            |  1 +
 .../apache/commons/lang3/concurrent/Memoizer.java  | 34 +++++++++-
 ...moizerTest.java => MemoizerComputableTest.java} | 32 ++++-----
 ...MemoizerTest.java => MemoizerFunctionTest.java} | 76 +++++++++++-----------
 4 files changed, 89 insertions(+), 54 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index e0197e3..c13545e 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -123,6 +123,7 @@ The <action> type attribute can be add,update,fix,remove.
     <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add JavaVersion.JAVA_18.</action>
     <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add TimeZones.toTimeZone(TimeZone).</action>
     <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add FutureTasks.</action>
+    <action                   type="add" dev="ggregory" due-to="Gary 
Gregory">Add Memoizer(Function) and Memoizer(Function, boolean).</action>
     <!-- UPDATE -->
     <action                   type="update" dev="ggregory" due-to="Dependabot, 
Gary Gregory">Bump spotbugs-maven-plugin from 4.2.0 to 4.5.0.0 #735, #808, 
#822, #834.</action>
     <action                   type="update" dev="ggregory" due-to="Dependabot, 
XenoAmess">Bump actions/cache from v2.1.4 to v2.1.7 #742, #752, #764, 
#833.</action>
diff --git a/src/main/java/org/apache/commons/lang3/concurrent/Memoizer.java 
b/src/main/java/org/apache/commons/lang3/concurrent/Memoizer.java
index d53318d..6fccc82 100644
--- a/src/main/java/org/apache/commons/lang3/concurrent/Memoizer.java
+++ b/src/main/java/org/apache/commons/lang3/concurrent/Memoizer.java
@@ -55,7 +55,7 @@ public class Memoizer<I, O> implements Computable<I, O> {
      * Constructs a Memoizer for the provided Computable calculation.
      * </p>
      * <p>
-     * If a calculation is thrown an exception for any reason, this exception 
will be cached and returned for all future
+     * If a calculation throws an exception for any reason, this exception 
will be cached and returned for all future
      * calls with the provided parameter.
      * </p>
      *
@@ -82,6 +82,38 @@ public class Memoizer<I, O> implements Computable<I, O> {
 
     /**
      * <p>
+     * Constructs a Memoizer for the provided Function calculation.
+     * </p>
+     * <p>
+     * If a calculation throws an exception for any reason, this exception 
will be cached and returned for all future
+     * calls with the provided parameter.
+     * </p>
+     *
+     * @param function the function whose results should be memorized
+     * @since 2.13.0
+     */
+    public Memoizer(final Function<I, O> function) {
+        this(function, false);
+    }
+
+    /**
+     * <p>
+     * Constructs a Memoizer for the provided Function calculation, with the 
option of whether a Function that
+     * experiences an error should recalculate on subsequent calls or return 
the same cached exception.
+     * </p>
+     *
+     * @param function the computation whose results should be memorized
+     * @param recalculate determines whether the computation should be 
recalculated on subsequent calls if the previous call
+     *        failed
+     * @since 2.13.0
+     */
+     public Memoizer(final Function<I, O> function, final boolean recalculate) 
{
+        this.recalculate = recalculate;
+        this.mappingFunction = k -> FutureTasks.run(() -> function.apply(k));
+    }
+
+    /**
+     * <p>
      * This method will return the result of the calculation and cache it, if 
it has not previously been calculated.
      * </p>
      * <p>
diff --git 
a/src/test/java/org/apache/commons/lang3/concurrent/MemoizerTest.java 
b/src/test/java/org/apache/commons/lang3/concurrent/MemoizerComputableTest.java
similarity index 99%
copy from src/test/java/org/apache/commons/lang3/concurrent/MemoizerTest.java
copy to 
src/test/java/org/apache/commons/lang3/concurrent/MemoizerComputableTest.java
index d45800d..d34bedb 100644
--- a/src/test/java/org/apache/commons/lang3/concurrent/MemoizerTest.java
+++ 
b/src/test/java/org/apache/commons/lang3/concurrent/MemoizerComputableTest.java
@@ -25,7 +25,7 @@ import org.easymock.EasyMock;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-public class MemoizerTest {
+public class MemoizerComputableTest {
 
     private Computable<Integer, Integer> computable;
 
@@ -35,17 +35,6 @@ public class MemoizerTest {
     }
 
     @Test
-    public void testOnlyCallComputableOnceIfDoesNotThrowException() throws 
Exception {
-        final Integer input = 1;
-        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(computable);
-        expect(computable.compute(input)).andReturn(input);
-        replay(computable);
-
-        assertEquals(input, memoizer.compute(input), "Should call computable 
first time");
-        assertEquals(input, memoizer.compute(input), "Should not call the 
computable the second time");
-    }
-
-    @Test
     public void testDefaultBehaviourNotToRecalculateExecutionExceptions() 
throws Exception {
         final Integer input = 1;
         final Memoizer<Integer, Integer> memoizer = new Memoizer<>(computable);
@@ -83,14 +72,14 @@ public class MemoizerTest {
     }
 
     @Test
-    public void testWhenComputableThrowsRuntimeException() throws Exception {
+    public void testOnlyCallComputableOnceIfDoesNotThrowException() throws 
Exception {
         final Integer input = 1;
         final Memoizer<Integer, Integer> memoizer = new Memoizer<>(computable);
-        final RuntimeException runtimeException = new RuntimeException("Some 
runtime exception");
-        expect(computable.compute(input)).andThrow(runtimeException);
+        expect(computable.compute(input)).andReturn(input);
         replay(computable);
 
-        assertThrows(RuntimeException.class, () -> memoizer.compute(input));
+        assertEquals(input, memoizer.compute(input), "Should call computable 
first time");
+        assertEquals(input, memoizer.compute(input), "Should not call the 
computable the second time");
     }
 
     @Test
@@ -103,4 +92,15 @@ public class MemoizerTest {
 
         assertThrows(Error.class, () -> memoizer.compute(input));
     }
+
+    @Test
+    public void testWhenComputableThrowsRuntimeException() throws Exception {
+        final Integer input = 1;
+        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(computable);
+        final RuntimeException runtimeException = new RuntimeException("Some 
runtime exception");
+        expect(computable.compute(input)).andThrow(runtimeException);
+        replay(computable);
+
+        assertThrows(RuntimeException.class, () -> memoizer.compute(input));
+    }
 }
diff --git 
a/src/test/java/org/apache/commons/lang3/concurrent/MemoizerTest.java 
b/src/test/java/org/apache/commons/lang3/concurrent/MemoizerFunctionTest.java
similarity index 71%
rename from src/test/java/org/apache/commons/lang3/concurrent/MemoizerTest.java
rename to 
src/test/java/org/apache/commons/lang3/concurrent/MemoizerFunctionTest.java
index d45800d..d9419ee 100644
--- a/src/test/java/org/apache/commons/lang3/concurrent/MemoizerTest.java
+++ 
b/src/test/java/org/apache/commons/lang3/concurrent/MemoizerFunctionTest.java
@@ -21,86 +21,88 @@ import static org.easymock.EasyMock.replay;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
+import java.util.function.Function;
+
 import org.easymock.EasyMock;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
-public class MemoizerTest {
+public class MemoizerFunctionTest {
 
-    private Computable<Integer, Integer> computable;
+    private Function<Integer, Integer> function;
 
     @BeforeEach
     public void setUpComputableMock() {
-        computable = EasyMock.mock(Computable.class);
-    }
-
-    @Test
-    public void testOnlyCallComputableOnceIfDoesNotThrowException() throws 
Exception {
-        final Integer input = 1;
-        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(computable);
-        expect(computable.compute(input)).andReturn(input);
-        replay(computable);
-
-        assertEquals(input, memoizer.compute(input), "Should call computable 
first time");
-        assertEquals(input, memoizer.compute(input), "Should not call the 
computable the second time");
+        function = EasyMock.mock(Function.class);
     }
 
     @Test
     public void testDefaultBehaviourNotToRecalculateExecutionExceptions() 
throws Exception {
         final Integer input = 1;
-        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(computable);
-        final InterruptedException interruptedException = new 
InterruptedException();
-        expect(computable.compute(input)).andThrow(interruptedException);
-        replay(computable);
+        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(function);
+        final IllegalArgumentException interruptedException = new 
IllegalArgumentException();
+        expect(function.apply(input)).andThrow(interruptedException);
+        replay(function);
 
         assertThrows(Throwable.class, () -> memoizer.compute(input));
-        assertThrows(IllegalStateException.class, () -> 
memoizer.compute(input));
+        assertThrows(IllegalArgumentException.class, () -> 
memoizer.compute(input));
     }
 
     @Test
     public void testDoesNotRecalculateWhenSetToFalse() throws Exception {
         final Integer input = 1;
-        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(computable, 
false);
-        final InterruptedException interruptedException = new 
InterruptedException();
-        expect(computable.compute(input)).andThrow(interruptedException);
-        replay(computable);
+        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(function, 
false);
+        final IllegalArgumentException interruptedException = new 
IllegalArgumentException();
+        expect(function.apply(input)).andThrow(interruptedException);
+        replay(function);
 
         assertThrows(Throwable.class, () -> memoizer.compute(input));
-        assertThrows(IllegalStateException.class, () -> 
memoizer.compute(input));
+        assertThrows(IllegalArgumentException.class, () -> 
memoizer.compute(input));
     }
 
     @Test
     public void testDoesRecalculateWhenSetToTrue() throws Exception {
         final Integer input = 1;
         final Integer answer = 3;
-        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(computable, 
true);
-        final InterruptedException interruptedException = new 
InterruptedException();
-        
expect(computable.compute(input)).andThrow(interruptedException).andReturn(answer);
-        replay(computable);
+        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(function, 
true);
+        final IllegalArgumentException interruptedException = new 
IllegalArgumentException();
+        
expect(function.apply(input)).andThrow(interruptedException).andReturn(answer);
+        replay(function);
 
         assertThrows(Throwable.class, () -> memoizer.compute(input));
         assertEquals(answer, memoizer.compute(input));
     }
 
     @Test
-    public void testWhenComputableThrowsRuntimeException() throws Exception {
+    public void testOnlyCallComputableOnceIfDoesNotThrowException() throws 
Exception {
         final Integer input = 1;
-        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(computable);
-        final RuntimeException runtimeException = new RuntimeException("Some 
runtime exception");
-        expect(computable.compute(input)).andThrow(runtimeException);
-        replay(computable);
+        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(function);
+        expect(function.apply(input)).andReturn(input);
+        replay(function);
 
-        assertThrows(RuntimeException.class, () -> memoizer.compute(input));
+        assertEquals(input, memoizer.compute(input), "Should call computable 
first time");
+        assertEquals(input, memoizer.compute(input), "Should not call the 
computable the second time");
     }
 
     @Test
     public void testWhenComputableThrowsError() throws Exception {
         final Integer input = 1;
-        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(computable);
+        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(function);
         final Error error = new Error();
-        expect(computable.compute(input)).andThrow(error);
-        replay(computable);
+        expect(function.apply(input)).andThrow(error);
+        replay(function);
 
         assertThrows(Error.class, () -> memoizer.compute(input));
     }
+
+    @Test
+    public void testWhenComputableThrowsRuntimeException() throws Exception {
+        final Integer input = 1;
+        final Memoizer<Integer, Integer> memoizer = new Memoizer<>(function);
+        final RuntimeException runtimeException = new RuntimeException("Some 
runtime exception");
+        expect(function.apply(input)).andThrow(runtimeException);
+        replay(function);
+
+        assertThrows(RuntimeException.class, () -> memoizer.compute(input));
+    }
 }

Reply via email to