我开始学习lambdas,我不明白为什么java Map有:
getOrDefault(Object key, V defaultValue)
而不是(工作方式相同,但如果没有值,那么将从供应商处获取defaultValue):
getOrUseSupplier(Object key, Supplier<V> defaultValue)
我目前看到的目前解决方案:
Disadventages:
我想知道是否还有任何使用和使用的不满情绪。有getOrDefault而不是getOrUseSupplier。你能告诉我,如果在java库中的任何地方,有这样的方法:
static <V> V getOrUseSupplier(Map<?, V> map, Object key, Supplier<V> supplier)
尝试从地图中获取值,如果它不存在,则从供应商处获取值。
答案 0 :(得分:4)
我想这是因为没有炸毁Map界面。您可以使用Optional.orElseGet(Supplier)
作为解决方法(如果您未在地图中保留空值):
Optional.ofNullable(map.get(key)).orElseGet(supplier)
答案 1 :(得分:2)
getOrUseSupplier()
中Map
的最接近的等价物名为computeIfAbsent()
,它允许使用键计算值,比仅使用{{1}时更灵活}。它还将计算值存储在Supplier
中,与Map
不同。这是因为它们具有不同的用例并且不是真正相关的。虽然getOrDefault
通常用于返回&#34; safe&#34;非空的默认值(例如返回空字符串而不是空)表示 应该在地图中,getOrDefault
表示某些必须地图,如果不是,则需要创建,否则程序的内部状态不正确。
以下示例忽略该密钥,只使用供应商的值。
computeIfAbsent()
答案 2 :(得分:1)
设计lambda时,在lambda-dev邮件列表中进行了关于是否包括与Supplier
等效的getOrDefault
的讨论。 Oracle的Brian Goetz将其从API中排除的原因有两个:避免不承担自身权重的特征的特征蠕变以及Lambda捕获的成本。
有时构造默认对象的成本太高,并且依赖于 三元操作又是逃生舱口。一种 Map.getOrDefault(Object,Supplier)将解决此问题。
这曾经被考虑过吗?
蠕变警报!
getOrDefault几乎不承担任何责任,
顺便说一句,我们不愿让供应商满意的另一个原因是 是lambda的实际成本模型与预期成本模型之间的不匹配 捕获。
捕获无状态(非捕获)lambda基本上是免费的。
捕获有状态的,例如
() -> state.toString()
目前具有与实例化内部类实例相当的成本 捕获局部变量。既然提供 供应商版本是成本,即使它可能会带来巨大的成本 减少,其交付的效果可能不如人们期望的那样。所以这 出于一个小考虑,不宜过于依赖此技巧。
我们正在研究可显着消除这些成本的VM工作, 但是首先我们得把8拿出来。
答案 3 :(得分:0)
使用getOrDefault()
方法时,请记住,如果第二个参数(默认值)由于某种原因引发异常,则即使键存在于映射中,也会引发该异常,例如无论键是否存在,都会评估默认值。这是一个示例:
private static final Map<String, Integer> RANKS = new HashMap<>(Map.of(
"A", 9,
"B", 8,
"C", 7,
"D", 6
));
public static void main(final String[] args) {
final int value1 = RANKS.getOrDefault("E", 5); // This will work
final int value2 = RANKS.getOrDefault("A", Integer.valueOf("G")); // Exception!
}
如您所见,即使键A
存在,它仍然会尝试评估默认值,在此示例中它本身会抛出一个NumberFormatException
。
如果您使用假设的getOrUseSupplier()
方法(不幸的是,如@Kayaman所述,该方法尚不存在于Java中,您应该自己实现),您可以执行以下操作:
final int value = getOrUseSupplier(RANKS, "A", () -> Integer.parseInt("G")); // This will work
现在,仅当缺少键A
时才会引发异常。
答案 4 :(得分:0)
Objects.requireNonNullElseGet()
是实现所需的getOrUseSupplier(Object key, Supplier<V> defaultValueSupplier)
行为的好方法。
Objects.requireNonNullElseGet(map.get(key), defaultValueSupplier));
优点(与其他解决方案相比):
需要Java 9。
我也很高兴在地图本身上也有这种方便的方法getOrUseSupplier()
。
也许在即将发布的版本中...
UPD
我认为this mail from Brian Goetz是您原始问题的正式答案。 Java设计人员担心程序员会滥用这种方法捕获lambda。