[改善Java代码]非稳定排序推荐使用List
我们知道Set与List的最大区别就是Set中的元素不可以重复(这个重复指的equals方法的返回值相等),其他方面则没有太大的区别了,在Set的实现类中有一个比较常用的类需要了解一下:TreeSet,该类实现了类默认排序为升序的Set集合,如果插入一个元素,默认会按照升序排列(当然是根据Comparable接口的compareTo的返回值确定排序位置了),不过,这样的排序是不是在元素经常变化的场景中也适用呢?我们来看例子:
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代码]非稳定排序推荐使用List的更多相关文章
- [改善Java代码]对字符串排序 持一种宽容的心态
在Java中一涉及到中文处理就会冒出很多的问题来,其中的排序也是一个让人头疼的问题,看代码: import java.util.Arrays; public class Client { public ...
- 拔高你的Java代码质量吧:推荐使用枚举定义常量(转)
提高你的Java代码质量吧:推荐使用枚举定义常量 一.分析 常量的声明是每一个项目中不可或缺的,在Java1.5之前,我们只有两种方式的声明:类常量和接口常量.不过,在1.5版之后有了改进,即新增了一 ...
- [改善Java代码]易变业务使用脚本语言编写
建议16: 易变业务使用脚本语言编写 Java世界一直在遭受着异种语言的入侵,比如PHP.Ruby.Groovy.JavaScript等,这些“入侵者”都有一个共同特征:全是同一类语言—脚本语言,它们 ...
- [改善Java代码]推荐使用枚举定义常量
枚举和注解都是在Java1.5中引入的,虽然他们是后起之秀,但是功能不容小觑,枚举改变了常量的声明方式,注解耦合了数据和代码. 建议83:推荐使用枚举定义常量 一.分析 常量的声明是每一个项目中不可或 ...
- [改善Java代码]推荐在复杂字符串操作中使用正则表达式
一.分析 字符串的操作,诸如追加.合并.替换.倒序.分隔等,都是在编码过程中经常用到的,而且Java也提供了append.replace.reverse.split等方法来完成这些操作,它们使用起来 ...
- [改善Java代码]不推荐使用binarySearch对列表进行检索
对一个列表进行检索时,我们使用的最多的是indexOf方法,它简单好用,而且也不会出错,虽然它只能检索到第一个符合条件的值,但是我们可以生成子列表后再检索.这样也就可以查找到所有符合条件的值了. Co ...
- [改善Java代码]推荐覆写toString方法
建议49: 推荐覆写toString方法 为什么要覆写toString方法,这个问题很简单,因为Java提供的默认toString方法不友好,打印出来看不懂,不覆写不行,看这样一段代码: public ...
- [改善Java代码] 避免instanceof非预期结果
建议18: 避免instanceof非预期结果 instanceof是一个简单的二元操作符,它是用来判断一个对象是否是一个类实例的,其操作类似于>=.==,非常简单,我们来看段程序,代码如下: ...
- [改善Java代码] 推荐使用序列化实现对象的拷贝
建议44: 推荐使用序列化实现对象的拷贝 上一个建议说了对象的浅拷贝问题,实现Cloneable接口就具备了拷贝能力,那我们来思考这样一个问题:如果一个项目中有大量的对象是通过拷贝生成的,那我们该如何 ...
随机推荐
- sass学习(2)——关于变量
定义一个sass变量 可以说,变量是一个编程语言的基础.所以对于sass来说,变量肯定是浓墨重彩的其中一笔,当然函数也是.那我们如何声明定义一个sass的变量呢? 变量的符号$ 变量名称 变量的值 那 ...
- stdlib.h 头文件
stdlib 头文件即standard library标准库头文件.stdlib.h里面定义了五种类型.一些宏和通用工具函数. 类型例如size_t.wchar_t.div_t.ldiv_t和lldi ...
- POJ3278http://poj.org/problem?id=3278
http://poj.org/problem?id=3278 题目大意: m,n两个数m可+1, -1, *2变成n,需要经过几步 #include<stdio.h> #include&l ...
- baseadapter.getItemId的使用方法:实现listview筛选、动态删除
转载:http://www.lai18.com/content/1631131.html 这里的listview筛选是指listview的adapter实现filter来过滤数据. “动态删除&quo ...
- Unity3D行为树插件Behave学习笔记
Behave1.4行为树插件 下载地址:http://pan.baidu.com/s/1i4uuX0L 安装插件和使用 我们先来看看插件的安装和基本使用方法,新建一个Unity3D项目,这里我使用的是 ...
- C# 创建移动应用
打开VS2013 选择ASP.NET MVC4Web应用程序,点击[确定] 选择[移动应用程序]点击[确定],运行之后显示的效果如图
- PI-webservice05-SAP调用外部webservice
在用webservice进行数据传输的过程中,SAP系统与.net开发的信息系统之间的数据调用.如何用SAP调用外部的.net系统发布的webservice程序来获取外部的数据,详情请见下文: 1,创 ...
- angularjs入门学习【应用剖析中篇】
在上一节讲完了关于应用开发中如数据绑定,加入样式一类的基础操作后,接下来,将在应用中,与控制其有关的一些事件... 一.UI和控制器的分离 我们须要明白控制器在应用中的三个作用: [1]在应用模型中设 ...
- 发布站点到远程FTP根目录
第一步:修改 phpcms/modules/admin/templates/site_add.tpl.php 找到 <legend><?php echo L('release_poi ...
- Swift3.0语法变化
写在前面 首先和大家分享一下学习新语法的技巧:用Xcode8打开自己的Swift2.3的项目,选择Edit->Convert->To Current Swift Syntax- 让Xcod ...