JavaRush /Java блог /Random /Кофе-брейк #253. В чем различие между Comparable и Compar...

Кофе-брейк #253. В чем различие между Comparable и Comparator. Что такое VarArgs (переменные аргументы) в Java

Статья из группы Random

В чем различие между Comparable и Comparator в Java

Источник: Medium В этом руководстве объясняется, что такое интерфейсы Comparable и Comparator, и как их можно использовать для сортировки коллекций в Java. Кофе-брейк #253. В чем различие между Comparable и Comparator. Что такое VarArgs (переменные аргументы) в Java - 1

Comparable

Comparable — это интерфейс, входящий в пакет java.lang и используемый для сортировки классов на основе их естественного порядка. Интерфейс Comparable должен быть реализован в классе, который будет использоваться для сортировки. Этот класс можно сортировать на основе отдельных атрибутов, таких как идентификатор, имя, отдел и так далее. Класс, реализующий интерфейс Comparable, сравнивает себя с другими объектами. Реализованный класс предлагает пользовательскую реализацию int CompareTo(T var1) для пользовательской сортировки. Метод int CompareTo(T var1) должен быть переопределен таким образом, чтобы:
  1. Он должен возвращать целое положительное значение Positive(+ve), если этот объект больше объекта сравнения.
  2. Он должен возвращать целое отрицательное значение Negative(-ve), если этот объект меньше объекта сравнения.
  3. Он должен вернуть Zero(0), если этот и сравниваемый объект равны.
При использовании класса Comparable можно сортировать только по одному атрибуту. Вот пример применения Comparable:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student  implements Comparable<Student>{
    private Integer id;
    private String name;
    private String department;

    @Override
    public int compareTo(Student student) {
       return this.name.compareTo(student.name);
    }
}

public class StudentComparableMain {
    public static void main(String[] args) {
        Student student=new Student(1,"John Doe","Java");
        Student student2=new Student(2,"Jane Doe","Java");
        Student student3=new Student(3,"Mike","Java");
        List<Student> students = Arrays.asList(student, student2,student3);
        System.out.println(students);
        
        Collections.sort(students);
        System.out.println(students);
    }
}
В приведенном выше примере кода первый оператор печати вернет список студентов в соответствии с порядком вставки.

[Student(id=1, name=John Doe, department=Java),
Student(id=2, name=Jane Doe, department=Java),
Student(id=3, name=Mike, department=Java)]
А второй оператор печати вернет список, отсортированный по именам студентов.

[Student(id=2, name=Jane Doe, department=Java), Метод int compare(T var1, T var2) должен быть реализован пользовательским классом comparator.
Student(id=1, name=John Doe, department=Java),
Student(id=3, name=Mike, department=Java)]

Comparator

Comparator — это интерфейс, входящий в пакет java.util, который также используется для сортировки коллекций в Java. В отличие от Comparable, интерфейс Comparator не обязательно должен быть реализован в исходном классе, его можно реализовать и в отдельном классе. Используя Comparator, мы можем сортировать список на основе различных атрибутов в соответствии с нашими требованиями. В компараторе два объекта передаются в метод сравнения и сравниваются друг с другом. Метод int Compare(T var1, T var2) должен быть реализован пользовательским классом компаратора. Метод int Compare(T var1, T var2) должен быть переопределен таким образом, чтобы:
  1. Он должен возвращать целое число положительное значение Positive(+ve), если первый объект больше второго объекта.
  2. Он должен возвращать целое отрицательное значение Negative(-ve), если первый объект меньше второго объекта.
  3. Он должен возвращать Zero(0), если оба объекта равны.
Пример использования Comparator:

import java.util.Comparator;

class StudentDeptComparator implements Comparator<Student> {

    @Override
    public int compare(Student s1, Student s2) {
        return s1.getDepartment().compareTo(s2.getDepartment());
    }
}

class StudentNameComparator implements Comparator<Student> {

    @Override
    public int compare(Student s1, Student s2) {
        return s1.getName().compareTo(s2.getName());
    }
}

Student student=new Student(1,"Jane","Java");
Student student2=new Student(2,"John","React");
Student student3=new Student(3,"Mike","BA");
List<Student> students = Arrays.asList(student, student2,student3);
        
// печатаем список согласно порядку вставки
System.out.println(students);
        
Collections.sort(students,new StudentDeptComparator());
// печатаем список, отсортированный по кафедрам студентов
System.out.println(students);

Collections.sort(students,new StudentNameComparator());
// печатаем список, отсортированный по именам студентов
System.out.println(students);
        
// сортируем список по имени и названию кафедры
Collections.sort(students,new StudentNameComparator().thenComparing(new StudentDeptComparator()));
System.out.println(students);
В приведенном выше примере кода первый оператор печати вернет список студентов в соответствии с порядком вставки.

[Student(id=1, name=Jane, department=Java),
Student(id=2, name=John, department=React),
Student(id=3, name=Mike, department=BA)]
Второй оператор печати вернет список, отсортированный по кафедре студентов.

[Student(id=3, name=Mike, department=BA),
Student(id=1, name=Jane, department=Java),
Student(id=2, name=John, department=React)]
Третий оператор печати вернет список, отсортированный по именам студентов.

[Student(id=1, name=Jane, department=Java),
Student(id=2, name=John, department=React),
Student(id=3, name=Mike, department=BA)]

Student student=new Student(1,"Jane","Java");
 Student student2=new Student(2,"Jane","BA");
 Student student3=new Student(3,"Mike","BA");
 Collections.sort(students,new StudentNameComparator()
                  .thenComparing(new StudentDeptComparator()));
 System.out.println(students);
Приведенный выше код сначала сортирует студентов по имени, а затем по кафедре. Результат оператора печати:

[Student(id=2, name=Jane, department=BA),
Student(id=1, name=Jane, department=Java),
Student(id=3, name=Mike, department=BA)]
Аналогично, Comparator также можно реализовать в лямбда-выражениях без использования какого-либо внешнего класса.

Collections.sort(
                students,
                (s1,s2)->{
                    return s1.getDepartment().compareTo(s2.getDepartment());
                }
        );
С помощью Comparable мы можем сортировать нашу коллекцию только на основе одного атрибута, а с помощью Comparator мы можем обеспечить собственную сортировку на основе нескольких атрибутов.

Заключение

И Comparable, и Comparator обычно используются в коллекциях Java для реализации функций сортировки. Comparable необходимо реализовать в классе, который требует сортировки, тогда как Comparator может быть реализован в другом классе или также может быть реализован с помощью лямбда-функции. Если нам нужна сортировка по естественному упорядочению на основе одного атрибута, то вам следует отдать предпочтение Comparable, а если требуется несколько стратегий сравнения, вместо этого рекомендуется использовать интерфейс Comparator.

Что такое VarArgs (переменные аргументы) в Java

Источник: Medium Благодаря этой публикации вы сможете понять о способе работы с переменными аргументами (VarArgs) в Java. VarArgs (Variable Arguments) означает переменные аргументы. В Java мы можем передавать переменное количество аргументов одного типа в один и тот же метод. Это упрощает создание методов, которым необходимо принимать переменное количество аргументов. До выпуска JDK 5 мы не могли объявить метод с переменным количеством аргументов. Аргументы переменной длины можно было обрабатывать либо с помощью перегруженных методов, либо путем передачи массива методу. Они оба часто приводят к ошибкам, и ухудшают читаемость кода. Чтобы решить эту проблему, в JDK 5 были введены переменные аргументы (Var Args). Переменный аргумент — это функция Java, которая позволяет нам передавать переменное количество аргументов одному методу. Но есть одно ограничение — они должны быть одного типа. VarArgs реализуется с использованием многоточия («...») в объявлении метода.

Public void myMethod(int... number){
 //body
 }
Мы можем использовать переменные аргументы в методе, который принимает ноль или более аргументов одного типа. Таким образом, при вызове метода мы можем передать ноль или более аргументов указанных типов, разделенных запятыми.

public class VarargsExample {
    public static void printNumbers(int... numbers) {
        System.out.println("Number of arguments: " + numbers.length);
        for (int num : numbers) {
            System.out.print(num + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        printNumbers();           // Вывод: Количество аргументов: 0
        printNumbers(1, 2, 3);   // Вывод: Количество аргументов: 3 1 2 3 
        printNumbers(10, 20);    // Вывод: Количество аргументов: 2 10 20
    }
}
Обратите внимание, что хотя мы также можем передавать аргументы переменной длины вместе с другими параметрами, перед этим следует убедиться, что существует только один параметр varargs и он должен быть записан последним в списке параметров объявления метода.

 Int myMethod(int a, float b, double...c){
  //Body
 }
Важные моменты относительно VarArgs:
  • VarArgs также можно перегружать, но перегрузка может привести к неоднозначности.
  • В методе может быть только один переменный аргумент.
  • VarArgs должны быть последним аргументом.
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Justinian Уровень 41 Master
30 августа 2023
Еще спрашивают, Comparator Comparable, они оба функциональные интерфейсы? У них есть аннотация функциональный интерфейс, если да/нет, то почему. Вывод мне не очень был понятен. Comparable принимает один объект и сравнивает этот объект с классом, в котором имплементирован. Если у нас есть Student, и мы хотим чтобы он адекватно в TreeSet к примеру добавлялся или нам нужно чтобы была некая дефолтная и часто используемая логика сравнения, мы используем Comparable. Comparable можно увидеть в классах String, Integer и тд именно поэтому и работает упорядчивание если бросить в сортируемые коллекции. Comparator это интерфейс, метод которого принимает некие два объекта и сравнивает их. Имплементация - физически сам метод compare у Comparable находится всредине класса, который сравнивается (поскольку он принимает лишь 1 аргумент и сравнивает этот аргумент с самим собой конкретного экземпляра класса) Имплементация Comparator находится где угодно. Это просто логика сравнения двух любых объектом. Чем Comparator удобен, мы можем менять сколько угодно и как угодно логику сравнения, писать новые, БЕЗ изменения самого класса, чей тип сравнивается. Это удобно, поскольку логика сравнения то может быть не одна - сортировать по цвету, или по возрасту или по имени или по всем сразу, с Comparable это в принципе невозможно, он позволяет только одну имплементацию использовать. А Comparator мы можем написать хоть 10 штук. Кроме того в больших программах все расположено по слоям, если мы в одном месте программы работаем с функциональностью и нам нужно отсортировать Студентов по имени, то мы здесь пишем компаратом и сортируем. Зачем нам бежать в класс Студент и менять там имплементацию на имя? А если нам нужно в программе две функциональности, сортировать по имени и сортировать по цвету глаз, мы не сможем это сделать с Comparable. А компаратор легко, написали два компаратора и используем когда какой нужно. И класс Студент спокойный и никто его не правит при каждом чихе