← Назад к вопросам
Как сортировать Stream
1.0 Junior🔥 221 комментариев
#Stream API и функциональное программирование
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Как сортировать Stream в Java
Stream API в Java 8+ предоставляет мощный и гибкий инструмент для сортировки данных. Рассмотрим все основные способы.
Базовая сортировка с sorted()
Сортировка примитивных типов:
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9, 3);
// Восходящий порядок (по умолчанию)
List<Integer> sorted = numbers.stream()
.sorted()
.collect(Collectors.toList());
// Результат: [1, 2, 3, 5, 8, 9]
// Нисходящий порядок
List<Integer> reversed = numbers.stream()
.sorted(Collections.reverseOrder())
.collect(Collectors.toList());
// Результат: [9, 8, 5, 3, 2, 1]
Сортировка строк:
List<String> words = Arrays.asList("zebra", "apple", "banana");
// По алфавиту
List<String> sorted = words.stream()
.sorted()
.collect(Collectors.toList());
// Результат: [apple, banana, zebra]
// Игнорируя регистр
List<String> sortedIgnoreCase = words.stream()
.sorted(String::compareToIgnoreCase)
.collect(Collectors.toList());
// По длине строки
List<String> sortedByLength = words.stream()
.sorted(Comparator.comparingInt(String::length))
.collect(Collectors.toList());
// Результат: [apple, zebra, banana]
Сортировка объектов
Сортировка по одному полю:
public class User {
private Long id;
private String name;
private int age;
// Constructor, getters, setters
}
List<User> users = Arrays.asList(
new User(1L, "Alice", 28),
new User(2L, "Bob", 25),
new User(3L, "Charlie", 32)
);
// Сортировка по имени
List<User> sortedByName = users.stream()
.sorted(Comparator.comparing(User::getName))
.collect(Collectors.toList());
// Сортировка по возрасту
List<User> sortedByAge = users.stream()
.sorted(Comparator.comparingInt(User::getAge))
.collect(Collectors.toList());
// Сортировка в обратном порядке
List<User> sortedByAgeDesc = users.stream()
.sorted(Comparator.comparingInt(User::getAge).reversed())
.collect(Collectors.toList());
Многоуровневая сортировка
Сортировка по нескольким критериям:
public class Employee {
private String department;
private String name;
private double salary;
}
List<Employee> employees = Arrays.asList(...);
// Сортировка: сначала по department, потом по salary (убывающий)
List<Employee> sorted = employees.stream()
.sorted(Comparator
.comparing(Employee::getDepartment)
.thenComparingDouble(Employee::getSalary).reversed())
.collect(Collectors.toList());
// Более сложный пример
List<Employee> sorted2 = employees.stream()
.sorted(Comparator
.comparing(Employee::getDepartment) // По отделу
.thenComparingInt(e -> e.getName().length()) // По длине имени
.thenComparingDouble(Employee::getSalary)) // По зарплате
.collect(Collectors.toList());
Пользовательские компараторы
Написание собственного Comparator:
// Вариант 1: Через лямбду
List<String> words = Arrays.asList("apple", "pie", "zoo");
List<String> sorted = words.stream()
.sorted((a, b) -> Integer.compare(b.length(), a.length())) // По убыванию длины
.collect(Collectors.toList());
// Вариант 2: Через метод
Comparator<String> byLength = (a, b) -> Integer.compare(a.length(), b.length());
List<String> sorted2 = words.stream()
.sorted(byLength.reversed())
.collect(Collectors.toList());
// Вариант 3: Класс с implements Comparator
public class UserAgeComparator implements Comparator<User> {
@Override
public int compare(User u1, User u2) {
return Integer.compare(u1.getAge(), u2.getAge());
}
}
List<User> sorted3 = users.stream()
.sorted(new UserAgeComparator())
.collect(Collectors.toList());
Сортировка с null значениями
Обработка null элементов:
List<String> words = Arrays.asList("apple", null, "zebra", "banana");
// Null значения в конце
List<String> sorted1 = words.stream()
.sorted(Comparator.nullsLast(Comparator.naturalOrder()))
.collect(Collectors.toList());
// Результат: [apple, banana, zebra, null]
// Null значения в начале
List<String> sorted2 = words.stream()
.sorted(Comparator.nullsFirst(Comparator.naturalOrder()))
.collect(Collectors.toList());
// Результат: [null, apple, banana, zebra]
// Для объектов
List<User> users2 = new ArrayList<>(users);
users2.add(null);
List<User> sorted = users2.stream()
.sorted(Comparator.nullsLast(
Comparator.comparing(User::getName)
))
.collect(Collectors.toList());
Производительность сортировки
Важные моменты:
// ❌ Плохо — сортирует всю коллекцию
List<User> users = ...;
List<User> top10 = users.stream()
.sorted(Comparator.comparingInt(User::getAge).reversed())
.limit(10)
.collect(Collectors.toList());
// ✅ Хорошо для больших данных
List<User> top10Better = users.stream()
.min(Comparator.comparing(Comparator.comparingInt(User::getAge).reversed())) // или использовать TreeSet
.collect(Collectors.toList());
// ✅ Или использовать PriorityQueue для топ N
PriorityQueue<User> topUsers = users.stream()
.reduce(new PriorityQueue<>(10, Comparator.comparingInt(User::getAge)),
(pq, user) -> { pq.offer(user); if(pq.size() > 10) pq.poll(); return pq; },
(pq1, pq2) -> { pq1.addAll(pq2); return pq1; });
Сортировка с фильтрацией
Комбинирование операций:
List<User> result = users.stream()
.filter(u -> u.getAge() > 25) // Фильтр
.sorted(Comparator.comparing(User::getName)) // Сортировка
.limit(5) // Лимит
.collect(Collectors.toList());
Параллельная сортировка Stream
Использование parallelStream():
List<Integer> largeList = IntStream.rangeClosed(1, 1_000_000)
.boxed()
.collect(Collectors.toList());
// Последовательная сортировка
long start = System.nanoTime();
List<Integer> sorted1 = largeList.stream()
.sorted()
.collect(Collectors.toList());
long sequential = System.nanoTime() - start;
// Параллельная сортировка (для больших объёмов)
start = System.nanoTime();
List<Integer> sorted2 = largeList.parallelStream()
.sorted()
.collect(Collectors.toList());
long parallel = System.nanoTime() - start;
System.out.println("Sequential: " + sequential + "ns");
System.out.println("Parallel: " + parallel + "ns");
Рекомендации по параллельной сортировке:
- Используй для больших коллекций (>10,000 элементов)
- Сортировка уже параллелизована внутри (Fork/Join pool)
- Перед sorted() не используй expensive фильтры
Практический пример: Сортировка в реальном приложении
@Service
public class UserService {
public List<UserResponse> getUsersSorted(String sortBy, String order) {
List<User> users = userRepository.findAll();
Comparator<User> comparator = switch(sortBy) {
case "name" -> Comparator.comparing(User::getName);
case "age" -> Comparator.comparingInt(User::getAge);
case "email" -> Comparator.comparing(User::getEmail);
default -> Comparator.comparing(User::getId);
};
if ("desc".equalsIgnoreCase(order)) {
comparator = comparator.reversed();
}
return users.stream()
.sorted(comparator)
.map(UserResponse::fromUser)
.collect(Collectors.toList());
}
}
Итог: Stream API предоставляет гибкий механизм для сортировки через sorted() метод с поддержкой Comparator. Можно использовать встроенные компараторы, писать свои, объединять несколько критериев и обрабатывать null значения.