本文由 ImportNew - 温布利往事 翻译自 dzone。欢迎加入翻译小组。转载请见文末要求。

由于其功能性和灵活性,ArrayList是 Java 集合框架中使用最为普遍的集合类之一。ArrayList 是一种 List 实现,它的内部用一个动态数组来存储元素,因此 ArrayList 能够在添加和移除元素的时候进行动态的扩展和缩减。你可能已经使用过 ArrayList,因此我将略过基础部分。如果你对 ArrayList 还不熟悉,你可以参考它的 API 文档可以很容易理解在 ArrayList 上执行基本的操作。
In this post, I will discuss one of the most important operation on ArrayList that you will most likely require implementing during enterprise application development. It’s sorting the elements of an ArrayList.
在这篇文章中,我将讨论 ArrayList 中一种极其重要的操作,你很有可能需要在企业应用开发中实现它。它就是 ArrayList 元素的排序。

一、排序字符串对象的 ArrayList

代码如下:

 package demo;

 import java.util.ArrayList;
import java.util.Collections; /**
* 自定义排序 实现ArrayList的升降序
* @author xq.qiu
*
*/
public class SortArrayListAscDesc {
private ArrayList<String> arrayList; /**
* 在构造器中初始化了一个 ArrayList 对象
*
* @param arrayList
*/
public SortArrayListAscDesc(ArrayList<String> arrayList) {
this.arrayList = arrayList;
} public ArrayList<String> getArrayList() {
return arrayList;
} /**
* ArrayList 的升序
* 按照自然顺序(按字母升序)
* @return
*/
public ArrayList<String> sortArrayList() {
// 我们调用了 Collections.sort()方法,并传递这个初始化的 ArrayList对象为参数,返回排序后的 ArrayList。
Collections.sort(this.arrayList);
return this.arrayList;
} /**
* ArrayLuist 的降序
* 按照自然顺序(按字母降序)
* @return
*/
public ArrayList<String> descArrayList() {
// 我们调用重载的 Collections.sort()方法让其按照降序对元素排序,这个版本的
// Collections.sort()接收ArrayList对象作为第一个参数,一个由
// Collections.reverseOrder()方法返回的 Comparator 对象作为第二个参数。
Collections.sort(this.arrayList, Collections.reverseOrder());
return this.arrayList;
} /**
* 测试ArrayList升降序
*
* @param args
*/
public static void main(String[] args) {
// 保存一个国家的ArrayList
ArrayList<String> countryList = new ArrayList<String>();
countryList.add("France");
countryList.add("USA");
countryList.add("India");
countryList.add("Chian");
countryList.add("England");
// 初始化自定义构造
SortArrayListAscDesc sortList = new SortArrayListAscDesc(countryList);
// get
ArrayList<String> arrayList = sortList.getArrayList();
// 原始ArrayList
System.out.println("原始ArrayList ----->" + arrayList);
// 升序
System.out.println("升序ArrayList ----->" + sortList.sortArrayList());
// 降序
System.out.println("降序ArrayList ----->" + sortList.descArrayList());
}
}

运行结果:

原始ArrayList ----->[France, USA, India, Chian, England]
升序ArrayList ----->[Chian, England, France, India, USA]
降序ArrayList ----->[USA, India, France, England, Chian]

到目前为止,所要排序的 ArrayList 元素都是非常简单的,我们仅仅只是调用 Collections.sort()方法并传递了需要排序的 ArrayList 对象作为参数。但是更多的是你会遇到一些复杂的情景下对 ArrayList 进行排序。
Collections.sort() 方法对 ArrayList 的元素或者任何其他 List 的实现提供的可比较的元素进行排序,这意味着这些元素的类需要实现 java.lang 包中的 Comparable 接口。正如 String 类实现了 Comparable 接口,我们就可以对由国名构成的 ArrayList 排序。有些其他的标准 Java 类实现了 Comparable 接口,包括原始的包装类,例如 Integer、Short、Double、Float、Boolean、BigInteger、BigDecimal、File 和 Date 类都实现了 Comparable 接口。

二、使用Comparable排序ArrayList

Comparable 是带有单一 compareTo()方法的接口。一个实现了 Comparable 接口的类对象可以与其它同类型的对象进行比较,实现 Comparable 接口的类需要重写 compareTo()方法,这个方法接收一个同类型的对象,并实现这个对象和传递给方法的另一个对象比较的逻辑。compareTo()方法返回Int类型的比较结果,分别代表下面的含义:
正值表示当前对象比传递给 comPareTO()的对象大
负值表示当前对象比传递给 comPareTO()的对象小
零表示两个对象相等
让我们来举一个例子,JobCandidate 类的对象保存在 ArrayList 中并准备对其进行排序。

 package demo.sort;

 public class JobCandidate implements Comparable {

     private String name;
private String gender;
private int age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getGender() {
return gender;
} public void setGender(String gender) {
this.gender = gender;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} /**
* 实现Comparable 方法
*
* @param o
* @return
*/
@Override
public int compareTo(Object o) {
JobCandidate obj = (JobCandidate) o;
return (this.getAge() < obj.getAge() ? -1 : (this.getAge() == obj.getAge() ? 0 : 1));
} @Override
public String toString() {
return String.format("名称:%s\t性别%s\t年龄%d\n", this.name, this.gender, this.age);
} }

在上面 JobCandidate 类被重写的 compareTo()方法中,我们实现了基于年龄的比较逻辑。我见过很多程序员将(this.getAge() – candidate.getAge())作为返回的比较结果。尽管使用这种 return 语句看上去似乎很吸引人,并且也不会对我们的例子造成影响,我的建议是远离这种语句。想象一下,比较整数值,其中有一个或者两个都是负数的结果。这会导致一些错误,让你的程序行为不定,而且更重要的是,这样的错误是很细微的,尤其是在大型的企业应用中很难检测出来。下面我们将写一个辅助类,为委托方对包含了 JobCandidate 元素的 ArrayList 对象进行排序。

 package demo.sort;

 import java.util.ArrayList;
import java.util.Collections; /**
* 关于JobCandidate的排序器
* @author xg.qiu
*
*/
public class JobCandidateSorter { private ArrayList<JobCandidate> jobCandidateArrayList = new ArrayList<>(); /**
* 我们初始化了一个 ArrayList 对象,委托方将通过构造函数实例化 JobCandidateSorter
*
* @param jobCandidateArrayList
*/
public JobCandidateSorter(ArrayList<JobCandidate> jobCandidateArrayList) {
// TODO Auto-generated constructor stub
this.jobCandidateArrayList = jobCandidateArrayList;
} /**
* 在这个方法中,我们调用 Collections.sort()并传递已经初始化了的 ArrayList 为参数,最后返回排序后的
* ArrayList。
*
* @return
*/
public ArrayList<JobCandidate> getSortJobCandidateArrayList() {
Collections.sort(jobCandidateArrayList);
return this.jobCandidateArrayList;
} }

在 JobCandidateSorter 类中,我们初始化了一个 ArrayList 对象,委托方将通过构造函数实例化 JobCandidateSorter 。然后我们编写了

getSortJobCandidateArrayList

()方法,在这个方法中,我们调用 Collections.sort()并传递已经初始化了的 ArrayList 为参数,最后返回排序后的 ArrayList。
接下来,我们写一个测试类来测试一下我们的代码。

 package demo.sort;

 import java.util.ArrayList;
import java.util.Iterator; public class JobCandidateSorterTest { public static void main(String[] args) {
// TODO Auto-generated method stub
// 我们创建了四个 JobCandidate 对象并把它们添加到 ArrayList
JobCandidate j1 = new JobCandidate("Xiaoqiu", "男", 25);
JobCandidate j2 = new JobCandidate("JackHas", "男", 20);
JobCandidate j3 = new JobCandidate("HaayLiy", "女", 19);
JobCandidate j4 = new JobCandidate("EricQiu", "男", 25); ArrayList<JobCandidate> jobCandidateArrayList = new ArrayList<>();
jobCandidateArrayList.add(j1);
jobCandidateArrayList.add(j2);
jobCandidateArrayList.add(j3);
jobCandidateArrayList.add(j4); // 我们调用 JobCandidateSorter 类的
// getSortJobCandidateArrayList()方法,并打印这个方法返回的排序后的 ArrayList。 JobCandidateSorter sorter = new JobCandidateSorter(jobCandidateArrayList);
ArrayList<JobCandidate> sorterList = sorter.getSortJobCandidateArrayList();
Iterator<JobCandidate> it = sorterList.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
} }

在上面的测试类中,我们创建了四个

JobCandidate对象并把它们添加到 ArrayList,然后传递这个 ArrayList 到构造函数来实例化
JobCandidateSorter 类。最后,我们调用
JobCandidateSorter 类的
getSortJobCandidateArrayList()方法,并打印这个方法返回的排序后的 ArrayList。测试的输出结果如下:
名称:HaayLiy    性别女    年龄19
名称:JackHas 性别男 年龄20
名称:Xiaoqiu 性别男 年龄25
名称:EricQiu 性别男 年龄25

使用 Comparable 对 ArrayList 排序是一种常用的方法。但是你必须知道有某些限制。你想要排序的对象的类必须实现 Comparable 并覆写 compareTo()方法。这基本上意味着你将只能基于一个成员变量来比较对象(我们例子中的年龄字段)。如果要求你按照姓名和年龄来对 JobCandidate 对象进行排序怎么办? Comparable 就不是解决的方法了。另外,比较逻辑是需要进行比较的对象的类的一部分,它消除了比较逻辑可复用性的可能。Java 通过使用在 java.util 包下提供的Comparator接口解决了上述的比较需求。

三、使用 Comparator 排序 ArrayList

Comparator 接口与Comparable 接口相似也提供了一个单一的比较方法叫作 compare()。然而,与 Comparable的 compareTo()方法不同的是,这个 compare()接受两个同类型的不同对象进行比较。
我们将用 Comparator 对我们之前使用过的相同 JobCandidate 类对象进行排序。我们将通过实现 Comparatoras 匿名内部类,允许对 JobCandidate 对象按照年龄和姓名进行排序。
下面是使用了 Comparator 的 JobCandidate 类代码

JobCandidate :

 /**
* age 的比较器
*/
public static Comparator<JobCandidate> ageComparator = new Comparator<JobCandidate>() {
@Override
public int compare(JobCandidate o1, JobCandidate o2) {
// TODO Auto-generated method stub
return (o2.getAge() < o1.getAge() ? -1 : (o2.getAge() == o1.getAge() ? 0 : 1));
}
}; /**
* name 的比较器
*/
public static Comparator<JobCandidate> nameComparator = new Comparator<JobCandidate>() {
@Override
public int compare(JobCandidate o1, JobCandidate o2) {
// TODO Auto-generated method stub
return (int) o1.getName().compareTo(o2.getName());
}
};

JobCandidateSorter:

     /**
* 实现age 的排序
* @return
*/
public ArrayList<JobCandidate> getSortJobCandidateByAge(){
Collections.sort(jobCandidateArrayList,JobCandidate.ageComparator);
return this.jobCandidateArrayList;
}
/**
* 实现name 的排序
* @return
*/
public ArrayList<JobCandidate> getSortJobCandidateByName(){
Collections.sort(jobCandidateArrayList,JobCandidate.nameComparator);
return this.jobCandidateArrayList;
}

test:

      // age的排序结果
ArrayList<JobCandidate> sorterAgeList = sorter.getSortJobCandidateByAge();
Iterator<JobCandidate> itAge = sorterAgeList.iterator();
while(itAge.hasNext()){
System.out.println(itAge.next());
}
// name的排序结果
ArrayList<JobCandidate> sorterNameList = sorter.getSortJobCandidateByName();
Iterator<JobCandidate> itName = sorterNameList.iterator();
while(itName.hasNext()){
System.out.println(itName.next());
}

总结

在本文中我们看到了 ArrayList 排序的不同方法。一种是使用 Comparable 另一种是使用 Comparator。方法的选择一直是造成程序员们困惑的原因之一。你最应该记住的就是一个 Comparable 对象可以说“我可以自己与另外一个对象比较”而一个 Comparator 对象可以说“我可以比较两个不同的对象”。你不能说一个接口比另一个要好。选择的接口取决于你需要实现的功能。

原文链接: dzone 翻译: ImportNew.com温布利往事
译文链接: http://www.importnew.com/17211.html

Java ArrayList的不同排序方法的更多相关文章

  1. Java中常见的排序方法

    本博主要介绍Java中几种常见的排序算法: /* 排序方法的演示1)插入排序(直接插入排序.希尔排序)2)交换排序(冒泡排序.快速排序)3)选择排序(直接选择排序.堆排序)4)归并排序5)分配排序(基 ...

  2. Java中List的排序方法

    方法一:实现Comparable接口 package com.java.test; public class Person implements Comparable<Person> { ...

  3. java ArrayList的几种方法使用

    package java06; import java.util.ArrayList; /* ArrayList的常用的几个方法: public boolean add(E e) : 向集合汇总添加元 ...

  4. [Java]ArrayList集合的contains方法

    用到集合ArrayList时经常会用到里面自带的方法boolean contains(Object o);此方法用于判断集合里面是否包含元素o,现在讨论下在Object类型为类类型的时候的情况: cl ...

  5. Java ArrayList几种遍历方法

    import java.util.ArrayList; import java.util.Iterator; public class StringSampleDemo { public static ...

  6. JAVA Map 和 List 排序方法

    private Map<String,String> mapDate; //正序 mapDate=new TreeMap<String, String>(new Compara ...

  7. Java ArrayList排序方法详解

    由于其功能性和灵活性,ArrayList是 Java 集合框架中使用最为普遍的集合类之一.ArrayList 是一种 List 实现,它的内部用一个动态数组来存储元素,因此 ArrayList 能够在 ...

  8. java提供的默认list排序方法-转

    1.java提供的默认list排序方法 主要代码: List<String> list = new ArrayList();list.add("刘媛媛"); list. ...

  9. 无前趋的顶点优先的拓扑排序方法(JAVA)(转载http://128kj.iteye.com/blog/1706968)

    无前趋的顶点优先的拓扑排序方法 该方法的每一步总是输出当前无前趋(即人度为零)的顶点,其抽象算法可描述为:     NonPreFirstTopSort(G){//优先输出无前趋的顶点       w ...

随机推荐

  1. sudo 运行 npm或node时,出现找不到命令

    sudo 运行 npm或node时,出现找不到命令的情况,运行下面这些命令, sudo ln -s /usr/local/bin/node /usr/bin/node sudo ln -s /usr/ ...

  2. matlab GUI重新命名

    http://www.mathworks.com/matlabcentral/newsreader/view_thread/309789 To change the name you should o ...

  3. 像黑客一样!Chrome 完全键盘操作指南(原生快捷键 + Vimium 插件)

    有那么一波小伙伴,多数时候都不需要用到鼠标,通常他们正好是“黑客”.当你开始使用键盘操作一切时,便能体会到无需用鼠标瞄准按钮时的干脆,无需在键盘和鼠标之间移动手时的轻松. Chrome 原生自带大量快 ...

  4. python redis的基本使用

    1.redis redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sor ...

  5. UVA11806 Cheerleaders

    题意 PDF 分析 如果要求是某行某列没有石子很好算,就一个组合数. 然后要求某行某列有,就用容斥原理就行了. 时间复杂度\(O(k^2 + 16T)\) 代码 #include<iostrea ...

  6. Ubuntu 破解密码及用户管理

    Ubuntu 破解密码及用户管理 ubuntu 16.04 破解密码 useradd 实现以下要求 1.ubuntu16.04破解密码 2.创建下面的用户.组和组成员关系 名字为xipudata 的组 ...

  7. css之选择器的认识

    css中有大量的选择器,主要用来精准的找到代码中的某一段或者某一个段落,并对其样式进行选择和改变. 首先介绍的第一个选择器是: 1,基本选择器: 直接找到标签对其进行样式修正,不论标签藏多深,或者数量 ...

  8. Java语言与C语言混合编程(1)--Java native 关键字

    一. 什么是 native Method 简单地讲,一个 native Method 就是一个java调用非java代码的接口.一个 native Method 是这样一个java的方法:该方法的实现 ...

  9. 模拟Linux修改实际、有效和保存设置标识

    就是模拟setuid seteuid setreuid setresuid,感觉代码比书上大段的文字好记,就写成代码形式了. // setuid.cc: 模拟<unistd.h>中的设置用 ...

  10. 数据结构与算法JavaScript描述——队列

    注:澄清一个bug: /** * 删除队首的元素: */ function dequeue(){ return this.dataStore.shift(); } 应该有return:   队列是一种 ...