大家好,又见面了,我是你们的朋友全栈君。
简述
java开发中经常会遇到List去重这个工作,现在就来整理一下List去重的6种方式。
方法代码以及效率测试
模拟测试数据
相关代码:
import java.util.LinkedList;
import java.util.List;
/**
* @ClassName: ListCleatMain
* @Description: 模拟数据进行List去重测试
* @author: ssqxx
* @date: 2020-11-18
* @version 1.0
*/
public class ListCleatMain {
public static void main(String[] args) {
//声明一个新的List
List list = new LinkedList<>();
//数据装载开始时间
Long startTime = System.currentTimeMillis();
System.out.println(“数据装载开始时间:” + startTime);
//模拟添加200000个Integer
for (int i=0;i<200000;i++){
Integer in =(int)(Math.random()*10+1);
list.add(in);
}
//数据装载结束时间
Long endTime = System.currentTimeMillis();
System.out.println(“数据装载结束时间:” + endTime);
//数据装载时差
System.out.println(“数据装载时差:” + (endTime – startTime));
//原数据遍历打印
System.out.println(“原数据:”);
list.forEach( li-> {
System.out.print(li + ” “);
});
System.out.println();
//开始时间
long startClear = System.currentTimeMillis();
System.out.println(“开始时间:” + startClear);
//去重-双for循环去重
List newList = ListClearByDoubleFor.listRemove(list);
//去重-Contains方法去重
// List newList = ListClearByContains.listRemove(list);
//去重-利用HashSet去重
// List newList = ListClearByHashSet.listRemove(list);
//去重-利用TreeSet去重
// List newList = ListClearByTreeSet.listRemove(list);
//去重-利用LinkedHashSet去重
// List newList = ListClearByLinkedHashSet.listRemove(list);
//去重-利用Java8的stream去重
// List newList = ListClearByStream.listRemove(list);
//结束时间
long endClear = System.currentTimeMillis();
System.out.println(“结束时间:” + endClear);
//时间差
System.out.println(“去重用时:” + (endClear – startClear));
//去重后数据遍历打印
System.out.println(“新数据:”);
newList.forEach(li -> {
System.out.print(li + ” “);
});
}
}
双for循环
实现思想:
使用两个for循环遍历集合所有元素,然后进行判断是否有相同元素,如果有,则去除。(有序)
相关代码:
import java.util.List;
/**
* @ClassName: ListClearByDoubleFor
* @Description: 双for循环进行list去重
* @author: ssqxx
* @date: 2020-11-18
* @version 1.0
*/
public class ListClearByDoubleFor {
/**
* 数据去重
* @param list
* @return list
*/
public static List listRemove(List list){
//双for循环进行list去重
for (int i=0; i
for (int j=i+1; j
if (list.get(i).equals(list.get(j))){
list.remove(j);
j–;
}
}
}
return list;
}
}
效率测试:
数据装载开始时间:1605667320390
数据装载结束时间:1605667320407
数据装载时差:17
原数据:
9 8 3 2 3 10 4 9 5 3 1 7 6 8 7 8 9 5 5 8 2 2 ……(20W数据)
开始时间:1605667320811
结束时间:1605667413269
去重用时:92458(这还用再测?)
新数据:
9 8 3 2 10 4 5 1 7 6
————————————————–
它不配!!!!!
List的contains方法
实现思想:
利用List集合contains方法循环遍历,先创建新的List集合,接着循环遍历原来的List集合,判断新集合是否包含有旧集合,如果有,则不添加至新集合,否则添加。(有序)
相关代码:
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName: ListClearByContains
* @Description: 利用List集合contains方法循环遍历去重
* @author: ssqxx
* @date: 2020-11-18
* @version 1.0
*/
public class ListClearByContains {
/**
* 数据去重
* @param list
* @return list
*/
public static List listRemove(List list){
//利用List集合contains方法循环遍历去重
List newList = new ArrayList();
list.forEach(li -> {
//判断新集合是否包含有,如果不包含有,则存入新集合中
if (!newList.contains(li)){
newList.add(li);
}
});
return newList;
}
}
效率测试:
数据装载开始时间:1605674583323
数据装载结束时间:1605674583340
数据装载时差:17
原数据:
8 10 7 3 7 6 6 1 7 6 2 8 9 6 6 5 2 6 5 5 3 1 ……(20W数据)
开始时间:1605674583756
结束时间:1605674583771
去重用时:15/13/13/13/11(5次测试)
新数据:
8 10 7 3 6 1 2 9 5 4
————————————————–
开始时间:1605680194498
结束时间:1605680194553
去重用时:55/57/56/61/64(打印原数据)
去重用时:144/120/127/124/125(不打印原数据)
新数据:
17 3 2 16 13 6 18 1 10 5 11 7 20 9 15 14 12 8 19 4
HashSet方法
实现思想:
HashSet实现了Set接口,不允许出现重复元素。可以基于这个想法,把List集合所有元素存入HashSet对象,接着把List集合元素全部清空,最后把HashSet对象元素全部添加至List集合中,这样就可以保证不出现重复元素。而HashSet有一个构造函数,在初始化时可以直接添加元素。其中,HashSet不能保证顺序不变,所以此方式不能保证List集合原来的顺序不变。 (无序)
相关代码:
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
/**
* @ClassName: ListClearByHashSet
* @Description: List集合放入HashSet中利用HashSet实现Set接口的无重复元素特性去重
* @author: ssqxx
* @date: 2020-11-18
* @version 1.0
*/
public class ListClearByHashSet {
/**
* 数据去重
* @param list
* @return list
*/
public static List listRemove(List list){
//List集合放入HashSet中利用HashSet实现Set接口的无重复元素特性去重
HashSet set = new HashSet(list);
list.clear();
list.add(set);
// Iterator it = set.iterator();
// while (it.hasNext()){
// list.add(it.next());
// }
return list;
}
}
效率测试:
数据装载开始时间:1605675392758
数据装载结束时间:1605675392776
数据装载时差:18
原数据:
3 6 1 1 7 6 9 2 8 6 4 7 1 9 5 5 4 3 3 1 10 8 10 10……(20w数据)
开始时间:1605675393184
结束时间:1605675393200
去重用时:16/20/15/12/15(5次测试)
新数据:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
————————————————–
开始时间:1605680088596
结束时间:1605680088641
去重用时:45/45/46/52/44(打印原数据)
去重用时:167/163/160/164/166(不打印原数据)
新数据:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
TreeSet方法
实现思想:
TreeSet集合也是实现Set接口,是一个有序的,并且无重复元素集合。(有序)
相关代码:
import java.util.*;
/**
* @ClassName: ListClearByTreeSet
* @Description: List集合放入TreeSet中利用HashSet实现Set接口的无重复元素特性去重
* @author: ssqxx
* @date: 2020-11-18
* @version 1.0
*/
public class ListClearByTreeSet {
/**
* 数据去重
* @param list
* @return list
*/
public static List listRemove(List list){
//List集合放入TreeSet中利用HashSet实现Set接口的无重复元素特性去重
TreeSet set = new TreeSet(list);
list.clear();
list.add(set);
// Iterator it = set.iterator();
// while (it.hasNext()){
// list.add(it.next());
// }
return list;
}
}
效率测试:
数据装载开始时间:1605675683470
数据装载结束时间:1605675683487
数据装载时差:17
原数据:
8 10 4 3 8 10 8 2 1 9 1 3 1 1 8 3 4 4 10 6 6 2……(20W数据)
开始时间:1605675683881
结束时间:1605675683909
去重用时:28/25/29/26/26(5次测试)
新数据:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
————————————————–
开始时间:1605679953606
结束时间:1605679953697
去重用时:91/94/104/103/101(打印原数据)
去重用时:112/119/123/113/117(不打印原数据)
新数据:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
LinkedHashSet方法
实现思想:
LinkedHashSet是一个实现Set接口将ArrayList删除重复数据的最佳方法。LinkedHashSet在内部完成两件事:删除重复数据,保持添加到其中的数据的顺序。(有序)
相关代码:
import java.util.*;
/**
* @ClassName: ListClearByLinkedHashSet
* @Description: List集合放入LinkedHashSet中利用LinkedHashSet实现Set接口的无重复元素特性去重
* @author: ssqxx
* @date: 2020-11-18
* @version 1.0
*/
public class ListClearByLinkedHashSet {
/**
* 数据去重
* @param list
* @return list
*/
public static List listRemove(List list){
//List集合放入LinkedHashSet中利用LinkedHashSet实现Set接口的无重复元素特性去重
LinkedHashSet hashSet = new LinkedHashSet(list);
list.clear();
list.add(hashSet);
// Iterator iterator = hashSet.iterator();
// while(iterator.hasNext()){
// list.add(iterator.next());
// }
return list;
}
}
效率测试:
数据装载开始时间:1605675839400
数据装载结束时间:1605675839417
数据装载时差:17
原数据:
2 7 5 1 4 4 1 5 1 9 10 7 3 9 7 3 6 7 1 1 4……(20W数据)
开始时间:1605675839818
结束时间:1605675839835
去重用时:17/16/14/17/19(5次测试)
新数据:
[2, 7, 5, 1, 4, 9, 10, 3, 6, 8]
————————————————–
开始时间:1605679823889
结束时间:1605679823938
去重用时:49/43/42/42/44(打印原数据)
去重用时:173/159/160/163/169(不打印原数据)
新数据:
[12, 1, 9, 6, 3, 8, 19, 13, 5, 16, 2, 10, 11, 15, 17, 4, 7, 20, 14, 18]
Java8的stream方法
实现思想:
要从arraylist中删除重复项,我们也可以使用java 8 stream api。使用steam的distinct()方法返回一个由不同数据组成的流,通过对象的equals()方法进行比较。 (有序)
相关代码:
import java.util.List;
import java.util.stream.Collectors;
/**
* @ClassName: ListClearByStream
* @Description: 使用java8新特性stream实现List去重
* @author: ssqxx
* @date: 2020-11-18
* @version 1.0
*/
public class ListClearByStream {
/**
* 数据去重
* @param list
* @return list
*/
public static List listRemove(List list){
//使用java8新特性stream实现List去重
List newList = (List) list.stream().distinct().collect(Collectors.toList());
return newList;
}
}
效率测试:
数据装载开始时间:1605679132825
数据装载结束时间:1605679132841
数据装载时差:16
原数据:
7 3 4 6 5 2 7 8 5 6 7 4 3 8 6 5 2 4 5 5 2 10 2……(20W数据)
开始时间:1605679133233
结束时间:1605679133248
去重用时:15/14/13/19/16(5次测试)
新数据:
7 3 4 6 5 2 8 10 9 1
————————————————–
开始时间:1605679582415
结束时间:1605679582443
去重用时:28/31/35/27/31(打印原数据)
去重用时:94/81/96/96/87(不打印原数据)
新数据:
8 15 4 3 17 1 10 19 12 9 16 20 7 6 18 13 2 5 14 11
结论
随机数在200000范围10以内(平均值):
使用两个for循环实现List去重:94258毫秒
使用List集合contains方法循环遍历去重时间:13毫秒
使用HashSet实现List去重时间:16毫秒
使用TreeSet实现List去重时间:27毫秒
使用LinkedHashSet实现List去重时间:17毫秒
使用java8新特性stream实现List去重:15毫秒
随机数在2000000范围20以内(平均值):
使用两个for循环实现List去重:已放弃!!!!
使用List集合contains方法循环遍历去重时间:128毫秒
使用HashSet实现List去重时间:164毫秒
使用TreeSet实现List去重时间:117毫秒
使用LinkedHashSet实现List去重时间:165毫秒
使用java8新特性stream实现List去重:91毫秒
随机数在20000000范围20以内(一次值):
使用两个for循环实现List去重:已放弃!!!!
使用List集合contains方法循环遍历去重时间:612毫秒
使用HashSet实现List去重时间:334毫秒
使用TreeSet实现List去重时间:813毫秒
使用LinkedHashSet实现List去重时间:364毫秒
使用java8新特性stream实现List去重:214毫秒
结论简述:
目前表现最好的是java8新特性stream实现的list去除,不论是数据量大小;
HashSet、TreeSet、LinkedHashSet都有实现Set接口,所以速度都不会很慢,但是在过了1000W这个数量的list后去重速度骤降,HashSet,LinkedHashSet依旧稳定快速;整体上HashSet>LinkedHashSet>TreeSet。不过HashSet是无序的,若想有序可以使用LinkedHashSet;
list集合的contains方法在数据量不大的时候能去重速度也挺快的,甚至能超过HashSet,但数据量大(500W)之后,去重速度骤降,数据量不大的list去重可以使用;
双for循环进行list去重就……算了,放弃吧!
整体排序:
500W数据以下:
(有序)stream>contains>LinkedHashSet>TreeSet>for
(无序)stream>contains>HashSet>LinkedHashSet>TreeSet>for
500W数据以上:
(有序)stream>LinkedHashSet>contains>TreeSet>for
(无序)stream>HashSet>LinkedHashSet>contains>TreeSet>for
以上数据为自测数据,可能与实际应用会存在误差,下次再测试一下String(字符串)的list排序。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/141516.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...