### Question:
LfuCache implements Cache<K, V> { @Override public V computeIfAbsent(K key, Function<K, V> f) { Pair<V> value = data.get(key); if (value == null) { misses.increment(); Pair<V> tmp = new Pair<>(f.apply(key)); value = data.putIfAbsent(key, tmp); if (value == null) { value = tmp; if (size.incrementAndGet() > compactionSize) { tryCompact(); } } } else { hits.increment(); } return value.get(); } LfuCache(Registry registry, String id, int baseSize, int compactionSize); @Override V get(K key); @Override V peek(K key); @Override void put(K key, V value); @Override V computeIfAbsent(K key, Function<K, V> f); @Override void clear(); @Override int size(); @Override Map<K, V> asMap();  }### Answer:
@Test public void computeIfAbsent() { Cache<String, String> cache = create(1, 2); Assertions.assertEquals("A", cache.computeIfAbsent("a", String::toUpperCase)); Assertions.assertEquals(0, hits()); Assertions.assertEquals(1, misses()); }
@Test public void computeIfAbsentRepeat() { Cache<String, String> cache = create(1, 2); Assertions.assertEquals("A", cache.computeIfAbsent("a", String::toUpperCase)); Assertions.assertEquals("A", cache.computeIfAbsent("a", s -> { throw new RuntimeException("fail"); })); Assertions.assertEquals(1, hits()); Assertions.assertEquals(1, misses()); }
@Test public void computeIfAbsentHitRate() { Cache<String, String> cache = create(100, 1000); for (String s : createTestData()) { cache.computeIfAbsent(s, String::toUpperCase); } Assertions.assertEquals(9730, hits()); Assertions.assertEquals(270, misses()); Assertions.assertEquals(0, compactions()); }