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
小结
另外,还可以在此基础上根据不同的业务需求进行更改和扩展。关于异常的问题,在这里只是做了一个简单的处理。
你…学会了吗?