Java之自定义排序工具类
"Java的封装,你到底了解了吗? 一个工具类,便知你的水平~ "
- 引入
在项目开发中,经常会遇到需要对一个复杂对象的集合进行规则排序,可能需要根据某一字段排序,也可能需要根据某些字段排序,导致冗余的代码看起来既复杂又繁琐。因此,我们可以通过封装一个通用的工具类,来针对所有的复杂对象进行抽象处理。 这样会使你的代码显得更加具备通用性,并且可适配。
- 理解
首先,在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);
}
}
}
输出结果:
排序前:
Person{userName='aaa', password='123456', age=25}
Person{userName='bbb', password='123456', age=15}
Person{userName='ccc', password='123456', age=20}
排序后:
Person{userName='aaa', password='123456', age=25}
Person{userName='ccc', password='123456', age=20}
Person{userName='bbb', password='123456', age=15}
-
sort方法默认的是正序,也可以倒序排列。
-
此种方式相对灵活,并且不需要实体类实现Comparable接口
-
而且无论list中的类型是实体类还是Map,都可以适用。
如果想使用sort中带一个参数的排序,则该实体类必须实现Comparable,并且重写compareTo方法,否则就会报异常
The method sort(List) in the type Collections is not applicable for the arguments (List)
意思是参数类型为List时,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()); } }
测试结果:
排序前: Person{userName='aaa', password='123456', age=25} Person{userName='bbb', password='123456', age=15} Person{userName='ccc', password='123456', age=20} 排序后: Person{userName='aaa', password='123456', age=25} Person{userName='ccc', password='123456', age=20} Person{userName='bbb', password='123456', age=15}
-
编写工具类
而以上的代码,在较大的项目中使用,尽管可以一一实现,但只针对具体的单一实现类,以及指定的属性配置,才可实现你所需要的排序方式,不足以达到通用的效果。那现在,我们就来写一个通用的实现类,来达到此目的。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; } }
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(); }
测试结果:
小结:
另外,还可以在此基础上根据不同的业务需求进行更改和扩展。关于异常的问题,在这里只是做了一个简单的处理。