在进行java开发时,经常需要对list进行排序,本文对此进行小结。总结了两种方法,第一种是通过原生支持的Comparator做排序,第二种是通过apache-common的工具包进行排序。相比而言,第二种代码可读性、易用性更强,推荐使用第二种。
我们要对User类组成的list进行排序,先按年龄age倒序排,再按等级grade正序排,如果grade为null,视为最大值,要排在最后。
public class User{ private int age ; private String grade ; public int getAge() { return age ; } public void setAge(int age) { this.age = age; } public String getGrade() { return grade ; } public void setGrade(String grade) { this.grade = grade; } }
User user1 = new User(); user1.setAge(15); user1.setGrade( "A"); users.add(user1); User user2 = new User(); user2.setAge(16); user2.setGrade( "A"); users.add(user2); User user3 = new User(); user3.setAge(15); user3.setGrade( null); users.add(user3);
主要是实现Comparator方法,代码如下
Collections. sort(users, new Comparator<Object>(){ @Override public int compare(Object arg1, Object arg2) { User u1 = (User)arg1; User u2 = (User)arg2; if(u2.getAge() == u1.getAge()) { if(u2.getGrade() == null || u1.getGrade() == null) { if(u2.getGrade() == null) { return -1; } else { return 1; } } return u1.getGrade().compareTo(u2.getGrade()); } return u2.getAge() - u1.getAge(); }; });
代码贴完,再来细说。这段代码实在不忍直视,可读性比较差。首先,为了实现主次排序的需求,需要在if(u2.getAge() == u1.getAge())时,再对grade进行判断,这就多了一层if嵌套。判断grade大小前,还需要对grade是否为null做判断,又多了一个if。其次,再看compare方法的返回值是怎么定义的:如果是正序排序,则当compare方法的参数1(arg1)大于参数2(arg2)时,需返回正数,如果相等,则返回0;逆排则相反,arg1大于arg2时,需返回负数。这个规则不方便记。那么,有没有更好的方法,答案是有的,可以借助apache-common的包。
Comparator mycmp1 = ComparableComparator.getInstance (); mycmp1 = ComparatorUtils. reversedComparator(mycmp1); //逆序 Comparator mycmp2 = ComparableComparator.getInstance (); mycmp2 = ComparatorUtils. nullHighComparator(mycmp2); //允许null // 声明要排序的对象的属性,并指明所使用的排序规则,如果不指明,则用默认排序 ArrayList<Object> sortFields = new ArrayList<Object>(); sortFields.add( new BeanComparator("age" , mycmp1)); //主排序(第一排序) sortFields.add( new BeanComparator("grade" , mycmp2)); //次排序(第二排序) // 创建一个排序链 ComparatorChain multiSort = new ComparatorChain(sortFields); // 开始真正的排序,按照先主,后副的规则 Collections.sort (users , multiSort);
其实大家看代码应该就能明白了,这里再啰嗦几句,看工具包是如何减轻程序员压力的
首先,通过ComparatorUtils封装好的排序器,可以直接声明是要倒序排,还是正序排(默认是正序,不需要声明),而不需再考虑Comparator返回值。
其次,通过ComparatorChain排序链的先后添加顺序,可以很方便地定义第一排序、第二排序甚至是第九百九十九排序……
最后,通过BeanComparator,直接传参为要排序的字段名称,代码可读性很强,之后要替换也很方便。假设要将age替换成别的排序字段,在第一种排序方法中,至少要替换四个地方,而在这里,替换一个地方即可。