Java for Beginner
672 subscribers
541 photos
155 videos
12 files
827 links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Comparable и Comparator, внутреннее устройство и варианты применения

Как работают Comparable и Comparator под капотом

Оба интерфейса используются в алгоритмах сортировки, таких как TimSort (применяется в Collections.sort() и Arrays.sort()). TimSort — это гибридный алгоритм, сочетающий сортировку слиянием и вставками, который оптимизирован для частично отсортированных данных.

Когда вы вызываете Collections.sort(), JVM передает объекты в метод compareTo (для Comparable) или compare (для Comparator). Алгоритм использует результаты сравнений для перестановки элементов.

Важно, чтобы реализация методов была консистентной:
Если a.compareTo(b) < 0, то b.compareTo(a) > 0.
Если a.compareTo(b) == 0, то b.compareTo(a) == 0.


Нарушение этих правил (например, несогласованность сравнений) может привести к некорректной сортировке или исключениям, таким как IllegalArgumentException.

Варианты применения

Сортировка по одному критерию с Comparable
Используется, когда класс имеет один логический порядок.

Например, класс Book может сортироваться по названию:
public class Book implements Comparable {

private String title; private double price;

public Book(String title, double price) {
this.title = title;
this.price = price;
}

@Override
public int compareTo(Book other) {
return this.title.compareTo(other.title);
}

}


Множественные критерии с Comparator
Comparator позволяет создавать разные способы сортировки.

Например, для класса Book можно создать несколько компараторов:
public class BookPriceComparator implements Comparator { 

@Override public int compare(Book b1, Book b2) {

return Double.compare(b1.getPrice(), b2.getPrice());

}
}

public class BookAuthorComparator implements Comparator {

@Override public int compare(Book b1, Book b2) {

return b1.getAuthor().compareTo(b2.getAuthor());
}
}


Использование:
List books = new ArrayList<>(); 
books.add(new Book("Java", 50.0));
books.add(new Book("Python", 40.0));
Collections.sort(books, new BookPriceComparator()); // Сортировка по цене


Лямбда-выражения и Comparator

С Java 8 можно использовать лямбда-выражения или метод Comparator.comparing() для упрощения кода:
List books = new ArrayList<>(); 
books.add(new Book("Java", 50.0));
books.add(new Book("Python", 40.0));
Collections.sort(books, Comparator.comparing(Book::getPrice)); // Сортировка по цене


Комбинированная сортировка

Comparator позволяет комбинировать критерии с помощью thenComparing():

List books = new ArrayList<>(); 
books.add(new Book("Java", 50.0));
books.add(new Book("Java", 40.0));
Collections.sort(books, Comparator.comparing(Book::getTitle) .thenComparing(Book::getPrice)); // Сначала по названию, затем по цене


#Java #Training #Medium #Comparable #Comparator
#Mems. Даже пауки вкатываются в IT.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Comparable и Comparator. Нюансы использования Comparable

Неизменяемость порядка
Если класс реализует Comparable, его порядок сортировки должен быть неизменным. Например, изменение поля, по которому происходит сортировка, после добавления объекта в отсортированную коллекцию (например, TreeSet), может нарушить инварианты коллекции.

Совместимость с equals
Желательно, чтобы compareTo был согласован с equals. Это значит, что если a.compareTo(b) == 0, то a.equals(b) должно быть true. Нарушение этого правила может привести к неожиданному поведению в коллекциях, таких как TreeSet или TreeMap.

Пример проблемы:
public class Person implements Comparable { 

private String name; private int age;

@Override
public int compareTo(Person other) {
return this.name.compareTo(other.name); // Сравнение только по имени
}

@Override
public boolean equals(Object obj) {
if (!(obj instanceof Person)) return false;
Person other = (Person) obj;
return this.name.equals(other.name) && this.age == other.age;
}

}


Здесь compareTo считает объекты равными, если совпадают имена, но equals требует совпадения и возраста. Это может вызвать проблемы в TreeSet, где два объекта с одинаковым именем, но разным возрастом будут считаться одинаковыми.

Null-обработка
Метод compareTo должен корректно обрабатывать null, иначе возможен NullPointerException.

Например:
@Override public int compareTo(Person other) {
if (other == null) return 1; // null считается "меньше" return this.age - other.age;
}


Нюансы использования Comparator

Гибкость и переиспользование
Comparator можно создавать динамически, что делает его более гибким.

Например, для одноразовой сортировки можно использовать лямбда-выражение:
List people = new ArrayList<>(); 

Collections.sort(people, (p1, p2) -> p2.getAge() - p1.getAge()); // Сортировка по убыванию возраста


Null-обработка
Comparator должен учитывать возможность null-значений.

Java 8 предоставляет методы для упрощения работы с null:
Comparator nullSafeComparator = Comparator .nullsFirst(Comparator.comparing(Person::getName)); // null-объекты будут первыми


Производительность
Частое создание новых объектов Comparator (например, в цикле) может быть неэффективным. Лучше сохранять и переиспользовать экземпляры Comparator.

Типичные ошибки

Несогласованность сравнений
Если compareTo или compare нарушают транзитивность (например, a < b и b < c, но a > c), сортировка может завершиться с ошибкой.

Использование вычитания для чисел
Вместо this.age - other.age лучше использовать Integer.compare(this.age, other.age), чтобы избежать переполнения при больших числах.

Игнорирование контракта
Реализация compareTo или compare должна быть рефлексивной, симметричной и транзитивной.

#Java #Training #Medium #Comparable #Comparator
Что выведет код?

import java.util.HashSet;

public class Task240425 {
public static void main(String[] args) {
HashSet<Magic> set = new HashSet<>();

Magic m1 = new Magic(1);
Magic m2 = new Magic(1);
Magic m3 = new Magic(2);

set.add(m1);
set.add(m2);
set.add(m3);

m3.value = 1;

set.remove(m1);
set.remove(new Magic(2));
set.remove(new Magic(1));

System.out.println(set.size());
}

static class Magic {
int value;

Magic(int value) {
this.value = value;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Magic magic = (Magic) o;
return value == magic.value;
}

@Override
public int hashCode() {
return value;
}
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
32%
0
32%
1
29%
2
7%
256
Визуальное представление слова "вые..ваться" 😜 😂

https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
Вопросы с собеседования 👩‍💻

Что делает метод split() в классе String?
Anonymous Quiz
13%
Объединяет строки
77%
Разделяет строку на массив подстрок
6%
Удаляет пробелы
4%
Заменяет символы
Comparable и Comparator. Практические примеры и рекомендации

Пример 1: Сортировка с учетом нескольких полей

Допустим, у нас есть класс Employee, который нужно сортировать сначала по отделу, а затем по зарплате:

public class Employee { 

private String department;
private double salary;

public Employee(String department, double salary) {
this.department = department;
this.salary = salary;
}

public String getDepartment() { return department; }
public double getSalary() { return salary; }

@Override
public String toString() {
return department + ": " + salary;
}

}


Сортировка с использованием Comparator:
List employees = new ArrayList<>(); 

employees.add(new Employee("HR", 50000));
employees.add(new Employee("IT", 60000));
employees.add(new Employee("HR", 45000));

Comparator comparator = Comparator.comparing(Employee::getDepartment).thenComparingDouble(Employee::getSalary);

Collections.sort(employees, comparator);

System.out.println(employees); // Вывод: [HR: 45000.0, HR: 50000.0, IT: 60000.0]


Пример 2: Обратная сортировка

Для сортировки в обратном порядке можно использовать reversed():
Comparator reverseComparator = Comparator.comparingDouble(Employee::getSalary).reversed();

Collections.sort(employees, reverseComparator);

System.out.println(employees); // Вывод: [IT: 60000.0, HR: 50000.0, HR: 45000.0]


Пример 3: Использование в TreeSet

TreeSet автоматически поддерживает порядок элементов, используя Comparable или Comparator:
TreeSet employeeSet = new TreeSet<>(Comparator.comparing(Employee::getDepartment).thenComparingDouble(Employee::getSalary)); 

employeeSet.add(new Employee("HR", 50000));
employeeSet.add(new Employee("IT", 60000));
employeeSet.add(new Employee("HR", 45000));

System.out.println(employeeSet); // Вывод: [HR: 45000.0, HR: 50000.0, IT: 60000.0]


Рекомендации

Выбирайте Comparable для естественного порядка
Если класс имеет очевидный порядок (например, числа, строки), реализуйте Comparable. Это упрощает использование класса в стандартных коллекциях.

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

Пользуйтесь Java 8+

Методы Comparator.comparing(), thenComparing() и лямбда-выражения значительно упрощают код.

Тестируйте сортировку
Убедитесь, что реализация compareTo и compare корректно обрабатывает краевые случаи (null, равные объекты, экстремальные значения).

Избегайте модификации отсортированных коллекций
Если объект в TreeSet или TreeMap изменяется так, что нарушается порядок, это может привести к некорректной работе коллекции.

#Java #Training #Medium #Comparable #Comparator
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Collectors в Java

Collectors в Java — это утилитный класс из пакета java.util.stream, введенный в Java 8 вместе с Stream API. Он предоставляет готовые реализации для выполнения операций сведения (reduction) над потоками данных. Основная задача Collectors — собирать элементы потока в коллекции, выполнять группировку, агрегацию или другие преобразования. Collectors используется в методе Stream.collect(), который является терминальной операцией, завершающей обработку потока.

Класс Collectors содержит статические методы, возвращающие объекты типа Collector<T, A, R>, где:
T — тип элементов в потоке.
A — тип промежуточного аккумулятора, используемого для накопления данных.
R — тип результата, который возвращается после обработки.


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


Collector состоит из четырех ключевых компонентов:
Supplier: создает начальный аккумулятор (например, новый ArrayList).
Accumulator: добавляет элемент потока в аккумулятор.
Combiner: объединяет два аккумулятора (используется в параллельных потоках).
Finisher: преобразует аккумулятор в конечный результат (например, возвращает коллекцию).


Пример простого использования:
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CollectorsExample {
public static void main(String[] args) {
Stream<String> stream = Stream.of("apple", "banana", "orange");
List<String> list = stream.collect(Collectors.toList());
System.out.println(list); // [apple, banana, orange]
}
}


Collectors часто используется для:
Сбора элементов в коллекции (List, Set, Map).
Группировки данных (groupingBy).
Объединения строк (joining).
Вычисления статистик (summingInt, averagingDouble).


#Java #Training #Medium #Collectors
Что выведет код?

import java.util.HashSet;

public class Task250425 {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();

String s1 = new String("hello");
String s2 = new String("hello");
String s3 = "hello";
String s4 = s1.intern();

set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(null);
set.add(null);

System.out.println(set.size());
}
}


#Tasks
Варианты ответа:
Anonymous Quiz
14%
1
38%
2
30%
3
19%
4
Надо сделать так, чтоб пет-проект стал рабочим! 😎

https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
Вопросы с собеседования 👩‍💻

Какой класс используется для работы с датами в Java 8 и новее?
Anonymous Quiz
14%
Date
67%
LocalDate
12%
Calendar
6%
Time
Collectors в Java

Collectors.toList

Collectors.toList() собирает элементы потока в List. Реализация по умолчанию возвращает ArrayList, но конкретная реализация не гарантируется и может измениться. Это один из самых простых и часто используемых коллекторов.

Пример:
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ToListExample {
public static void main(String[] args) {
Stream<String> stream = Stream.of("apple", "banana", "orange");
List<String> list = stream.collect(Collectors.toList());
System.out.println(list); // [apple, banana, orange]
}
}


Внутренне toList использует:
Supplier: new ArrayList<>()
Accumulator: list.add(element)
Combiner: list1.addAll(list2)
Finisher: возвращает сам аккумулятор (identity функция).


Особенности:
Сохраняет порядок элементов (если поток упорядочен).
Допускает дубликаты.
Не поддерживает настройку типа List (для этого есть toCollection).


Collectors.toSet

Collectors.toSet() собирает элементы потока в Set, по умолчанию возвращая HashSet. Как и в случае с toList, конкретная реализация не гарантируется.

Пример:
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ToSetExample {
public static void main(String[] args) {
Stream<String> stream = Stream.of("apple", "banana", "apple");
Set<String> set = stream.collect(Collectors.toSet());
System.out.println(set); // [apple, banana]
}
}


Внутренне toSet использует:
Supplier: new HashSet<>()
Accumulator: set.add(element)
Combiner: set1.addAll(set2)
Finisher: возвращает аккумулятор.


Особенности:
Удаляет дубликаты (Set не допускает повторяющихся элементов).
Не гарантирует порядок элементов (HashSet не сохраняет порядок).
Для упорядоченного множества можно использовать toCollection(TreeSet::new).


#Java #Training #Medium #Collectors #CollectorsToList #CollectorsToSet
Всем доброго, субботнего утра! ☀️

Надеюсь, что у всех все хорошо и очередная суббота позволит отдохнуть и восстановить силы перед напряженными 3-х дневными рабочими неделями 🤣

Сегодня как всегда мы посмотрим мемчики, а вот завтра вечером жду всех на лайф кодинге!
@Shikin_Anatoliy допишет свой футбольный сервис! Так что приходите, двери открыты для усех❤️

А в остальном, всем и каждому, просто хороших выходных!
💃
Please open Telegram to view this post
VIEW IN TELEGRAM