【问题标题】:ArrayList::new taking more time than k->new ArrayList<>() in computeIfAbsent method of map [duplicate]ArrayList::new 在 map 的 computeIfAbsent 方法中比 k->new ArrayList<>() 花费更多时间 [重复]
【发布时间】:2021-01-29 05:43:04
【问题描述】:

我需要根据对象的某些成员对对象列表进行分组。让我通过一个例子来展示我想要实现的需求:

我有一个 UserStage 类:

public class UserStage {

    private Integer userId;
    private Integer stageId;
    private LocalDateTime modifiedOn;

   //getter, setter and toString methods
}

现在假设我有一个List&lt;UserStage&gt;,它可以为同一个用户 ID 提供多个对象。我们称之为 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 -&gt; new ArrayList&lt;&gt;() 时,现在创建分组只需要 3 到 4 毫秒。

我尝试使用streams 使用groupingBy,对于同一个列表,它也在 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));

我在这里错过了什么吗?任何建议将不胜感激!

谢谢。

【问题讨论】:

    标签: java arraylist lambda java-8 hashmap


    【解决方案1】:
    1. 如果map 没有密钥kmap.computeIfAbsent(k, func) 将使用参数k 调用func
    2. functionArrayList::new 接受参数initialCapacity,这将是列表的后备数组的初始大小

    因此,在您的情况下,如果地图中不存在 userId 1000,程序将执行 new ArrayList&lt;&gt;(1000) 以创建由大小为 1000Object[] 支持的 ArrayList。这就是为什么它需要更长的时间并且有时会消耗所有 VM 内存的原因。

    【讨论】:

      猜你喜欢
      • 2013-12-20
      • 2012-09-29
      • 1970-01-01
      • 2011-06-03
      • 2015-12-07
      • 2014-01-03
      • 1970-01-01
      • 1970-01-01
      • 2012-04-08
      相关资源
      最近更新 更多