使用收集器使用临时变量

时间:2017-08-17 05:16:35

标签: java stream garbage-collection

我有以下代码。我试图了解它是否会对内存进行任何更改。

方法1:使用收藏家我可以直接返回地图:

    List<Customer> customerList = new ArrayList<>();
    customerList.add(new Customer("1", "pavan"));
    customerList.add(new Customer("2", "kumar"));

    return customerList.stream().collect(Collectors.toMap(t->t.getId(), t->t));

方法2:使用显式地图收集结果,如下所示:

   Map<String,Customer> map = new HashMap<String, Customer>();  
   map = customerList.stream().collect(Collectors.toMap(t->t.getId(), t->t));       
   return map;

与第一种方法相比,如果我迭代超过一百万次,第二种方法对内存/ GC有什么影响吗?

3 个答案:

答案 0 :(得分:1)

除了在第二个示例中实例化您不需要的Map实例之外,两段代码都是相同的。您立即将您创建的Map引用替换为流返回的Map引用。编译器很可能会将其作为冗余代码消除。

streams API的collect方法将为您实例化Map;代码已经过很好的优化,这是使用Stream API而不是自己做的优势之一。

要回答您的具体问题,您可以根据需要多次迭代这两段代码,这对GC的影响不会产生任何影响。

答案 1 :(得分:1)

到目前为止代码并不完全相同;具体而言Collectors.toMap表示会返回Map

  

无法保证返回的地图的类型,可变性,可串行性或线程安全性。

绝对不能保证返回的Map 实际上HashMap。它可能是其他任何东西 - 任何其他Map在这里;所以将它分配给HashMap是错误的。

然后就是构建Collector的方式。它可以简化为:

customerList.stream().collect(Collectors.toMap(Customer::getId, Function.identity()));

与lambda表达式相反,方法引用Customer::getId将创建一个较少的方法(因为lambda表达式不依赖于方法和方法引用)。

如果在多个地方使用,Function.identity()而非t -> t也会创建 less 对象。阅读this

然后有HashMap内部如何运作的事实。如果您没有指定default size,则可能需要重新调整大小 - 这是一项昂贵的操作。 默认情况下 Collectors.toMap将以16个条目的默认 Mapload_factor的{​​{1}}开头 - 这意味着你可以在下一次调整大小之前输入12个条目。

您不能使用0.75省略它,因为它的供应商总是从Collectors.toMap开始 - 使用默认的16个条目和0.75的load_factor。

知道这一点,你可以完全放弃流:

HashMap::new

答案 2 :(得分:0)

在第二种方法中,您将实例化Map,并将引用重新分配给对stream.collect()调用返回的引用。 显然,&#34; map&#34;引用的第一个Map对象;失去了。

第一种方法没有这个问题。

简而言之,是的,这在内存使用方面略有不同,但考虑到你有一百万个条目可以迭代,它可能是微不足道的。