Map getOrDefault VS getOrUseSupplier
I guess it was because not to blow up the Map interface. You can use Optional.orElseGet(Supplier)
as a workaround (if you don't keep nulls in your map):
Optional.ofNullable(map.get(key)).orElseGet(supplier)
The closest equivalent of getOrUseSupplier()
in Map
is named computeIfAbsent()
which allows for the value to be computed using the key, giving more flexibility than if it only took a Supplier
. It also stores the computed value in the Map
, unlike getOrDefault
. This is because they have distinct use cases and are not really related. While getOrDefault
is usually used to return a "safe" non-null default value (such as returning empty string instead of a null) indicating that something should be in the map, computeIfAbsent()
implies that something must be in the map, and if it's not, it needs to be created or otherwise the internal state of the program is not correct.
The following example ignores the key and just uses the supplier's value.
public static <V,T> V getOrUseSupplier(Map<T, V> map, T key, Supplier<V> supplier) {
return map.computeIfAbsent(key, k -> supplier.get());
}
When lambdas were designed, a discussion was had on the lambda-dev mailing list on whether to include a Supplier
equivalent to getOrDefault
. Two reasons were given by Oracle's Brian Goetz for its exclusion from the API: to avoid feature creep of features that don't carry their own weight, and the cost of lambda capture.
Question
Sometimes constructing the default object is too costly and relying on the ternary operation is the escape hatch again. A Map.getOrDefault(Object,Supplier) would solve this.
Has this been considered before?
Feature creep
Feature creep alert!
getOrDefault barely, and I mean barely, carried its weight.
Cost
BTW, another reason we are reluctant to go Supplier-happy is that there is a mismatch between the actual and perceived cost models for lambda capture.
Capturing stateless (non-capturing) lambdas is essentially free.
Capturing stateful ones, such as
() -> state.toString()
currently has a cost comparable to instantiating an inner class instance that captures a local variable. Since the only reason to provide the supplier version is cost, even though it may deliver significant cost reduction, it may not deliver as much as people expect it will. So this is a small consideration in favor of not leaning on this trick too heavily.
We are looking at VM work that will significantly remove these costs, but first we have to get 8 out the door.