说明:这是在面试中面试官出的题。虽然是常见的优化问题,但这种经验的确很有用。感慨之余,分享出来,以此共勉。

场景:现有List<PersonA>,List<PersonB>,PersonA 的属性是 String类型的身份证号,int型age;PersonB 的属性是 String类型的身份证号,int型sex;两个集合中的身份证号有相同的;

需求:查找身份证号相同的人的性别。

常见的思路是:

 @Data
public class PersonA {
private String card;
private int age; public PersonA(String card, int age) {
this.card = card;
this.age = age;
}
}
----------------------------------------------
@Data
public class PersonB {
private String card;
private int sex; public PersonB(String card, int sex) {
this.card = card;
this.sex = sex;
}
}
public class TestForFor {
private List<PersonA> pa;
private List<PersonB> pb;
@Before
public void before(){
pa = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
pa.add(new PersonA(UUID.randomUUID().toString(),20));
}
pa.add(new PersonA("abcd111",10));
pa.add(new PersonA("abcd112",10));
pa.add(new PersonA("abcd113",10));
pa.add(new PersonA("abcd114",10));
pa.add(new PersonA("abcd115",10));
pa.add(new PersonA("abcd116",10));
pb = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
pb.add(new PersonB(UUID.randomUUID().toString(),Math.random() >= 0.5 ? 1 : 0));
}
pb.add(new PersonB("abcd111",1));
pb.add(new PersonB("abcd112",1));
pb.add(new PersonB("abcd113",1));
pb.add(new PersonB("abcd114",1));
pb.add(new PersonB("abcd115",1));
pb.add(new PersonB("abcd116",1));
}
@Test
public void testFor(){
out.println("start search");
for (PersonA a : pa) {
for (PersonB b : pb) {
if (a.getCard().equals(b.getCard())){
out.println(b.getSex()==1?"男":"女");
}
}
}
}
}

结果。。。花费三秒多的时间。这还只是一万条数据

现在换一种思路,直接贴代码

  private List<PersonA> pa;
private List<PersonB> pb;
private Map<String,Object> map;
@Before
public void before(){
out.println("start before");
pa = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
pa.add(new PersonA(UUID.randomUUID().toString(),20));
}
pa.add(new PersonA("abcd111",10));
pa.add(new PersonA("abcd112",10));
pa.add(new PersonA("abcd113",10));
pa.add(new PersonA("abcd114",10));
pa.add(new PersonA("abcd115",10));
pa.add(new PersonA("abcd116",10)); pb = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
pb.add(new PersonB(UUID.randomUUID().toString(),Math.random() >= 0.5 ? 1 : 0));
}
pb.add(new PersonB("abcd111",1));
pb.add(new PersonB("abcd112",1));
pb.add(new PersonB("abcd113",1));
pb.add(new PersonB("abcd114",1));
pb.add(new PersonB("abcd115",1));
pb.add(new PersonB("abcd116",1));
map = new HashMap<>();
for ( PersonB pbb : pb ) {
map.put(pbb.getCard(),pbb.getSex());
}
}
@Test
public void testFor(){
out.println("start search");
for (PersonA a : pa) {
if (map.containsKey(a.getCard())){
out.print(a.getAge()+" ");
out.println((int)map.get(a.getCard())==1?"男":"女");
}
//out.println(map.get(a.getCard())==null?"空":map.get(a.getCard()));
//out.println((int)map.get(a.getCard())==1?"男":"女");
}
}

可以看出,查找的效率明显提升。

这里面的重点,第29行我用map重新填写了pb的数据[我的本地的sql坏了,所以用伪数据库的方式模仿,感兴趣也可以从数据库里试试],

为什么用map填完了后速度会这么快?

原因很简单。因为ArrayList的底层是数组实现的,若要查找必定是从索引0开始一个个的进行比对;而HashMap则不同,

HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度依然为O(1),因为最新的Entry会插入链表头部,仅需要简单改变引用链即可,而对于查找操作来讲,此时就需要遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。

关于以上加粗内容取自博客

我在面试时只想到了hash,面试官提醒我用hashmap,恍然大悟。


时隔数月,回来归纳下这个问题。2018/9/13


其实这个问题可以抽象为:两个数组求交集,这里简要说下思路。

使用 treeset装载第一个数组,遍历第二个数组,if(!contains数组二中的值),add到一个新list中,最后这个list存的就是交集

原创分享,转载标注。

java遍历的优化的更多相关文章

  1. 35 个 Java 代码性能优化总结

    前言 代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用, ...

  2. Java的性能优化

    http://www.toutiao.com/i6368345864624144897/?tt_from=mobile_qq&utm_campaign=client_share&app ...

  3. Java 代码性能优化总结

    前言 代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用, ...

  4. Java代码性能优化总结

    代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用,但是, ...

  5. [JAVA] java程序性能优化

    一.避免在循环条件中使用复杂表达式 在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快. 例子: import java.util ...

  6. java常用重构优化总结--自己亲身体验

    代码重构  6大原则:    单一职责原则(一个类最好最好只有一种行为动机,太多承担职责会导致耦合度太高).    开放封闭原则(功能可以扩展,但是不可以内部修改).    依赖倒转原则(应该依赖抽象 ...

  7. Java 代码性能优化

    代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用,但是, ...

  8. 小细节,大用途,35 个 Java 代码性能优化总结!

    前言: 代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用 ...

  9. 来自极客头条的 35 个 Java 代码性能优化总结

    前言 代码优化,一个很重要的课题.可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,就像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用, ...

随机推荐

  1. MyEclipse中Lombok的安装及使用

    lombok是一款通过注解的形式简化我们必须有又显得臃肿的代码的工具.最常用的就是@Data注解.实体类上用了这个注解,实体类的各个属性就不需要书写get和set方法. 安装步骤: 1.关闭Myecl ...

  2. CSS常用字体名称

    CSS样式中常用的字体名称   css中引入字体: @font-face { font-family: "AncientWar"; src: url('style/css/font ...

  3. tomcat无法打开8080页面

    tomcat已启动 app已经正常执行 但不能打开8080管理页面 可能是在webapps目录下没有ROOT目录

  4. tomcat中session在两个webapp中实现共享

    现在遇到一个需求就是要求完成简单的单点登录,通过在一个tomcat实例中放置两个webapps应用ROOT应用和CEO应用来完成在ROOT应用登录后,在CEO可以直接使用,而未在ROOT应用登录时,不 ...

  5. 使用H2数据库进行单元测试

    背景 H2 数据库是一个开源的嵌入型内存数据库,采用纯Java语言实现: 程序非常小巧轻便,整个完整的Jar包也只有1.5M左右,很容易集成到项目中. 官网地址 http://www.h2databa ...

  6. 【原创】源码角度分析Android的消息机制系列(四)——MessageQueue的工作原理

    ι 版权声明:本文为博主原创文章,未经博主允许不得转载. MessageQueue,主要包含2个操作:插入和读取.读取操作会伴随着删除操作,插入和读取对应的方法分别为enqueueMessage和ne ...

  7. Android util.Log 工具类

    Android中的日志工具类是Log(android.util.Log),这个类中提供了如下5个方法来供我们打印日志. Log.v().用于打印那些最为琐碎的.意义最小的日志信息.对应级别verbos ...

  8. java之拦截器Interceptor

    1,拦截器的概念    java里的拦截器是动态拦截Action调用的对象,它提供了一种机制可以使开发者在一个Action执行的前后执行一段代码,也可以在一个Action执行前阻止其执行,同时也提供了 ...

  9. windows下cmd常用

    windows下cmd常用 shutdown -s -t 2------2秒后关机 加上-f选项意思是强制执行 shutdown -r -t 2------2秒后重启 加上-f选项意思是强制执行 lo ...

  10. 让浏览器全面兼容WebP图片格式

    WebP格式 WebP是Google推出的一种图片格式,它基于VP8编码,可对图像大幅压缩.与JPEG相同,WebP也是一种有损压缩,但在画质相同的情况下,WebP格式比JPEG图像小40%. Wik ...