Java之自定義排序工具類
- 2019 年 10 月 8 日
- 筆記
「 Java的封裝,你到底了解了嗎? 一個工具類,便知你的水平~ 」 —— 23號老闆
0
1
引入
原創:小靜
在項目開發中,經常會遇到需要對一個複雜對象的集合進行規則排序,可能需要根據某一欄位排序,也可能需要根據某些欄位排序,導致冗餘的程式碼看起來既複雜又繁瑣。因此,我們可以通過封裝一個通用的工具類,來針對所有的複雜對象進行抽象處理。 這樣會使你的程式碼顯得更加具備通用性,並且可適配。
02
理解
首先,在Java當中,我們可能會想到一個常用的工具類,那就是Collections。
Collections類提供了對集合元素進行排序、反轉方法。
● void sort(List)
該方法用於對List內的元素排序。
● void shuffle(List)
該方法用於對List內的元素進行隨機排序。
● void reverse(List)
該方法用於對List內的元素進行逆序排序。
創建一個Person實體類
public class Person{ private String userName; private String password; private Integer age; //setter、getter }
傳統的實現,我們會這樣操作:
main() { List<Person> personList = new ArrayList<>(); Person person1 = new Person("aaa","123456",25); Person person2 = new Person("bbb","123456",15); Person person3 = new Person("ccc","123456",20); personList.add(person1); personList.add(person2); personList.add(person3); //排序前 if (personList != null && personList.size() > 0) { for (Person person : personList) { System.out.println(person); } System.out.println("-------------"); } //排序 Collections.sort(personList, new Comparator<Person>() { @Override public int compare(Person p1, Person p2) { //return p1.getAge() - p2.getAge(); //表示升序 return p2.getAge() - p1.getAge(); //表示降序 } }); //排序後 if (personList != null && personList.size() > 0) { for (Person person : personList) { System.out.println(person); } } }
輸出結果:

sort方法默認的是正序,也可以倒序排列。
此種方式相對靈活,並且不需要實體類實現Comparable介面,
而且無論list中的類型是實體類還是Map,都可以適用。
如果想使用sort中帶一個參數的排序,則該實體類必須實現Comparable,並且重寫compareTo方法,否則就會報異常
The method sort(List<T>) in the type Collections is not applicable for the arguments (List<Emp>)
意思是參數類型為List<Emp>時,sort方法無法執行,原因是泛型沒有繼承Comparable介面。
改造:
public class Person implements Comparable<Person> { private String userName; private String password; private Integer age; @Override public int compareTo(Person person) { //按照年齡正序 //return this.getAge().compareTo(person.getAge()); //按照年齡進行排序 (並且是倒序) return person.getAge().compareTo(this.getAge()); } }
測試結果:

0
3
編寫工具類
而以上的程式碼,在較大的項目中使用,儘管可以一一實現,但只針對具體的單一實現類,以及指定的屬性配置,才可實現你所需要的排序方式,不足以達到通用的效果。那現在,我們就來寫一個通用的實現類,來達到此目的。
/** * @Auther: bboyHan * @Date: 2019/1/29 18:40 */ public class CollectionsUtil { public static final String DESC = "desc"; public static final String ASC = "asc"; /** * 對list中的元素按升序排列. * * @param list 排序集合 * @param field 排序欄位 * @return */ public static List<?> sort(List<?> list, final String field) { return sort(list, field, null); } /** * 對list中的元素進行排序. * * @param list 排序集合 * @param field 排序欄位 * @param sort 排序方式: SortList.DESC(降序) SortList.ASC(升序). */ @SuppressWarnings("unchecked") public static List<?> sort(List<?> list, final String field, final String sort) { Collections.sort(list, new Comparator() { public int compare(Object a, Object b) { int ret = 0; try { Field f = a.getClass().getDeclaredField(field); f.setAccessible(true); Class<?> type = f.getType(); if (type == int.class) { ret = Integer.compare(f.getInt(a), f .getInt(b)); } else if (type == double.class) { ret = Double.compare(f.getDouble(a), f .getDouble(b)); } else if (type == long.class) { ret = Long.compare(f.getLong(a), f .getLong(b)); } else if (type == float.class) { ret = Float.compare(f.getFloat(a), f .getFloat(b)); } else if (type == Date.class) { ret = ((Date) f.get(a)).compareTo((Date) f.get(b)); } else if (isImplementsOf(type, Comparable.class)) { ret = ((Comparable) f.get(a)).compareTo(f .get(b)); } else { ret = String.valueOf(f.get(a)).compareTo( String.valueOf(f.get(b))); } } catch (SecurityException | NoSuchFieldException | IllegalAccessException | IllegalArgumentException e) { e.printStackTrace(); } if (sort != null && sort.equalsIgnoreCase(DESC)) { return -ret; } else { return ret; } } }); return list; } /** * 對list中的元素按fields和sorts進行排序, * fields[i]指定排序欄位,sorts[i]指定排序方式.如果sorts[i]為空則默認按升序排列. * * @param list * @param fields * @param sorts */ @SuppressWarnings("unchecked") public static List<?> sort(List<?> list, String[] fields, String[] sorts) { if (fields != null && fields.length > 0) { for (int i = fields.length - 1; i >= 0; i--) { final String field = fields[i]; String tmpSort = ASC; if (sorts != null && sorts.length > i && sorts[i] != null) { tmpSort = sorts[i]; } final String sort = tmpSort; Collections.sort(list, new Comparator() { public int compare(Object a, Object b) { int ret = 0; try { Field f = a.getClass().getDeclaredField(field); f.setAccessible(true); Class<?> type = f.getType(); if (type == int.class) { ret = ((Integer) f.getInt(a)) .compareTo(f.getInt(b)); } else if (type == double.class) { ret = ((Double) f.getDouble(a)) .compareTo(f.getDouble(b)); } else if (type == long.class) { ret = ((Long) f.getLong(a)).compareTo(f .getLong(b)); } else if (type == float.class) { ret = ((Float) f.getFloat(a)) .compareTo(f.getFloat(b)); } else if (type == Date.class) { ret = ((Date) f.get(a)).compareTo((Date) f .get(b)); } else if (isImplementsOf(type, Comparable.class)) { ret = ((Comparable) f.get(a)) .compareTo(f.get(b)); } else { ret = String.valueOf(f.get(a)).compareTo( String.valueOf(f.get(b))); } } catch (SecurityException | NoSuchFieldException | IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } if (sort != null && sort.equalsIgnoreCase(DESC)) { return -ret; } else { return ret; } } }); } } return list; } /** * 默認按正序排列 * * @param list * @param method */ public static List<?> sortByMethod(List<?> list, final String method) { return sortByMethod(list, method, null); } @SuppressWarnings("unchecked") public static List<?> sortByMethod(List<?> list, final String method, final String sort) { Collections.sort(list, new Comparator() { public int compare(Object a, Object b) { int ret = 0; try { Method m = a.getClass().getMethod(method, null); m.setAccessible(true); Class<?> type = m.getReturnType(); if (type == int.class) { ret = ((Integer) m.invoke(a, null)) .compareTo((Integer) m.invoke(b, null)); } else if (type == double.class) { ret = ((Double) m.invoke(a, null)).compareTo((Double) m .invoke(b, null)); } else if (type == long.class) { ret = ((Long) m.invoke(a, null)).compareTo((Long) m .invoke(b, null)); } else if (type == float.class) { ret = ((Float) m.invoke(a, null)).compareTo((Float) m .invoke(b, null)); } else if (type == Date.class) { ret = ((Date) m.invoke(a, null)).compareTo((Date) m .invoke(b, null)); } else if (isImplementsOf(type, Comparable.class)) { ret = ((Comparable) m.invoke(a, null)) .compareTo(m.invoke(b, null)); } else { ret = String.valueOf(m.invoke(a, null)).compareTo( String.valueOf(m.invoke(b, null))); } if (isImplementsOf(type, Comparable.class)) { ret = ((Comparable) m.invoke(a, null)) .compareTo(m.invoke(b, null)); } else { ret = String.valueOf(m.invoke(a, null)).compareTo( String.valueOf(m.invoke(b, null))); } } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ne) { ne.printStackTrace(); } if (sort != null && sort.toLowerCase().equals(DESC)) { return -ret; } else { return ret; } } }); return list; } @SuppressWarnings("unchecked") public static List<?> sortByMethod(List<?> list, final String methods[], final String sorts[]) { if (methods != null && methods.length > 0) { for (int i = methods.length - 1; i >= 0; i--) { final String method = methods[i]; String tmpSort = ASC; if (sorts != null && sorts.length > i && sorts[i] != null) { tmpSort = sorts[i]; } final String sort = tmpSort; Collections.sort(list, new Comparator() { public int compare(Object a, Object b) { int ret = 0; try { Method m = a.getClass().getMethod(method, null); m.setAccessible(true); Class<?> type = m.getReturnType(); if (type == int.class) { ret = ((Integer) m.invoke(a, null)) .compareTo((Integer) m.invoke(b, null)); } else if (type == double.class) { ret = ((Double) m.invoke(a, null)) .compareTo((Double) m.invoke(b, null)); } else if (type == long.class) { ret = ((Long) m.invoke(a, null)) .compareTo((Long) m.invoke(b, null)); } else if (type == float.class) { ret = ((Float) m.invoke(a, null)) .compareTo((Float) m.invoke(b, null)); } else if (type == Date.class) { ret = ((Date) m.invoke(a, null)) .compareTo((Date) m.invoke(b, null)); } else if (isImplementsOf(type, Comparable.class)) { ret = ((Comparable) m.invoke(a, null)) .compareTo(m.invoke(b, null)); } else { ret = String.valueOf(m.invoke(a, null)) .compareTo( String.valueOf(m .invoke(b, null))); } } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ne) { ne.printStackTrace(); } if (sort != null && sort.toLowerCase().equals(DESC)) { return -ret; } else { return ret; } } }); } } return list; } /** * 判斷對象實現的所有介面中是否包含szInterface * * @param clazz * @param szInterface */ public static boolean isImplementsOf(Class<?> clazz, Class<?> szInterface) { boolean flag = false; Class<?>[] face = clazz.getInterfaces(); for (Class<?> c : face) { if (c == szInterface) { flag = true; } else { flag = isImplementsOf(c, szInterface); } } if (!flag && null != clazz.getSuperclass()) { return isImplementsOf(clazz.getSuperclass(), szInterface); } return flag; }
0
4
測試
main方法:
public static void main(String[] args) throws Exception { List<Person> list = new ArrayList<Person>(); list.add(new Person("zhangsan", "b", 18)); list.add(new Person("zhangsi", "b", 28)); list.add(new Person("lisi", "d", 20)); list.add(new Person("wangwu", "d", 22)); System.out.println("-----------排序前---------------"); for (Person p : list) { System.out.println(p.toString()); } System.out.println(); // 按age正序排序,注意結果排完後是1,2,3,11. 不是1,11,2,3(如果是String類型正序排序是這樣) CollectionsUtil.sort(list, "age", null); System.out.println("---------測試Integer和正序,按age正序排序-----------------"); for (Person p : list) { System.out.println(p.toString()); } System.out.println(); // 按id倒序 CollectionsUtil.sort(list, "userName", CollectionsUtil.DESC); System.out.println("--------測試int和倒序,按id倒序------------------"); for (Person p : list) { System.out.println(p.toString()); } System.out.println(); // 先按userName正序排序,再按age正序排序 CollectionsUtil.sort(list, new String[] { "userName", "age" }, new String[] {}); System.out .println("---------測試多個排序欄位,先按userName正序,userName相同時再按age正序-----------------"); for (Person p : list) { System.out.println(p.toString()); } System.out.println(); // 先按userName正序排序,再按id倒序排序 CollectionsUtil.sort(list, new String[] { "userName", "age" }, new String[] { CollectionsUtil.ASC, CollectionsUtil.DESC }); System.out .println("---------測試多個排序欄位,先按userName正序,userName相同時再按age倒序-----------------"); for (Person p : list) { System.out.println(p.toString()); } System.out.println(); // sortByMethod CollectionsUtil.sortByMethod(list, "getAge", null); System.out .println("---------測試sortByMethod,按getAge方法正序-----------------"); for (Person p : list) { System.out.println(p.toString()); } System.out.println(); }
測試結果:

0
5
小結
另外,還可以在此基礎上根據不同的業務需求進行更改和擴展。關於異常的問題,在這裡只是做了一個簡單的處理。
你…學會了嗎?