參考:改善java代碼的151個建議-73建議:使用Compatator排序
在項目開發中,我們經常要對一組數據排序,或者升序或者降序,在java中排序有多種方式,最土的方法就是自己寫排序算法,比如冒泡排序,快速排序,二叉樹排序等,但一般不要自己寫,jdk已經為我們提供了很多的 排序算法,我們采用拿來主義就成了。
在java中,要給數據排序,有兩種實現方式,分別實現兩個接口:
- 一種是實現Comparable接口
- 另一種是實現Comparator接口
在JDK類庫中,有一部分類實現了Comparable接口,如Integer Double和String等。
Comparable接口有一個comparTo(Object o)方法,它返回整數類型。對於表達式x.compareTo(y),如果返回值為0,則表示x和y相等,如果返回值大於0,則表示x大於y,如果返回值小於0,則表示x小於y.
查看Comparable接口源碼
public interface Comparable<T> { public int compareTo(T o); }
舉個例子:
給公司職員排序,按照工號排序,先定義一個職員類
編寫Employee類實現Comparable接口
package hello; import org.apache.commons.lang3.builder.CompareToBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; public class Employee implements Comparable<Employee>{ //id是根據進入公司的先后順序編碼的 private int id; //姓名 private String name; //職位 private Position position; public Employee(int id, String name, Position position) { super(); this.id = id; this.name = name; this.position = position; } //按照id號排序,也就是資歷的深淺排序 @Override public int compareTo(Employee o) { // TODO Auto-generated method stub return new CompareToBuilder().append(id, o.id).toComparison(); } @Override public String toString(){ return ToStringBuilder.reflectionToString(this); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Position getPosition() { return position; } public void setPosition(Position position) { this.position = position; } }
這是一個簡單的javabean,描述的是一個員工的基本信息,其中id是員工編號,按照進入公司的先后順序編碼,position是崗位描述,表示是經理還是普通職員,這是一個枚舉類型:
public enum Position { Boss, Manager,staff }
職位有三個級別:
Boss(老板), Manager(經理), Staff(職員)
- 按id排序
Employee類的compareTo()方法,是Comparable接口必須要實現的方法,使用apach的工具類來實現,表明是按照id的自然序列排序的(升序)。一切准備完畢,我們看看如何排序:
package hello; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; public class HelloWord { public static void main(String[] args) { List<Employee> list = new ArrayList<Employee>(5); // 一個老板 list.add(new Employee(1001, "張三", Position.Boss)); // 兩個經理 list.add(new Employee(1006, "趙四", Position.Manager)); list.add(new Employee(1003, "王五", Position.Manager)); // 兩個職員 list.add(new Employee(10002, "李六", Position.staff)); list.add(new Employee(1005, "馬牛", Position.staff)); // 按照id排序,也就是按照資歷深淺排序 Collections.sort(list); for (Employee e : list) { System.out.println(e); } } }
【運行結果】:
hello.Employee@46244bb9[id=1001,name=張三,position=Boss]
hello.Employee@4b5d7792[id=1003,name=王五,position=Manager]
hello.Employee@3e0a765c[id=1005,name=馬牛,position=staff]
hello.Employee@7fbb6976[id=1006,name=趙四,position=Manager]
hello.Employee@6909037d[id=10002,name=李六,position=staff]
是按照id升序排列的,結果正確。
- 按職位排序
本着“領導為先”的理念,按職位從高到低排序,先是老板,然后是經理,最后是普通職員,Employee已經是一個穩定類,為了一個排序功能修改它,影響按照id排序,不是一個好辦法。
Collections.sort()方法有一個重載方法sort(List<T> list, Comparator<? super T> c),有一個Comparator接口參數,我們實現這個接口:
//職位排序器 class PositionComparator implements Comparator<Employee>{ @Override public int compare(Employee o1, Employee o2) { //按照職位降序排列 return o1.getPosition().compareTo(o2.getPosition()); }
創建了一個職位排序法,按職位高低排序,測試一下:
Collections.sort(list, new PositionComparator()); for (Employee e : list) { System.out.println(e); }
【運行結果】:
hello.Employee@46244bb9[id=1001,name=張三,position=Boss]
hello.Employee@4b5d7792[id=1003,name=王五,position=Manager]
hello.Employee@7fbb6976[id=1006,name=趙四,position=Manager]
hello.Employee@3e0a765c[id=1005,name=馬牛,position=staff]
hello.Employee@6909037d[id=10002,name=李六,position=staff]
按照職位排序,結果正確。
- 按照職位從低到高排序
為了照顧員工,需要按職位由低到高排序
兩個辦法:
- Collections.reverse(List<?> list)方法實現倒序排列
- Collections.sort(List<?> list,Collections.reverseOrder(new PositionComparator())也可以
用這兩個方法來測試:
Collections.reverse(list); for (Employee e : list) { System.out.println(e); } System.out.println("----"); Collections.sort(list, Collections.reverseOrder(new PositionComparator())); for (Employee e : list) { System.out.println(e); }
【運行結果】:
hello.Employee@6909037d[id=10002,name=李六,position=staff] hello.Employee@3e0a765c[id=1005,name=馬牛,position=staff] hello.Employee@7fbb6976[id=1006,name=趙四,position=Manager] hello.Employee@4b5d7792[id=1003,name=王五,position=Manager] hello.Employee@46244bb9[id=1001,name=張三,position=Boss] ---- hello.Employee@6909037d[id=10002,name=李六,position=staff] hello.Employee@3e0a765c[id=1005,name=馬牛,position=staff] hello.Employee@7fbb6976[id=1006,name=趙四,position=Manager] hello.Employee@4b5d7792[id=1003,name=王五,position=Manager] hello.Employee@46244bb9[id=1001,name=張三,position=Boss]
按照職位由地到高排序,結果正確
- 先按職位排序,職位 相同按id排序
在compareTo或compare方法中先判斷職位是否相等,職位相等再根據工號排序
修改Employee類的compareTo()方法為
@Override public int compareTo(Employee o) { return new CompareToBuilder() .append(position, o.position) //按照職位排序 .append(o.id,id).toComparison(); //工號排序 }
排序代碼:
Collections.sort(list); for (Employee e : list) { System.out.println(e); }
【運行結果】:
hello.Employee@4d871a69[id=1001,name=張三,position=Boss] hello.Employee@631803fb[id=1006,name=趙四,position=Manager] hello.Employee@4b5d7792[id=1003,name=王五,position=Manager] hello.Employee@655538e5[id=1005,name=馬牛,position=staff] hello.Employee@20e0b1d6[id=1002,name=李六,position=staff]
總結:
- 實現了Comparable接口類表明自身可比較,有了比較才能進行排序;
- Comparator接口是一個工具類接口,用作比較,與原類的邏輯沒有關系;