← Назад к вопросам
В чем разница между peek() и sorted()?
1.3 Junior🔥 181 комментариев
#Stream API и функциональное программирование#Основы Java
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Peek() vs Sorted() в Java Stream API
Основное различие
peek() — промежуточная операция для отладки/логирования, не изменяет Stream.
sorted() — промежуточная операция для сортировки, изменяет порядок элементов.
Оба — промежуточные операции (intermediate), но имеют разные назначение и поведение.
Peek() — операция для отладки
List<Integer> numbers = List.of(3, 1, 4, 1, 5);
List<Integer> result = numbers.stream()
.peek(n -> System.out.println("Original: " + n)) // Видит каждый элемент
.map(n -> n * 2)
.peek(n -> System.out.println("After map: " + n))
.toList();
// Вывод:
// Original: 3
// After map: 6
// Original: 1
// After map: 2
// Original: 4
// After map: 8
// Original: 1
// After map: 2
// Original: 5
// After map: 10
Характеристики peek():
- Промежуточная операция (intermediate operation)
- Не изменяет Stream
- Ленивая (lazy) — выполняется только при terminal операции
- Для отладки/логирования
- Принимает Consumer<T> (void функцию)
- Возвращает Stream без изменений
- Элементы проходят через peek в том же порядке
Синтаксис peek()
Stream.peek(element -> { /* действие, не возвращает ничего */ });
// Примеры
stream.peek(System.out::println);
stream.peek(item -> logger.debug(item));
stream.peek(n -> counter.increment());
Когда использовать peek()
// ✅ Для отладки
List<User> users = userList.stream()
.filter(u -> u.getAge() > 18)
.peek(u -> System.out.println("Adult user: " + u.getName())) // Отладка
.toList();
// ✅ Для логирования
List<Product> products = productList.stream()
.filter(p -> p.getPrice() > 100)
.peek(p -> logger.info("Expensive product: " + p.getName()))
.toList();
// ✅ Для сбора метрик
List<Integer> numbers = numberList.stream()
.map(n -> n * 2)
.peek(n -> metrics.recordValue(n))
.toList();
// ❌ Не использовать для изменения состояния!
struct.peek(item -> item.setProcessed(true)); // Плохая практика
Sorted() — операция сортировки
List<Integer> numbers = List.of(3, 1, 4, 1, 5);
List<Integer> result = numbers.stream()
.sorted()
.toList();
System.out.println(result); // [1, 1, 3, 4, 5]
Характеристики sorted():
- Промежуточная операция (intermediate operation)
- Изменяет порядок элементов в Stream
- Требует буферизации — должна получить все элементы перед сортировкой
- Stateful — требует состояния (весь Stream в памяти)
- Ленивая (lazy) — но буферизирует при выполнении
- Может принимать Comparator
- Возвращает отсортированный Stream
Синтаксис sorted()
// Сортировка по умолчанию (естественный порядок)
Stream.sorted();
// Сортировка с Comparator
Stream.sorted(Comparator.comparingInt(o -> o));
Stream.sorted((a, b) -> a.compareTo(b));
// Примеры
stream.sorted();
stream.sorted(Comparator.naturalOrder());
stream.sorted(Comparator.reverseOrder());
stream.sorted(Comparator.comparingInt(String::length));
stream.sorted((a, b) -> b.compareTo(a)); // Обратный порядок
Примеры sorted()
List<String> words = Arrays.asList("apple", "banana", "cherry");
// Сортировка по алфавиту
List<String> sorted = words.stream()
.sorted()
.toList();
System.out.println(sorted); // [apple, banana, cherry]
// Обратная сортировка
List<String> reversed = words.stream()
.sorted(Comparator.reverseOrder())
.toList();
System.out.println(reversed); // [cherry, banana, apple]
// Сортировка по длине
List<String> byLength = words.stream()
.sorted(Comparator.comparingInt(String::length))
.toList();
System.out.println(byLength); // [apple, banana, cherry]
// Сортировка по длине (обратно)
List<String> byLengthReverse = words.stream()
.sorted(Comparator.comparingInt(String::length).reversed())
.toList();
System.out.println(byLengthReverse); // [banana, cherry, apple]
Детальное сравнение
| Аспект | Peek() | Sorted() |
|---|---|---|
| Назначение | Отладка, логирование | Сортировка |
| Тип операции | Intermediate (промежуточная) | Intermediate (промежуточная) |
| Изменяет Stream | Нет | Да (порядок элементов) |
| Параметр | Consumer<T> (void функция) | Comparator или ничего |
| Возвращает | Исходный Stream без изменений | Отсортированный Stream |
| Ленивость | Lazy (по требованию) | Lazy (но требует буферизации) |
| Памяти | O(1) на элемент | O(n) (весь Stream) |
| Производительность | O(n) | O(n log n) обычно |
| Порядок элементов | Сохраняется | Изменяется |
| Статефул | Нет | Да (требует состояния) |
| Используется в production | Редко (только отладка) | Часто (функциональное) |
Практические примеры
Peek() для отладки
List<Integer> numbers = Arrays.asList(5, 2, 8, 1, 9);
List<Integer> result = numbers.stream()
.filter(n -> n > 2)
.peek(n -> System.out.println("After filter: " + n))
.map(n -> n * n)
.peek(n -> System.out.println("After map: " + n))
.toList();
// Вывод:
// After filter: 5
// After map: 25
// After filter: 8
// After map: 64
// After filter: 9
// After map: 81
Sorted() для порядка
List<String> names = Arrays.asList("Charlie", "Alice", "Bob");
List<String> sorted = names.stream()
.sorted()
.toList();
System.out.println(sorted); // [Alice, Bob, Charlie]
Комбинация: peek() + sorted()
List<Integer> numbers = Arrays.asList(3, 1, 4, 1, 5);
List<Integer> result = numbers.stream()
.peek(n -> System.out.println("Before sort: " + n))
.sorted()
.peek(n -> System.out.println("After sort: " + n))
.toList();
// Вывод:
// Before sort: 3
// Before sort: 1
// Before sort: 4
// Before sort: 1
// Before sort: 5
// After sort: 1
// After sort: 1
// After sort: 3
// After sort: 4
// After sort: 5
Сортировка объектов
public class Product {
private String name;
private double price;
// getters, constructor
}
List<Product> products = Arrays.asList(
new Product("Laptop", 1200),
new Product("Mouse", 25),
new Product("Keyboard", 75)
);
// Сортировка по цене
List<Product> byPrice = products.stream()
.sorted(Comparator.comparingDouble(Product::getPrice))
.peek(p -> System.out.println(p.getName() + ": $" + p.getPrice()))
.toList();
// Вывод:
// Mouse: $25
// Keyboard: $75
// Laptop: $1200
Производительность
Peek() — O(n), не буферизирует
stream.peek(x -> {}) // Просто проходит через каждый элемент
Sorted() — O(n log n), буферизирует всё
stream.sorted() // Должна получить все элементы, отсортировать, потом отпустить
// На 1 млн элементов
List<Integer> million = IntStream.range(0, 1_000_000).boxed().toList();
// Peek — быстро
long start = System.currentTimeMillis();
million.stream()
.peek(x -> {}) // O(n)
.toList();
long peekTime = System.currentTimeMillis() - start; // ~10ms
// Sorted — медленнее
start = System.currentTimeMillis();
million.stream()
.sorted() // O(n log n)
.toList();
long sortTime = System.currentTimeMillis() - start; // ~200ms
Антипаттерны
// ❌ Плохо: используем peek() для изменения состояния
struct.peek(item -> item.setProcessed(true)); // Побочный эффект!
// ✅ Хорошо: используем map() для трансформации
struct.map(item -> {
item.setProcessed(true);
return item;
});
// ✅ Лучше: просто используй forEachпо необходимости
struct.forEach(item -> item.setProcessed(true));
Ещё про промежуточные операции
// Все промежуточные операции Stream API
stream.filter(predicate) // Отфильтровать
stream.map(function) // Трансформировать
stream.flatMap(function) // Развернуть вложенные стримы
stream.sorted() // Отсортировать
stream.distinct() // Удалить дубликаты
stream.limit(n) // Ограничить количество
stream.skip(n) // Пропустить n элементов
stream.peek(consumer) // Отладка (side effect)
Заключение
peek()— вспомогательная операция для отладки и логирования, не изменяет Stream, O(n)sorted()— сортирует элементы, изменяет порядок, требует буферизации всех элементов, O(n log n)- Обе операции промежуточные (intermediate), но с разными целями
peek()для отладки,sorted()для функциональности- Не используй
peek()для побочных эффектов в production коде