[改善Java代码]非稳定排序推荐使用List
2016-07-11 14:43
369 查看
我们知道Set与List的最大区别就是Set中的元素不可以重复(这个重复指的equals方法的返回值相等),其他方面则没有太大的区别了,在Set的实现类中有一个比较常用的类需要了解一下:TreeSet,该类实现了类默认排序为升序的Set集合,如果插入一个元素,默认会按照升序排列(当然是根据Comparable接口的compareTo的返回值确定排序位置了),不过,这样的排序是不是在元素经常变化的场景中也适用呢?我们来看例子:
程序输出:
这没有问题,随着时间的推移,身高175cm的人长高了10cm,而180cm却保持不变,那排序的位置应该改变一下吧,看代码(只需修改main方法):
程序输出:
很可惜,竟然没有重新排序,偏离了我们的预期。这正是下面要说明的问题,SortedSet接口(TreeSet实现了该接口)只是定义了在给集合加入元素时将其进行排序,并不能保证元素修改后的排序结果,因此TreeSet使用于不变量的集合数据排序,比如String、Integer等类型,但不适用于可变量的排序,特别是不确定何时元素会发生变化的数据集合。
原因知道了,那如何解决此类重排序问题呢?有两种方式:
(1).Set集合重排序
重新生成一个Set对象,也就是对原有的Set对象重排序,代码如下:
程序输出:
就一句话即可重新排序。可能有读者会问,使用TreeSet(SortedSet< E > s)这个构造函数不是可以更好地解决问题吗?不行,该构造函数只是原Set的浅拷贝,如果里面有相同的元素,是不会重新排序的。
(2).彻底重构掉TreeSet,使用List解决问题
我们之所以使用TreeSet是希望实现自动排序,即使修改也能自动排序,既然它无法实现,那就用List来代替,然后再使用Collections.sort()方法对List排序.看代码:
程序输出:
两种方法都可以解决我们的困境,到底哪一个是最优的呢?对于不变量的排序,例如直接量(也就是8个基本类型)、String类型等,推荐使用TreeSet,而对于可变量,例如我们自己写的类,可能会在逻辑处理中改变其排序关键值的,则建议使用List自行排序。
又有问题了,如果需要保证集合中元素的唯一性,又要保证元素值修改后排序正确,那该如何处理呢?List不能保证集合中的元素唯一,它是可以重复的,而Set能保证元素唯一,不重复。如果采用List解决排序问题,就需要自行解决元素重复问题(若要剔除也很简单,转变为HashSet,剔除后再转回来)。若采用TreeSet,则需要解决元素修改后的排序问题,孰是孰非,就需要根据具体的开发场景来决定了。
import java.util.SortedSet; import java.util.TreeSet; public class Client { public static void main(String[] args) { SortedSet<Person> set = new TreeSet<Person>(); //身高180CM set.add(new Person(180)); //身高175CM set.add(new Person(175)); for(Person p:set){ System.out.println("身高:"+p.getHeight()); } } static class Person implements Comparable<Person>{ //身高 private int height; public Person(int _age){ height = _age; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } //按照身高排序 public int compareTo(Person o) { return height - o.height; } } }
程序输出:
身高:175 身高:180
这没有问题,随着时间的推移,身高175cm的人长高了10cm,而180cm却保持不变,那排序的位置应该改变一下吧,看代码(只需修改main方法):
public static void main(String[] args) { SortedSet<Person> set = new TreeSet<Person>(); // 身高180CM set.add(new Person(180)); // 身高175CM set.add(new Person(175)); // 身高最矮的人大变身 set.first().setHeight(185); for (Person p : set) { System.out.println("身高:" + p.getHeight()); } }
程序输出:
身高:185 身高:180
很可惜,竟然没有重新排序,偏离了我们的预期。这正是下面要说明的问题,SortedSet接口(TreeSet实现了该接口)只是定义了在给集合加入元素时将其进行排序,并不能保证元素修改后的排序结果,因此TreeSet使用于不变量的集合数据排序,比如String、Integer等类型,但不适用于可变量的排序,特别是不确定何时元素会发生变化的数据集合。
原因知道了,那如何解决此类重排序问题呢?有两种方式:
(1).Set集合重排序
重新生成一个Set对象,也就是对原有的Set对象重排序,代码如下:
import java.util.ArrayList; import java.util.SortedSet; import java.util.TreeSet; public class Client { public static void main(String[] args) { SortedSet<Person> set = new TreeSet<Person>(); // 身高180CM set.add(new Person(180)); // 身高175CM set.add(new Person(175)); // 身高最矮的人大变身 set.first().setHeight(185); //set重排序 set = new TreeSet<Person>(new ArrayList<Person>(set)); //set = new TreeSet(set);该构造函数只是原Set的浅拷贝,如果里面有相同的元素,是不会重新排序的 for (Person p : set) { System.out.println("身高:" + p.getHeight()); } } static class Person implements Comparable<Person> { // 身高 private int height; public Person(int _age) { height = _age; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } // 按照身高排序 public int compareTo(Person o) { return height - o.height; } } }
程序输出:
身高:180 身高:185
就一句话即可重新排序。可能有读者会问,使用TreeSet(SortedSet< E > s)这个构造函数不是可以更好地解决问题吗?不行,该构造函数只是原Set的浅拷贝,如果里面有相同的元素,是不会重新排序的。
(2).彻底重构掉TreeSet,使用List解决问题
我们之所以使用TreeSet是希望实现自动排序,即使修改也能自动排序,既然它无法实现,那就用List来代替,然后再使用Collections.sort()方法对List排序.看代码:
import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.TreeSet; public class Client { public static void main(String[] args) { List<Person> list = new ArrayList<Person>(); // 身高180CM list.add(new Person(180)); // 身高175CM list.add(new Person(175)); // 身高最矮的人大变身 list.get(1).setHeight(185); //排序 Collections.sort(list); for (Person p : list) { System.out.println("身高:" + p.getHeight()); } } static class Person implements Comparable<Person> { // 身高 private int height; public Person(int _age) { height = _age; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } // 按照身高排序 public int compareTo(Person o) { return height - o.height; } } }
程序输出:
身高:180 身高:185
两种方法都可以解决我们的困境,到底哪一个是最优的呢?对于不变量的排序,例如直接量(也就是8个基本类型)、String类型等,推荐使用TreeSet,而对于可变量,例如我们自己写的类,可能会在逻辑处理中改变其排序关键值的,则建议使用List自行排序。
又有问题了,如果需要保证集合中元素的唯一性,又要保证元素值修改后排序正确,那该如何处理呢?List不能保证集合中的元素唯一,它是可以重复的,而Set能保证元素唯一,不重复。如果采用List解决排序问题,就需要自行解决元素重复问题(若要剔除也很简单,转变为HashSet,剔除后再转回来)。若采用TreeSet,则需要解决元素修改后的排序问题,孰是孰非,就需要根据具体的开发场景来决定了。
相关文章推荐
- java打印二维数组
- Java FTP上传文件工具类
- MySql三表联查(Spring+SpringMVC+MyBatis)
- Java GC 原理
- [改善Java代码]多线程使用Vector或HashTable
- 用JDK自带的包来解析XML文件(DOM+xpath)
- [改善Java代码]减少HashMap中元素的数量
- Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)
- java二分法查找
- java自学篇之数组2
- [改善Java代码]使用shuffle打乱列表
- [改善Java代码]集合运算时使用更优雅的方式
- java自学篇之数组1
- Java基础——使用json所要用到的jar包下载
- [改善Java代码]集合中的元素必须做到compareTo和equals同步
- HeadFirstJava——8_接口与抽象类
- java接口的实现
- [改善Java代码]不推荐使用binarySearch对列表进行检索
- 深入剖析Java中的装箱和拆箱
- [改善Java代码]使用Comparator进行排序