### Question:
CacheProxy implements InvocationHandler { @SuppressWarnings("unchecked") public static <T> T cache(T delegate) { return (T) newProxyInstance( delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), new CacheProxy(delegate) ); }  @SuppressWarnings("unchecked") static T cache(T delegate); @Override Object invoke(Object proxy, Method method, Object[] args);  }### Answer:
@Test void testCache() { AtomicInteger executionCount = new AtomicInteger(); BiFunction<Integer, String, Integer> task = (i, s) -> executionCount.incrementAndGet(); BiFunction<Integer, String, Integer> cached = cache(task); assertEquals(1, cached.apply(1, "2")); assertEquals(1, cached.apply(1, "2")); assertEquals(2, cached.apply(2, "2")); assertEquals(3, cached.apply(2, "3")); assertEquals(2, cached.apply(2, "2")); assertEquals(1, cached.apply(1, "2")); }
@Test void testThrows() { { Runnable r = () -> { throw new IllegalStateException(); }; assertThrows(IllegalStateException.class, () -> cache(r).run()); } { Runnable r = () -> { throw new Error(); }; assertThrows(Error.class, () -> cache(r).run()); } { Callable<?> r = () -> { throw new IOException(); }; assertThrows(RuntimeException.class, () -> cache(r).call()); } }