Looking for java Keywords? Try Ask4Keywords

Java Language TreeMap / TreeSet настраиваемого типа Java


пример

Поскольку TreeMap s и TreeSet сохраняют ключи / элементы в соответствии с их естественным порядком . Для этого ключи TreeMap и элементы TreeSet должны сопоставляться друг с другом.

Скажем, у нас есть пользовательский класс Person :

public class Person  {

    private int id;
    private String firstName, lastName;
    private Date birthday;

    //... Constuctors, getters, setters and various methods
}

Если мы сохраним его как-есть в TreeSet (или ключ в TreeMap):

TreeSet<Person2> set = ...      
set.add(new Person(1,"first","last",Date.from(Instant.now())));

Тогда мы столкнулись бы с Исключением, таким как этот:

Exception in thread "main" java.lang.ClassCastException: Person cannot be cast to java.lang.Comparable
    at java.util.TreeMap.compare(TreeMap.java:1294)
    at java.util.TreeMap.put(TreeMap.java:538)
    at java.util.TreeSet.add(TreeSet.java:255)

Чтобы исправить это, предположим, что мы хотим заказать экземпляры Person на основе порядка их идентификаторов ( private int id ). Мы могли бы сделать это одним из двух способов:

  1. Одним из решений является изменение Person чтобы он реализовал интерфейс Comparable :

    public class Person implements Comparable<Person> {
        private int id;
        private String firstName, lastName;
        private Date birthday;
    
        //... Constuctors, getters, setters and various methods
    
        @Override
        public int compareTo(Person o) {
            return Integer.compare(this.id, o.id); //Compare by id
        }
    }
    
  2. Еще одно решение - предоставить TreeSet компаратору :

Java SE 8
TreeSet<Person> treeSet = new TreeSet<>((personA, personB) -> Integer.compare(personA.getId(), personB.getId()));
TreeSet<Person> treeSet = new TreeSet<>(new Comparator<Person>(){
    @Override
    public int compare(Person personA, Person personB) {
        return Integer.compare(personA.getId(), personB.getId());
    }
});

Однако есть два оговорки к обоим подходам:

  1. Очень важно не изменять какие-либо поля, используемые для упорядочения, как только экземпляр был вставлен в TreeSet / TreeMap . В приведенном выше примере, если мы изменим id человека, который уже вставлен в коллекцию, мы можем столкнуться с неожиданным поведением.

  2. Важно правильно и последовательно выполнять сравнение. Согласно Джавадоку :

Разработчик должен обеспечить sgn(x.compareTo(y)) == -sgn(y.compareTo(x)) для всех x и y. (Это означает, что x.compareTo(y) должен генерировать исключение, если y.compareTo(x) генерирует исключение).

Разработчик должен также гарантировать, что отношение транзитивно: (x.compareTo(y)>0 && y.compareTo(z)>0) подразумевает x.compareTo(z)>0 .

Наконец, разработчик должен убедиться, что x.compareTo(y)==0 означает, что sgn(x.compareTo(z)) == sgn(y.compareTo(z)) для всех z.