当前位置: 首页 > 科技观察

项目里用到 Java 集合时,应该避免的一些坑

时间:2023-03-22 11:06:52 科技观察

在本文的项目中使用Java集合时应避免的一些陷阱。ArrayList踩坑Listtemp=newArrayList();//获取一批数据Listall=getData();for(Stringstr:all){temp.add(str);}首先我们看看这段代码有什么问题?事实上,在大多数情况下,这并没有错。无非是循环往ArrayList中写入数据。但是在特殊情况下,比如这里getData()返回的数据非常大的时候,后面的temp.add(str)就会出现问题。比如我们在查看代码的时候,发现这里返回的数据有时候可以高达2000W。这时候ArrayList里面写的问题就凸显出来了。大家都知道ArrayList是用数组实现的,数据的长度是有限制的;需要适时扩充阵法。这里以最后插入为例add(Ee)。ArrayListtemp=newArrayList<>(2);temp.add("1");temp.add("2");temp.add("3");当我们初始化一个长度为2的ArrayList,并在里面写入三段数据时,ArrayList就得进行扩容,即将之前的数据复制到一个长度为3的新数组中。之所以是3是因为新的长度=原来的长度*1.5从源码中我们可以知道ArrayList的默认长度是10。但实际上DEFAULT_CAPACITY=10的数组在初始化的时候并没有创建。而是在里面添加第一个数据的时候,会扩充到10。现在我们知道了默认长度是10,也就是说,一旦写入第9个元素,就会扩充到10*1.5=15。这一步就是数组复制,也就是开辟一个新的内存空间来存放这15个数组。一旦频繁大量写入,就会导致数组副本很多,效率极低。但是如果我们提前预测可能会写入多少条数据,就可以提前避免这个问题。比如我们往里面写入1000W条数据,初始化时给定的数组长度和默认长度10有很大的性能差距。我用JMHbenchmark验证如下:@Warmup(iterations=5,时间=1,timeUnit=TimeUnit.SECONDS)@Measurement(iterations=5,time=1,timeUnit=TimeUnit.SECONDS)publicclassCollectionsTest{privatestaticfinalintTEN_MILLION=10000000;@Benchmark@BenchmarkMode(Mode.AverageTime)@OutputTimeUnit(TimeUnit.MICROSECONDS)publicvoidarrayList(){Listarray=newArrayList<>();for(inti=0;iarray=newArrayList<>(TEN_MILLION);for(inti=0;iarray=newLinkedList<>();for(inti=0;i