2013-06-06 5 views
0

У меня есть простой класс, который содержит строку (имя) и целое число (возраст). Объекты, которые должны храниться в коллекции, не должны иметь двойных именных значений и сортироваться в соответствии с возрастами возраста. Первый пример кода удаляет все двойные имена, но не содержит второй критерий заказа:Компаратор Java: два критерия заказа

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-statement уже проверен, если имена обоих объектов равны. Почему это происходит?

+0

Что вы имеете в виду под двойным именем? –

+0

@kocko Я думаю, что он означает, что у него не может быть два объекта с тем же именем, поэтому, если они имеют одинаковое имя, они считаются равными. – jazzbassrob

+4

Компаратор _not_ предназначен для проверки на единство. Если вы хотите проверить уникальность имен, вы должны использовать «Карта» с именами в качестве ключей и лиц в качестве значений. – fge

ответ

3

У вас есть фундаментальная проблема: вы хотите в то же время протестировать для однозначности и, чтобы заказать записи. Там нет встроенной коллекции, которая будет проверять, в то же время, что записи равны и, что их сравнение 0.

Например, два Set реализации HashSet и TreeSet:

  • HashSet использует Object ' s .equals()/.hashCode() для проверки равенства;
  • TreeSet использует Comparator (или объекты «Comparable», если они их реализуют) для проверки на равенство.

Это не совсем то же самое. На самом деле, с одним конкретным классом JDK, то есть, BigDecimal, это может быть довольно удивительно:

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() в виде списка и использовать Collections.sort(). Если вы используете Guava, эта последняя часть так же проста, как Ordering.natural().sortedCopy(theMap.values()), при условии, что ваши значения реализуются Comparable.

+0

Спасибо. Может ли быть хорошим выбором для перезаписи метода 'equals()' класса объекта? В этом случае мне нужно было бы только вызвать 'mySet.contains (o1)' перед тем, как добавить объект o1 в коллекцию. Впоследствии уникальность гарантируется в соответствии с равным контрактом. – user1812379

+0

Если вы переопределите '.equals()', вы также должны переопределить '.hashCode()'! И да, если вы используете эти значения в 'Set', который зависит от равенства, вы все равно должны это делать. – fge

+0

Но 'hashCode()' необходимо только для коллекций на основе хэша, не так ли? Другие просто игнорируют это. В этом случае, может ли 'name.hashCode()' быть простым, но жизнеспособным хеш-кодом? Спасибо. – user1812379

Смежные вопросы