Java的比較器是用來對List集合進行排序用的,分爲內部比較器和外部比較器兩類java
內部比較器:被排序的類要 implements Comparable 類,並實現compareTo方法。網絡
外部比較器:須要實現一個implements Comparator的比較器,實現compare方法,並在sort方法中將該比較器當參數傳入。ide
(具體實現,網絡上有不少資料,此處再也不贅述)this
外部比較器雖然相比內部比較器 實現瞭解耦,代碼侵入小,可是二者都不能擺脫同一個麻煩的問題:設計
那就是對每一個待排序的對象,均需單獨實現一個比較器類。若是項目中有不少類都須要排序,那就須要重複勞動,寫不少個比較器類了。對象
本文的目的,即經過泛型和反射機制的應用,來設計實現一個通用的外部比較器。該比較器對任何待排序的對象均能適用,減小低級的重複勞動。blog
話很少說,直接貼代碼:排序
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
import java.text.Collator;
import java.util.Comparator;
/**
* @Description: 指定需根據某字段排序的方法名,進行排序,返回類型自動判斷,目前支持Integer 和 String
* @Author: wangzhen3
* @CreationTime: 2018/5/29 15:02
* @ModifiedBy:
*/
public class CompareByFunctionName<T> implements Comparator<T> {
private static final Logger logger = LoggerFactory.getLogger(CompareByFunctionName.class);
/**
* 需比較字段的方法名 如 getStatus
*/
private String functionName = "";
/**
* 是否倒序
*/
private Boolean invert = false;
public CompareByFunctionName(String functionName){
this.functionName = functionName;
this.invert = false;
}
public CompareByFunctionName(String functionName, Boolean invert){
this.functionName = functionName;
this.invert = invert;
}
@Override
public int compare(T o1, T o2) {
Object ret1;
Object ret2;
Method method;
try {
method = o1.getClass().getMethod(functionName);
ret1 = method.invoke(o1);
ret2 = method.invoke(o2);
if(ret1 instanceof Integer){
return !invert? (Integer)ret1 - (Integer)ret2 :
(Integer)ret2 - (Integer)ret1;
}else if(ret1 instanceof String){
return !invert? Collator.getInstance(java.util.Locale.CHINA).compare(ret1,ret2) :
Collator.getInstance(java.util.Locale.CHINA).compare(ret2,ret1);
}else{
//直接toString 比較
return !invert? Collator.getInstance(java.util.Locale.CHINA).compare(ret1.toString(),ret2.toString()) :
Collator.getInstance(java.util.Locale.CHINA).compare(ret2.toString(),ret1.toString());
}
}catch (Exception e){
logger.error(e.getMessage());
}
logger.error("比較失敗,o1={},o2={}",o1.toString(),o2.toString());
return 0;
}
}ip
關鍵步驟說明:字符串
1)java反射機制中的Field 和 Method 方法,網上有不少博客介紹,此處不贅述。
2)functionName 必須爲public方法,否則無訪問權限。
或許你會有疑問,爲何此處反射是使用Method得到數據值 而不直接用字段Field來獲取數據值,緣由是字段通常被聲明爲private,因此經過Field通常無訪問權限,沒法取出數據,而Method ,好比status 字段的getStatus方法,一般是public ,因此能取出數據。
3)固然,functionName 是能夠換成 字段名稱fieldName 的,只須要新增轉換邏輯,根據java的駝峯式命名約定,把fieldName 轉換爲functionName 便可
4)Collator.getInstance(java.util.Locale.CHINA) .compare()
爲了實現中文字符串排序功能
項目中使用示例:
根據字段status對List<MonitorAlarmData> 進行倒序排列,使status=1的排在開頭,status=-1的排在末尾
public class MonitorAlarmData {
private String id; //problem id
private Integer status;//當前狀態 -1 已忽略; 0 OK; 1 problem;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
}
List<MonitorAlarmData> monitorAlarmDataList = new ArrayList<>();
//省略代碼,往monitorAlarmDataList 中添加數據
//排序 monitorAlarmDataList.sort(new CompareByFunctionName("getStatus",true));