Add getResultThrowing; remove Deprecated getResult

This commit is contained in:
2024-02-26 14:20:02 -06:00
parent edf942a01b
commit a035bbe18f
2 changed files with 62 additions and 57 deletions

View File

@ -58,42 +58,15 @@ public class Memoization<K, V>
/*******************************************************************************
** Get the memoized Value for a given input Key.
**
** But note, this looks the same to the caller, whether the key just wasn't in
** the internal map (e.g., had never been looked up), or if it was previously looked
** up, and that returned null. In either case, the optional will be empty.
**
** See getMemoizedResult for where we can tell the difference (and we would
** generally want to call that.
*******************************************************************************/
@Deprecated
public Optional<V> getResult(K key)
{
MemoizedResult<V> result = map.get(key);
if(result != null)
{
if(result.getTime().isAfter(Instant.now().minus(timeout)))
{
return (Optional.ofNullable(result.getResult()));
}
}
return (Optional.empty());
}
/******************************************************************************* /*******************************************************************************
** Get the memoized Value for a given input Key - computing it if it wasn't previously ** Get the memoized Value for a given input Key - computing it if it wasn't previously
** memoized (or expired). ** memoized (or expired).
** **
** In here, if the optional is empty, it means the value is null (whether that ** If the returned Optional is empty, it means the value is null (whether that
** came form memoization, or from the lookupFunction, you don't care - the answer ** came form memoization, or from the lookupFunction, you don't care - the answer
** is null). ** is null).
*******************************************************************************/ *******************************************************************************/
public Optional<V> getResult(K key, UnsafeFunction<K, V, ?> lookupFunction) public <E extends Exception> Optional<V> getResultThrowing(K key, UnsafeFunction<K, V, E> lookupFunction) throws E
{ {
MemoizedResult<V> result = map.get(key); MemoizedResult<V> result = map.get(key);
if(result != null) if(result != null)
@ -111,12 +84,33 @@ public class Memoization<K, V>
///////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////
// ok - either we never memoized this key, or it's expired, so, apply the lookup function, // // ok - either we never memoized this key, or it's expired, so, apply the lookup function, //
// store the result, and then return the value (in an Optional.ofNullable) // // store the result, and then return the value (in an Optional.ofNullable) //
// and if the lookup function throws - then we let it throw. //
///////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////
V value = lookupFunction.apply(key);
storeResult(key, value);
return (Optional.ofNullable(value));
}
/*******************************************************************************
** Get the memoized Value for a given input Key - computing it if it wasn't previously
** memoized (or expired).
**
** If a null value was memoized, the resulting optional here will be empty.
**
** If the lookup function throws, then a null value will be memoized and an empty
** Optional will be returned.
**
** In here, if the optional is empty, it means the value is null (whether that
** came form memoization, or from the lookupFunction, you don't care - the answer
** is null).
*******************************************************************************/
public Optional<V> getResult(K key, UnsafeFunction<K, V, ?> lookupFunction)
{
try try
{ {
V value = lookupFunction.apply(key); return getResultThrowing(key, lookupFunction);
storeResult(key, value);
return (Optional.ofNullable(value));
} }
catch(Exception e) catch(Exception e)
{ {
@ -131,8 +125,8 @@ public class Memoization<K, V>
/******************************************************************************* /*******************************************************************************
** Get a memoized result, optionally containing a Value, for a given input Key. ** Get a memoized result, optionally containing a Value, for a given input Key.
** **
** In this method (contrasted with getResult), if the returned Optional is empty, ** If the returned Optional is empty, it means that we haven't ever looked up
** it means that we haven't ever looked up or memoized the key (or it's expired). ** or memoized the key (or it's expired).
** **
** If the returned Optional is not empty, then it means we've memoized something ** If the returned Optional is not empty, then it means we've memoized something
** (and it's not expired) - so if the Value from the MemoizedResult is null, ** (and it's not expired) - so if the Value from the MemoizedResult is null,

View File

@ -39,6 +39,7 @@ import com.kingsrook.qqq.backend.core.utils.lambdas.UnsafeFunction;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
@ -61,9 +62,9 @@ class MemoizationTest extends BaseTest
memoization.setMaxSize(3); memoization.setMaxSize(3);
memoization.setTimeout(Duration.ofMillis(100)); memoization.setTimeout(Duration.ofMillis(100));
assertThat(memoization.getResult("one")).isEmpty(); assertThat(memoization.getMemoizedResult("one")).isEmpty();
memoization.storeResult("one", 1); memoization.storeResult("one", 1);
assertThat(memoization.getResult("one")).isPresent().get().isEqualTo(1); assertThat(memoization.getMemoizedResult("one")).isPresent().get().extracting("result").isEqualTo(1);
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
// store 3 more results - this should force 1 out // // store 3 more results - this should force 1 out //
@ -71,22 +72,22 @@ class MemoizationTest extends BaseTest
memoization.storeResult("two", 2); memoization.storeResult("two", 2);
memoization.storeResult("three", 3); memoization.storeResult("three", 3);
memoization.storeResult("four", 4); memoization.storeResult("four", 4);
assertThat(memoization.getResult("one")).isEmpty(); assertThat(memoization.getMemoizedResult("one")).isEmpty();
////////////////////////////////// //////////////////////////////////
// make sure others are present // // make sure others are present //
////////////////////////////////// //////////////////////////////////
assertThat(memoization.getResult("two")).isPresent().get().isEqualTo(2); assertThat(memoization.getMemoizedResult("two")).isPresent().get().extracting("result").isEqualTo(2);
assertThat(memoization.getResult("three")).isPresent().get().isEqualTo(3); assertThat(memoization.getMemoizedResult("three")).isPresent().get().extracting("result").isEqualTo(3);
assertThat(memoization.getResult("four")).isPresent().get().isEqualTo(4); assertThat(memoization.getMemoizedResult("four")).isPresent().get().extracting("result").isEqualTo(4);
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
// wait more than the timeout, then make sure all are gone // // wait more than the timeout, then make sure all are gone //
///////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////
SleepUtils.sleep(150, TimeUnit.MILLISECONDS); SleepUtils.sleep(150, TimeUnit.MILLISECONDS);
assertThat(memoization.getResult("two")).isEmpty(); assertThat(memoization.getMemoizedResult("two")).isEmpty();
assertThat(memoization.getResult("three")).isEmpty(); assertThat(memoization.getMemoizedResult("three")).isEmpty();
assertThat(memoization.getResult("four")).isEmpty(); assertThat(memoization.getMemoizedResult("four")).isEmpty();
} }
@ -100,24 +101,17 @@ class MemoizationTest extends BaseTest
Memoization<String, Integer> memoization = new Memoization<>(); Memoization<String, Integer> memoization = new Memoization<>();
memoization.storeResult("null", null); memoization.storeResult("null", null);
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////
// note - we can't tell a stored null apart from a non-stored value by calling getResult // // the memoizedResult should never be null, and should be present if we memoized/stored a null value //
/////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////
Optional<Integer> optionalNull = memoization.getResult("null");
assertNotNull(optionalNull);
assertTrue(optionalNull.isEmpty());
////////////////////////////////////////////
// instead, we must use getMemoizedResult //
////////////////////////////////////////////
Optional<MemoizedResult<Integer>> optionalMemoizedResult = memoization.getMemoizedResult("null"); Optional<MemoizedResult<Integer>> optionalMemoizedResult = memoization.getMemoizedResult("null");
assertNotNull(optionalMemoizedResult); assertNotNull(optionalMemoizedResult);
assertTrue(optionalMemoizedResult.isPresent()); assertTrue(optionalMemoizedResult.isPresent());
assertNull(optionalMemoizedResult.get().getResult()); assertNull(optionalMemoizedResult.get().getResult());
///////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// make sure getMemoizedResult returns empty for an un-set key // // make sure getMemoizedResult returns non-null and empty for an un-set key //
///////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
optionalMemoizedResult = memoization.getMemoizedResult("never-stored"); optionalMemoizedResult = memoization.getMemoizedResult("never-stored");
assertNotNull(optionalMemoizedResult); assertNotNull(optionalMemoizedResult);
assertTrue(optionalMemoizedResult.isEmpty()); assertTrue(optionalMemoizedResult.isEmpty());
@ -177,6 +171,23 @@ class MemoizationTest extends BaseTest
/*******************************************************************************
**
*******************************************************************************/
@Test
void testGetResultThrowing() throws Exception
{
Memoization<String, Integer> memoization = new Memoization<>();
UnsafeFunction<String, Integer, Exception> lookupFunction = Integer::parseInt;
assertEquals(Optional.of(1), memoization.getResultThrowing("1", lookupFunction));
assertThatThrownBy(() -> memoization.getResultThrowing(null, lookupFunction)).hasMessageContaining("null");
assertThatThrownBy(() -> memoization.getResultThrowing("two", lookupFunction)).hasMessageContaining("For input string:");
}
/******************************************************************************* /*******************************************************************************
** **
*******************************************************************************/ *******************************************************************************/
@ -198,7 +209,7 @@ class MemoizationTest extends BaseTest
for(int n = 0; n < 1_000_000; n++) for(int n = 0; n < 1_000_000; n++)
{ {
memoization.storeResult(String.valueOf(n), n); memoization.storeResult(String.valueOf(n), n);
memoization.getResult(String.valueOf(n)); memoization.getMemoizedResult(String.valueOf(n));
if(n % 100_000 == 0) if(n % 100_000 == 0)
{ {