前言
前两天写了个双色球生成器,把代码一亮,好多朋友就问了,你这样嵌套性能不就很低了么?
拜托大哥,我生成1000万个,你也不一定都买了呀,够需求就行了;
但是还是有求必应吧!请看↓
十行写个彩票随机生成器(双色球+大乐透)
开始操作
诉求
集合去重在目标数量比较大的时候效率低下,极大可能还会让服务器宕机(偷偷告诉你其实这就是我前几天线上出的问题 ),有什么办法可以高效且优雅 的完成任务么?
先看原代码↓
优化前
public static <T> List<T> distinctI(List<T> list){
if (list == null){
return null;
}else {
List<T> result = new ArrayList<>();
for (T item : list){
if (!result.contains(item)){
result.add(item);
}
}
return result;
}
}
这里是使用List的contains判断目标数组中是否有该元素,如果看不出有何问题的话,请继续往下看。
优化后
public static <T> List<T> distinctII(List<T> list){
if (list ==null){
return null;
}else {
List<T> result = new ArrayList<>(new HashSet<>(list));
return result;
}
}
对比
优化前
数据量 | 耗时(毫秒) |
---|---|
10000 | 118 |
100000 | 5885 |
1000000 | 482137 |
优化后
数据量 | 耗时(毫秒) |
---|---|
1000000 | 678 |
解析
当使用contains方法时,判断result中是否有item元素,如果没有就将item[i] add到result集合中去,这样虽然完成了功能的实现,但是随着并发量逐渐增大的时候,它的时间复杂度就会上升为(n^2)/2(数据量的时候contains方法的执行会导致大量的线程资源被占用,你懂得!)
n的值 | 遍历次数 |
---|---|
10000 | 5000万 |
100000 | 50亿 |
1000000 | 5000亿 |
so!
小结
回去查查代码中是不是有类似的情况,有的话赶紧亡羊补牢吧
另外还有
- HashSet: 可以去重,但不能排序
- TreeSet: 既可去重,又可以排序(默认为升序)
- Stream: 既可去重,又可以排序(代码简洁且高效)
详细解读请移步:Java8 Stream链式表达式:去重+排序