← Назад к вопросам
В какие коллекции собирал Stream
1.6 Junior🔥 221 комментариев
#Stream API и функциональное программирование#Коллекции
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Собрание Stream в коллекции с помощью Collectors
Stream в Java — это не коллекция, а способ обработки данных. Когда нужно собрать результаты Stream в коллекцию, используют Collectors. Это один из самых частых вопросов в собеседованиях.
Основной способ: collect() с Collectors
import java.util.stream.Collectors;
import java.util.*;
public class StreamCollectorsExample {
// 1. Собрание в List (самый частый случай)
@Test
public void collectToList() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> evenNumbers = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList()); // или toUnmodifiableList()
System.out.println(evenNumbers); // [2, 4]
}
// 2. Собрание в Set
@Test
public void collectToSet() {
List<Integer> numbers = Arrays.asList(1, 2, 2, 3, 3, 3);
Set<Integer> uniqueNumbers = numbers.stream()
.collect(Collectors.toSet()); // HashSet
System.out.println(uniqueNumbers); // [1, 2, 3]
}
// 3. Собрание в конкретный Set (TreeSet, LinkedHashSet)
@Test
public void collectToSpecificSet() {
List<Integer> numbers = Arrays.asList(3, 1, 2);
TreeSet<Integer> sorted = numbers.stream()
.collect(Collectors.toCollection(TreeSet::new));
System.out.println(sorted); // [1, 2, 3] в порядке сортировки
}
// 4. Собрание в Map
@Test
public void collectToMap() {
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
// Ключ: имя, Значение: длина
Map<String, Integer> nameLength = names.stream()
.collect(Collectors.toMap(
Function.identity(), // ключ: само имя
String::length // значение: длина имени
));
System.out.println(nameLength);
// {Alice=5, Bob=3, Charlie=7}
}
}
Разные типы коллекций
public class CollectorsTypesExample {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
// List — изменяемый список
List<Integer> list = numbers.stream()
.filter(n -> n > 2)
.collect(Collectors.toList());
// Результат: [3, 4, 5]
// Unmodifiable List (Java 10+) — неизменяемый
List<Integer> unmodifiableList = numbers.stream()
.filter(n -> n > 2)
.collect(Collectors.toUnmodifiableList());
// Результат: [3, 4, 5] (read-only)
// Set — уникальные элементы
Set<Integer> set = numbers.stream()
.filter(n -> n > 2)
.collect(Collectors.toSet());
// Результат: [3, 4, 5] (порядок не гарантирован)
// LinkedHashSet — с сохранением порядка
Set<Integer> linkedSet = numbers.stream()
.filter(n -> n > 2)
.collect(Collectors.toCollection(LinkedHashSet::new));
// Результат: [3, 4, 5] (порядок сохранён)
// TreeSet — отсортированный
Set<Integer> treeSet = numbers.stream()
.filter(n -> n > 2)
.collect(Collectors.toCollection(TreeSet::new));
// Результат: [3, 4, 5] (отсортировано)
// Map — собрание в пары ключ-значение
Map<Integer, String> map = numbers.stream()
.collect(Collectors.toMap(
n -> n,
n -> "num_" + n
));
// Результат: {1=num_1, 2=num_2, ...}
// LinkedHashMap — Map с сохранением порядка
Map<Integer, String> linkedMap = numbers.stream()
.collect(Collectors.toMap(
n -> n,
n -> "num_" + n,
(a, b) -> a, // merge function (для дубликатов)
LinkedHashMap::new
));
// ConcurrentHashMap — потокобезопасный Map
Map<Integer, String> concurrent = numbers.stream()
.collect(Collectors.toMap(
n -> n,
n -> "num_" + n,
(a, b) -> a,
ConcurrentHashMap::new
));
}
Продвинутые техники
Grouping By (группировка по критерию)
public class GroupingExample {
@Test
public void groupByExample() {
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 25),
new Person("David", 30)
);
// Группировка по возрасту
Map<Integer, List<Person>> byAge = people.stream()
.collect(Collectors.groupingBy(Person::getAge));
System.out.println(byAge);
// {
// 25=[Alice, Charlie],
// 30=[Bob, David]
// }
}
@Test
public void groupingWithDownstream() {
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 25)
);
// Группировка по возрасту с подсчётом
Map<Integer, Long> ageCount = people.stream()
.collect(Collectors.groupingBy(
Person::getAge,
Collectors.counting() // downstream collector
));
System.out.println(ageCount);
// {25=2, 30=1}
}
@Test
public void groupingWithMapping() {
List<Person> people = Arrays.asList(
new Person("Alice", 25),
new Person("Bob", 30),
new Person("Charlie", 25)
);
// Группировка по возрасту, собрание имён
Map<Integer, List<String>> namesByAge = people.stream()
.collect(Collectors.groupingBy(
Person::getAge,
Collectors.mapping(
Person::getName,
Collectors.toList()
)
));
System.out.println(namesByAge);
// {
// 25=[Alice, Charlie],
// 30=[Bob]
// }
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
@Override
public String toString() { return name; }
}
Partitioning By (разбиение на две части)
public class PartitioningExample {
@Test
public void partitioningExample() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
// Разбиение на чётные и нечётные
Map<Boolean, List<Integer>> evenOdd = numbers.stream()
.collect(Collectors.partitioningBy(n -> n % 2 == 0));
System.out.println("Even: " + evenOdd.get(true)); // [2, 4, 6]
System.out.println("Odd: " + evenOdd.get(false)); // [1, 3, 5]
}
@Test
public void partitioningWithDownstream() {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
// Разбиение с подсчётом
Map<Boolean, Long> evenOddCount = numbers.stream()
.collect(Collectors.partitioningBy(
n -> n % 2 == 0,
Collectors.counting()
));
System.out.println("Even count: " + evenOddCount.get(true)); // 3
System.out.println("Odd count: " + evenOddCount.get(false)); // 3
}
}
Joining (соединение строк)
public class JoiningExample {
@Test
public void joiningStrings() {
List<String> words = Arrays.asList("Hello", "World", "Java");
// Соединение с разделителем
String result = words.stream()
.collect(Collectors.joining(", "));
System.out.println(result); // Hello, World, Java
}
@Test
public void joiningWithPrefixSuffix() {
List<String> words = Arrays.asList("Hello", "World");
String result = words.stream()
.collect(Collectors.joining(", ", "[", "]"));
System.out.println(result); // [Hello, World]
}
}
Практическое сравнение
public class PracticalComparison {
List<String> names = Arrays.asList(
"Alice", "Bob", "Charlie", "David", "Eve"
);
// ✅ Когда нужен порядок и модификация -> List
List<String> toList = names.stream()
.filter(s -> s.length() > 3)
.collect(Collectors.toList());
// ✅ Когда нужны уникальные значения -> Set
Set<String> toSet = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toSet());
// ✅ Когда нужна пара ключ-значение -> Map
Map<String, Integer> toMap = names.stream()
.collect(Collectors.toMap(
s -> s,
String::length
));
// ✅ Когда нужно перенести в специфичный тип
TreeSet<String> toTreeSet = names.stream()
.collect(Collectors.toCollection(TreeSet::new));
// ✅ Когда нужно разбить данные
Map<Boolean, List<String>> partition = names.stream()
.collect(Collectors.partitioningBy(s -> s.length() > 3));
// ✅ Когда нужно сгруппировать
Map<Integer, List<String>> grouped = names.stream()
.collect(Collectors.groupingBy(String::length));
}
Частые ошибки
public class CommonMistakes {
// ❌ Ошибка 1: забыли Collectors
// List<Integer> list = stream.collect(toList());
// ✅ Правильно:
List<Integer> list = stream.collect(Collectors.toList());
// ❌ Ошибка 2: используют collect без потока
// Collectors.toList(); // это не работает, нужен stream.collect()
// ❌ Ошибка 3: забыли merge function в toMap с дубликатами ключей
// List<String> dup = Arrays.asList("a", "a");
// dup.stream().collect(Collectors.toMap(s -> s, String::length));
// Exception! IllegalStateException: Duplicate key
// ✅ Правильно:
Map<String, Integer> map = dup.stream()
.collect(Collectors.toMap(
s -> s,
String::length,
(a, b) -> a // merge function: берём первое значение
));
}
Производительность
public class PerformanceConsiderations {
// ✅ Быстро: использование toList()
List<Integer> list = numbers.stream()
.filter(n -> n > 5)
.collect(Collectors.toList()); // O(n)
// ⚠️ Медленнее для больших данных: groupingBy
Map<Integer, List<Integer>> grouped = numbers.stream()
.collect(Collectors.groupingBy(n -> n % 10)); // O(n log n)
// ✅ Параллельный сбор (для больших объёмов данных)
List<Integer> parallel = numbers.parallelStream()
.filter(n -> n > 5)
.collect(Collectors.toList()); // multi-threaded
}
Заключение
Самые частые:
Collectors.toList()— собрание в списокCollectors.toSet()— собрание в множествоCollectors.toMap()— собрание в таблицуCollectors.groupingBy()— группировкаCollectors.joining()— соединение строк
Мастерство работы с Collectors — важный навык для Java разработчика, так как Stream API везде.