ArrayList的contains性能问题与解决方案

项目中经常会通过集合的contains方法来检查某个对象是否存在。ArrayList是集合中使用频率最高的,因此大家习惯性的会直接使用ArrayList的contains方法做检查。

当元素数量较少时对性能没有任何影响,但当操作上十万百万元素时,性能问题便凸显出来。ArrayList的contains方法效率非常低下,此时我们最简单的优化方案便是

使用HashSet的contains方法取代,下方是测试代码,通过最终的测试结果显示,两者的效率差距上百倍。

 

分析其原理:

ArraysList的contains方法是采用indexOf遍历数据的方式判断存在性,当元素非常多时,这种方式方式非常低,时间复杂度为o(n);

HashSet的contains方法是采用HashMap的containsKey方法,根据key计算hash值,然后取对应链表判断存在性,时间复杂度为o(1),效率比ArrayList高很多。

 

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.junit.Assert;

import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class ContainsTest {
    public static void main(String[] args) {
        int COUNT = 20000000;
        List<Element> elementList = new ArrayList<>(COUNT);
        Set<Element> elementSet = new HashSet<>(COUNT);
        for (int i = 0; i < COUNT; i++) {
            Element element = new Element(i, "name" + i);
            elementList.add(element);
            elementSet.add(element);
        }
        //
        Element element = new Element(COUNT - 1, "name" + (COUNT - 1));
        Instant start = null;
        boolean contains = false;
        //
        start = Instant.now();
        contains = elementSet.contains(element);
        Assert.assertTrue(contains);
        System.out.println(String.format("set contains method elapsed time[%s]ms", Duration.between(start, Instant.now()).toMillis()));
        //
        start = Instant.now();
        contains = elementList.contains(element);
        Assert.assertTrue(contains);
        System.out.println(String.format("list contains method elapsed time[%s]ms", Duration.between(start, Instant.now()).toMillis()));
    }

    static class Element {
        int id;
        String name;

        public Element(int id, String name) {
            this.id = id;
            this.name = name;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;

            if (o == null || getClass() != o.getClass()) return false;

            Element element = (Element) o;

            return new EqualsBuilder()
                    .append(id, element.id)
                    .append(name, element.name)
                    .isEquals();
        }

        @Override
        public int hashCode() {
            return new HashCodeBuilder(17, 37)
                    .append(id)
                    .append(name)
                    .toHashCode();
        }
    }
}

set contains method elapsed time[2]ms
list contains method elapsed time[334]ms
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值