Jus*_*meo 10 java java-8 java-stream
我有一个将列表转换为地图的功能.调用此函数后,映射的大小不会更改.我正在尝试在以下两个实现之间做出决定:
Map<Long, Object> listToMap(List<Object> objs) {
/* Implementation One: */
Map<Long, Object> map = new HashMap<>(objs.size(), 1);
for (Object obj : objs) {
map.put(obj.getKey(), obj);
}
return map;
/* Implementation Two: */
return objs.stream().collect(Collectors.toMap(Object::getKey, obj -> obj));
}
Run Code Online (Sandbox Code Playgroud)
在第一个实现中,我通过使用1的加载因子和列表的大小为所有元素分配了足够的内存.这确保不会执行调整大小操作.然后,我遍历列表并逐个添加元素.
在第二个实现中,我使用Java 8流来提高可读性.
我的问题是:第二个实现是否会涉及HashMap的多个调整大小,还是已经过优化以分配足够的内存?
第二个实现将涉及HashMap的多个调整大小.
我通过在调试器中运行它来确定这一点,并且每次调整哈希映射的大小时都会中断.首先,我调整了您发布的代码,以便在我的系统上进行编译:
import java.util.*;
import java.util.stream.*;
class Test {
public static void main(String[] args) {
List<Object> list = new ArrayList<Object>();
for(int i=0; i<100000; i++) {
list.add(new Integer(i));
}
new Test().listToMap(list);
}
Map<Integer, Object> listToMap(List<Object> objs) {
return objs.stream().collect(Collectors.toMap(Object::hashCode, obj -> obj));
}
}
Run Code Online (Sandbox Code Playgroud)
然后我编译它并在调试器中运行它直到它命中listToMap:
$ javac Test.java && jdb Test
Initializing jdb ...
> stop in Test.listToMap
Deferring breakpoint Test.listToMap.
It will be set after the class is loaded.
> run
run Test
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
>
VM Started: Set deferred breakpoint Test.listToMap
Breakpoint hit: "thread=main", Test.listToMap(), line=14 bci=0
14 return objs.stream().collect(Collectors.toMap(Object::hashCode, obj -> obj));
main[1]
Run Code Online (Sandbox Code Playgroud)
然后我设置了一个断点java.util.HashMap.resize并继续:
main[1] stop in java.util.HashMap.resize
Set breakpoint java.util.HashMap.resize
main[1] cont
>
Breakpoint hit: "thread=main", java.util.HashMap.resize(), line=678 bci=0
main[1]
Run Code Online (Sandbox Code Playgroud)
并且cont在我感到无聊之前又多了一些:
main[1] cont
>
Breakpoint hit: "thread=main", java.util.HashMap.resize(), line=678 bci=0
main[1] cont
>
Breakpoint hit: "thread=main", java.util.HashMap.resize(), line=678 bci=0
main[1] cont
>
Breakpoint hit: "thread=main", java.util.HashMap.resize(), line=678 bci=0
main[1] cont
>
Breakpoint hit: "thread=main", java.util.HashMap.resize(), line=678 bci=0
main[1] cont
>
Breakpoint hit: "thread=main", java.util.HashMap.resize(),
line=678 bci=0
main[1] print size
size = 3073
main[1] cont
>
Breakpoint hit: "thread=main", java.util.HashMap.resize(), line=678 bci=0
main[1] print size
size = 6145
main[1] cont
>
Breakpoint hit: "thread=main", java.util.HashMap.resize(), line=678 bci=0
main[1] print size
size = 12289
Run Code Online (Sandbox Code Playgroud)
所以是的:它肯定会不断调整大小.
第二个实现是否涉及HashMap的多个调整大小,还是已经过优化以分配足够的内存?
在你的代码中,前者.请参阅/sf/answers/3593377301/
值得注意的是,对于您当前的实施:
collect结束,你仍然可以结束了一个主哈希数组,它是高达2倍太大."浪费"的内存可能在表中每个条目最多8个字节,但平均每个条目将是4个字节.HashMap.除了用于表示键和值的空间外,每个条目大约消耗32个字节.(以上数字假定为64位引用.)
作为替代方案,如果使用4参数重载,则toMap()可以提供一个Supplier来创建Map要填充的内容.这允许您执行以下操作:
HashMap使用足够大的初始容量来分配a 以避免调整大小,但不能太大.Map每个条目使用的内存少于HashMap.Map<K,V>为您的K和V类型实现.... (例如,您可以使用TLongObjectHashMapGNU Trove库.)(在后两种情况下,目标是找到一个Map或"类似地图"的类,它使用较少的内存(对于你的K和V类型)但仍具有适当的查找性能.)
| 归档时间: |
|
| 查看次数: |
580 次 |
| 最近记录: |