Suppose I have a cache implemented as java.util.Map which stores (arbitrary) values for keys. As the values are not mandatorily present, the cache returns an java.util.Optional and is able to be provided with a java.util.function.Supplier to calculate the value for a given non-existing key.
My first naive approach was
public class Cache0 {
private final Map<String, String> mapping = new HashMap<>();
public Optional<String> get(String key, Supplier<Optional<String>> supplier) {
final Optional<String> valueOptional;
if (this.mapping.containsKey(key)) {
final String value = this.mapping.get(key);
valueOptional = Optional.of(value);
} else {
valueOptional = supplier.get();
if (valueOptional.isPresent()) {
this.mapping.put(key, valueOptional.get());
}
}
return valueOptional;
}
}
but I found this very inelegant and as I learned about java.util.Map#computeIfAbsent I changed the code to the following
public class Cache1 {
private final Map<String, String> mapping = new HashMap<>();
public Optional<String> get(String key, Supplier<Optional<String>> supplier) {
final String value = this.mapping.computeIfAbsent(key, absentKey -> this.getValue(supplier));
return Optional.ofNullable(value);
}
private String getValue(Supplier<Optional<String>> supplier) {
return supplier.get()
.orElse(null);
}
}
but what now bothers me is the redundant use of java.util.Optional#ofNullable in combination with the null result of the getValue method which is needed to provide java.util.Map#computeIfAbsent with the "default" value not to be inserted into the map.
In an ideal situation, something like the following would be possible
public class Cache2 {
private final Map<String, String> mapping = new HashMap<>();
public Optional<String> get(String key, Supplier<Optional<String>> supplier) {
return this.mapping.computeIfAbsent(key, absentKey -> supplier.get());
}
}
where java.util.Map#computeIfAbsent would skip the insertion if the second parameter represents an empty java.util.Optional and returns an java.util.Optional#empty instead but unfortunately the use of java.util.Optional#empty as "default" insert value for java.util.Map#computeIfAbsent is not supported and the code does not compile.
A further possibility would be to store a mapping of String to java.util.Optional but then the java.util.Map would store the java.util.Optional#empty as value contradicting my use-case again to be forced to store invalid mappings and removing/replacing them by hand later.
public class Cache3 {
private final Map<String, Optional<String>> mapping = new HashMap<>();
public Optional<String> get(String key, Supplier<Optional<String>> supplier) {
return this.mapping.computeIfAbsent(key, absentKey -> supplier.get());
}
}
Is anyone aware of a better approach to handle this kind of use-case or do I have to fall back to my implementation of Cache1?