Collection. Как создать отсортированную коллекцию?

В данном уроке я бы хоте показать, каким образом можно создать коллеккцию, для хранение объектов в сортированом виде.

Где вам это может пригодится?

Допустим у вас есть надор данных, а точней набор объектов с данными, и вы их помещаете в список, коллекцию, но как известно, то в не все коллекции сохраняют порядок добавления, а также не все имеют возможность сортировать элементы.

Что же делать в том случае, когда вам нужно отсортировать элементы коллекции? Именно это мы сейчас и рассмотрим.

На днях мне пришлось применить данный способ сортировки, вот я решил им поделится с вами. В этом примере мы научимся сортировать по дате рождения, и по возврасту.

Хочу обратить ваше внимание, что данные для тестирование сортировки были придуманы, и не соответствуют реальным.

 

Шаг 1. Создание проекта и его структура

По традиции всех уроков как всегда создаем проект:

А структура всего проекта будет достаточно проста:

Теперь кратко о структуре. Как вы видите есть два пакета comparator и pojo в первом будут лежать компараторы (будут рассмотрены ниже), а во втором наш объект который мы будем сортировать.

Все это мы будем проверять с помощью JUnit 4.11 вот зависимость для pom.xml:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
</dependency>

На этом этап подготовки закончен, давайте теперь напишем POJO.

 

Шаг 2. Создание POJO

Я создал простой объект с 3-мя полями и назвалд его People, который имеет имя, возвраст и дату рождения:

package com.devcolibri.exam.pojo;

import java.util.Date;

public class People {

    private String fullName;
    private int age;
    private Date birthday;

    public People(String fullName, int age, Date birthday) {
        this.fullName = fullName;
        this.age = age;
        this.birthday = birthday;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String fullName) {
        this.fullName = fullName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + " {" +
                "\n\tName: " + this.fullName + ";" +
                "\n\tAge: " + this.age + ";" +
                "\n\tBirthday: " + birthday +
                "\n}";
    }
}

Как видите я переопределил метод toString(), чтобы было удобней выводить его содержимое в тестах.

 

Шаг 3. Создание компараторов

Что такое компаратор в Java Collection?

Это класс позволяющий сравнивать данные для их разделение, и с его помощью можно сравнивать данные обьекта для того чтобы определить куда его вставить в списке.

А теперь создадим первый компаратор, который будет сортировать по дате рождения. Создаем класс и называем его PeopleBirthdayComparator:

package com.devcolibri.exam.comparator;

import com.devcolibri.exam.pojo.People;

import java.util.Comparator;

public class PeopleBirthdayComparator implements Comparator<People> {

    @Override
    public int compare(People people1, People people2) {
        return people1.getBirthday().compareTo(people2.getBirthday());
    }

}

Как видите он достаточно простой, мы реализуем интерфейс Comparator указываем ему дженерик наш объект — это тот объект, который будет добавляться в список.

Дальше мы должны реальзовать один метод compare в нем мы должны указать сравнение по дате, что и вернет нам число, которое определит позицию в списке.

Теперь создадим компаратор, который будет сортировать по возврасту человека, назовем его PeopleAgeComparator:

package com.devcolibri.exam.comparator;

import com.devcolibri.exam.pojo.People;

import java.util.Comparator;

public class PeopleAgeComparator implements Comparator<People> {
    @Override
    public int compare(People people1, People people2) {
        return people1.getAge() - people2.getAge();
    }
}

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

 

Шаг 4. Тестирование компараторов

Первым будем тестировать PeopleBirthdayComparator для него создаем в тестах класс PeopleBirthdayComparatorTest:

package com.devcolibri.exam.comparator;

import com.devcolibri.exam.pojo.People;
import org.junit.Before;
import org.junit.Test;

import java.util.GregorianCalendar;
import java.util.Set;
import java.util.TreeSet;

public class PeopleBirthdayComparatorTest {

    private Set<People> peoples;

    @Before
    public void setUp() throws Exception {
        // Инициализируем наш список и указываем наш компаратор
        // который будет выполнять фильтрацию элементов и их положение в списке
        peoples = new TreeSet<People>(new PeopleBirthdayComparator());
    }

    @Test
    public void testAddPeople() throws Exception {
        // Создаем тестовые объекты
        People people1 = new People("Alex Barchuk", 21, GregorianCalendar.getInstance().getTime());
        Thread.sleep(100);
        People people2 = new People("Jered Gogs", 54, GregorianCalendar.getInstance().getTime());
        Thread.sleep(100);
        People people3 = new People("Mike Devidson", 31, GregorianCalendar.getInstance().getTime());
        Thread.sleep(100);
        People people4 = new People("Steve Jobs", 40, GregorianCalendar.getInstance().getTime());
        Thread.sleep(100);

        // В любом порядке добавляем их в список
        // В зависимости от фильтра объекты будут в момент добавления
        // определять свое место с помощью компаратора и мы в итоге получим отсортированый список
        peoples.add(people1);
        peoples.add(people4);
        peoples.add(people3);
        peoples.add(people2);

        // Выводим все элементы списка 
        for(People people : peoples){
            System.out.println(people);
        }

    }
}

Как вы возможно заметили я после каждой инициализации вызываю Thread.sleep(100); чтобы поток заснул на 100 миллисекунд, это делается для того чтобы дата у каждого People была разной, потому-что если будет дата рождения одинаковой, то People не добавится в коллеуцию, так как это Set и в элементы одинаковые не повторяются.

А так как они у нас фильтруются нашим компаратором, то одинаковыми они будут считаться если дыты рождение совпадают вплоть до миллисекунд.

В результате мы получим в консоли вывод содержимого нашего списка, которое будет отсортированно по дате рождения:

People {
	Name: Alex Barchuk;
	Age: 21;
	Birthday: Fri Dec 20 15:42:15 EET 2013
}
People {
	Name: Jered Gogs;
	Age: 54;
	Birthday: Fri Dec 20 15:42:15 EET 2013
}
People {
	Name: Mike Devidson;
	Age: 31;
	Birthday: Fri Dec 20 15:42:16 EET 2013
}
People {
	Name: Steve Jobs;
	Age: 40;
	Birthday: Fri Dec 20 15:42:16 EET 2013
}

Как видите элементы вывелись не в том порядке в котором добавлялись, а в отсортированном по дате рождения. Дата рождения в мемент сортировки учитывалась вплоть до миллисекунд.

А теперь давайте протестироуем следующий компаратор, который сортирует по возврасту, для этого создадим класс и назовем его PeopleAgeComparatorTest:

package com.devcolibri.exam.comparator;

import com.devcolibri.exam.pojo.People;
import org.junit.Before;
import org.junit.Test;

import java.util.GregorianCalendar;
import java.util.Set;
import java.util.TreeSet;

public class PeopleAgeComparatorTest {

    private Set<People> peoples;

    @Before
    public void setUp() throws Exception {
        // Инициализируем наш компаратор для сортировки по возврасту
        peoples = new TreeSet<People>(new PeopleAgeComparator());
    }

    @Test
    public void testAddPeople() throws Exception {
        // Инициализируем всех People
        People people1 = new People("Alex Barchuk", 21, GregorianCalendar.getInstance().getTime());
        People people2 = new People("Jered Gogs", 54, GregorianCalendar.getInstance().getTime());
        People people3 = new People("Mike Devidson", 31, GregorianCalendar.getInstance().getTime());
        People people4 = new People("Steve Jobs", 40, GregorianCalendar.getInstance().getTime());

        // Добавялем элементы в коллекцию в любом порядке
        peoples.add(people1);
        peoples.add(people4);
        peoples.add(people3);
        peoples.add(people2);

        // Выводим элементы коллеуции
        for(People people : peoples){
            System.out.println(people);
        }

    }

}

И после выполнения данного теста мы увидим следующий результат:

People {
	Name: Alex Barchuk;
	Age: 21;
	Birthday: Fri Dec 20 15:48:56 EET 2013
}
People {
	Name: Mike Devidson;
	Age: 31;
	Birthday: Fri Dec 20 15:48:56 EET 2013
}
People {
	Name: Steve Jobs;
	Age: 40;
	Birthday: Fri Dec 20 15:48:56 EET 2013
}
People {
	Name: Jered Gogs;
	Age: 54;
	Birthday: Fri Dec 20 15:48:56 EET 2013
}

Как видите сортировка прошла по возврасту от меньшего к большему.

p.s. Спасибо за внимание, надеюсь данный материал вам помог.

Урок создан: 20 декабря 2013 | Просмотров: 16477 | Автор: Александр Барчук | Правила перепечатки


Добавить комментарий

Добавить комментарий

Ваш e-mail не будет опубликован.

Комментарии:

  • 09 января 2014 в 11:49

    Андрей

    Как сделать чтобы было отсортировано по возрасту и по каждому возрасту сортировка по дате?

  • 28 марта 2014 в 11:31

    Геннадий

    Опечатка в первом предложении. Допустим у вас есть надор данных. Удалите потом коммит

  • 02 декабря 2015 в 00:53

    Валерий

    А где тут мейн? Я не понял как это все дело запускается