Java比较器:两个排序标准

时间:2013-06-06 09:57:04

标签: java collections comparator

我有一个包含字符串(名称)和整数(年龄)的简单类。应存储在集合中的对象不得具有双重名称值,并应根据年龄下降进行排序。 第一个代码示例删除所有双重名称,但不包含第二个排序标准:

public int compare(Person p1, Person p2) {  
    int reVal = 1;

       if(p1.getName().compareTo(p2.getName()) != 0){
       reVal = 1;       
       }
       else {
       reVal = 0;       
       }                               
         return reVal;                  
    } 

下一个示例比较器应该对其余的对象集进行排序,这些对象不包含任何双重名称:

public int compare(Person p1, Person p2) {  
    boolean ageGt = (p1.getAge() > p2.getAge());
    int reVal = 1;

       if(p1.getName().compareTo(p2.getName()) != 0){
       if(scoreGt)
            reVal = -1;
       else 
            reVal = 1;      
       }
       else {
       reVal = 0;       
       }                               
         return reVal;                  
    } 

第二个比较器正确地按照年龄值对对象进行排序,但是它允许双重名称,这是我不理解的,因为如果两个对象的名称相等,则外部if语句已经被检查。为什么会这样?

1 个答案:

答案 0 :(得分:3)

这里有一个根本问题:您希望同时测试unicity 以订购条目。没有内置集合可以同时检查条目,它们的比较为0。

例如,两个Set实施是HashSetTreeSet

  • HashSet使用Object的{​​{1}} / .equals()来测试相等性;
  • .hashCode()使用TreeSet(或对象'Comparator功能实现它)来测试是否相等。

这不是一回事。事实上,对于一个特定的JDK类,即Comparable,这可能会非常令人惊讶:

BigDecimal

你不能同时吃蛋糕而且吃它。在这里,您想根据年龄根据名称和比较来测试unicity,您必须使用final BigDecimal one = new BigDecimal("1"); final BigDecimal oneDotZero = new BigDecimal("1.0"); final Set<BigDecimal> hashSet = new HashSet<>(); // BigDecimal implements Comparable of itself, so we can use that final Set<BigDecimal> treeSet = new TreeSet<>(); hashSet.add(one); hashSet.add(oneDotZero); // hashSet's size is 2: one.equals(oneDotZero) == false treeSet.add(one); treeSet.add(oneDotZero); // treeSet's size is... 1! one.compareTo(oneDotZero) == 0

为了获得排序的人员列表,您必须复制此地图的Map作为列表并使用.values()。如果您使用Guava,后一部分就像Collections.sort()一样简单,只要您的值实现Ordering.natural().sortedCopy(theMap.values())