我遇到过与here讨论的问题类似的问题,但具有更强的实际用途。
例如,我有一个Map<String, Integer>
,我有一些函数,给定一个键,如果映射的整数值为负,则将NULL
放到地图上:
Map<String, Integer> map = new HashMap<String, Integer>();
public void nullifyIfNegative(String key) {
Integer value = map.get(key);
if (value != null && value.intValue() < 0) {
map.put(key, null);
}
}
在这种情况下,查找(以及密钥的hashCode
计算)完成两次:一次用于查找,一次用于替换。如果有另一种方法(已经在HashMap
中)并且允许使其更有效,那将是很好的:
public void nullifyIfNegative(String key) {
Map.Entry<String, Integer> entry = map.getEntry(key);
if (entry != null && entry.getValue().intValue() < 0) {
entry.setValue(null);
}
}
同样关注的情况,当你想操纵不可变对象时,可以是映射值:
Map<String, String>
:我想在字符串值附加一些内容。Map<String, int[]>
:我想在数组中插入一个数字。所以这种情况很常见。解决方案,可能有用,但不适合我:
org.apache.commons.collections.map.AbstractHashedMap
(至少有protected getEntry()
方法),但不幸的是,commons-collections不支持泛型。org.apache.commons.lang.mutable.MutableInt
]或集合而不是数组)。这个解决方案会导致内存丢失,我想避免这种情况。java.util.HashMap
(应该放在java.util
包中)并将其放到endorsed folder(因为java.lang.ClassLoader
将拒绝加载{ {1}},请参阅资料来源),但我不想修补JDK,看起来像可以认可的软件包列表,不包括Class<?> defineClass(String name, byte[] b, int off, int len)
。类似的问题已在sun.com bugtracker上提出,但我想知道,社区的意见是什么,以及可以考虑最大记忆和出路的方法。绩效。
如果您同意,这是好的和受益的功能,请投票给这个错误!
答案 0 :(得分:3)
作为一个逻辑问题,你是对的,因为单个getEntry会为你节省哈希查找。实际上,除非你有一个特定的用例,你有理由担心性能损失(这似乎不太可能,哈希查找很常见,O(1),并且很好地优化)你担心的是可能微不足道。
你为什么不写一个考试?创建一个哈希表,其中包含数百万个对象的数量,或者比应用程序可能创建的数量级更大的数量级,并且平均get()的时间超过一百万次左右(提示:它将会是一个非常小的数字。)
你正在做的更大的问题是同步。您应该知道,如果您在地图上进行条件更改,即使您使用的是同步地图,也可能会遇到问题,因为您必须锁定对覆盖两者的范围的密钥的访问权限( )和set()操作。
答案 1 :(得分:1)
不漂亮,但您可以使用轻量级对象来保存对实际值的引用,以避免第二次查找。
HashMap<String, String[]> map = ...;
// append value to the current value of key
String key = "key";
String value = "value";
// I use an array to hold a reference - even uglier than the whole idea itself ;)
String[] ref = new String[1]; // lightweigt object
String[] prev = map.put(key, ref);
ref[0] = (prev != null) ? prev[0] + value : value;
我不会过分担心哈希查找性能(Steve B's answer指出原因非常好)。特别是对于String键,我不会过于担心hashCode()
,因为它的结果是缓存的。您可能会担心equals()
,因为每次查询可能会多次调用它。但对于短字符串(通常用作键),这也可以忽略不计。
答案 2 :(得分:-2)
此提案没有性能提升,因为平均情况下Map的性能为O(1)。但是在这种情况下允许访问原始条目会引发另一个问题。可以更改条目中的键(即使它只能通过反射),因此可以中断内部数组的顺序。