java - ArrayList::new 在 map 的 computeIfAbsent 方法中比 k->new ArrayList<>() 花费更多时间
问题描述
我需要根据对象的某些成员对对象列表进行分组。让我通过一个例子来展示我想要实现的需求:
我有一个UserStage类:
public class UserStage {
private Integer userId;
private Integer stageId;
private LocalDateTime modifiedOn;
//getter, setter and toString methods
}
现在假设我有一个List<UserStage>
可以为同一个 userId 拥有多个对象的对象。我们称之为userStageDataList。
我想按 userId 对这个列表进行分组,以便我可以获得特定 userId 的所有记录的列表。这可以通过不同的方法来实现,但我试图实现的方法如下:
Map<Integer, List<UserStage>> userWiseStageList = new HashMap<>();
for (UserStage userStage : userStageDataList) {
userWiseStageList.computeIfAbsent(userStage.getUserId(), ArrayList::new).add(userStage);
}
但令我惊讶的是,对于列表中的 75 个项目,执行此操作需要持续大约 3000 毫秒。有时它会抛出java.lang.OutOfMemoryError: Java heap space
.
当我替换为时ArrayList::new
,k -> new ArrayList<>()
现在只需要 3 到 4 毫秒即可创建分组。
我尝试groupingBy
使用streams
,并且对于同一个列表,它也在 5-7 毫秒内很好地执行。
我使用以下代码来测量执行时间:
StopWatch watch = new StopWatch();
watch.start();
// here goes map creation code as shown above
logger.info("\n\n\n time taken for creating the map = {}",watch.getTime(TimeUnit.MILLISECONDS));
我在这里错过了什么吗?任何建议,将不胜感激!
谢谢。
解决方案
map.computeIfAbsent(k, func)
如果没有 key ,将func
使用参数调用。k
map
k
- 函数
ArrayList::new
接受一个参数initialCapacity
,该参数将是 List 的后备数组的初始大小
因此,在您的情况下,如果地图中不存在 userId 1000
,则程序将执行new ArrayList<>(1000)
以创建由Object[]
size支持的 ArrayList 1000
。这就是为什么它需要更长的时间并且有时会消耗所有 VM 内存的原因。
推荐阅读
- java - 替换选择排序:
- python - Django Form Wizard - 为相关的帖子模型使用图像表单集
- php - 在 PHP Laravel 控制器中定义和初始化一个类属性
- angular - Angular7具有空路径的多个子路由
- image-processing - 如何在图像处理中找到联合直方图和边缘直方图,它们之间有什么显着性差异?
- list - takeWhile 在 Scala 中用于元素 n+1
- angular - 升级到 Angular 9 后,自定义类型定义文件被忽略
- python - Pulp Killer 数独 - 检查选项对于变量的选择是不同的
- objective-c - 将动作附加到按钮并单击 MacOS 应用程序中的未触发事件
- firefox - 如何在privacy.resistfingerprinting(Firefox)中制作固定大小的窗口