← Назад к вопросам

Как поменять тип коллекции

2.2 Middle🔥 201 комментариев
#Stream API и функциональное программирование#Коллекции

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как поменять тип коллекции

В Java часто требуется конвертировать данные между разными типами коллекций (List, Set, Map, Queue). Это критическая задача при работе с данными. Рассмотрю все способы преобразования коллекций.

1. Основные типы коллекций и их отношения

// Иерархия коллекций
Collection
├── List (упорядочена, может быть дубликатов)
│   ├── ArrayList
│   ├── LinkedList
│   └── CopyOnWriteArrayList
├── Set (без дубликатов, неупорядочена)
│   ├── HashSet
│   ├── LinkedHashSet
│   └── TreeSet
└── Queue (очередь, FIFO)
    ├── LinkedList
    ├── PriorityQueue
    └── Deque

Map (ключ-значение, не наследует Collection)
├── HashMap
├── LinkedHashMap
├── TreeMap
└── ConcurrentHashMap

2. List ↔ Set преобразования

List → Set:

// Способ 1: Через конструктор (самый простой)
List<String> list = Arrays.asList("apple", "banana", "apple");
Set<String> set = new HashSet<>(list);
// Результат: {apple, banana} - дубликаты удалены

// Способ 2: LinkedHashSet (сохраняет порядок)
Set<String> linkedSet = new LinkedHashSet<>(list);
// Результат: {apple, banana} - в том же порядке

// Способ 3: TreeSet (сортирует)
Set<String> treeSet = new TreeSet<>(list);
// Результат: {apple, banana} - отсортировано

// Способ 4: Stream API
Set<String> streamSet = list.stream()
    .collect(Collectors.toSet());  // HashSet

Set<String> linkedStreamSet = list.stream()
    .collect(Collectors.toCollection(LinkedHashSet::new));

Set → List:

Set<String> set = new HashSet<>(Arrays.asList("apple", "banana"));

// Способ 1: Через конструктор
List<String> list = new ArrayList<>(set);

// Способ 2: Stream API
List<String> streamList = set.stream()
    .collect(Collectors.toList());

// Способ 3: addAll
List<String> newList = new ArrayList<>();
newList.addAll(set);

// Способ 4: Сортированный List
List<String> sortedList = set.stream()
    .sorted()
    .collect(Collectors.toList());

3. List ↔ Array преобразования

Array → List:

String[] array = {"apple", "banana", "cherry"};

// Способ 1: Arrays.asList (НЕ изменяемый список!)
List<String> list = Arrays.asList(array);  // ⚠️ Fixed-size
list.add("date");  // UnsupportedOperationException!

// Способ 2: Новый изменяемый список
List<String> mutableList = new ArrayList<>(Arrays.asList(array));
mutableList.add("date");  // OK

// Способ 3: Stream API
List<String> streamList = Arrays.stream(array)
    .collect(Collectors.toList());

// Способ 4: Для примитивных типов
int[] intArray = {1, 2, 3};
List<Integer> intList = Arrays.stream(intArray)
    .boxed()  // int → Integer
    .collect(Collectors.toList());

List → Array:

List<String> list = Arrays.asList("apple", "banana", "cherry");

// Способ 1: toArray() - создаёт Object[]
Object[] objectArray = list.toArray();  // [apple, banana, cherry]

// Способ 2: Типизированный массив (правильный способ)
String[] stringArray = list.toArray(new String[0]);
// или новый синтаксис (Java 11+)
String[] stringArray = list.toArray(String[]::new);

// Способ 3: Stream API
String[] streamArray = list.stream()
    .toArray(String[]::new);

// Способ 4: Для примитивных типов
List<Integer> intList = Arrays.asList(1, 2, 3);
int[] intArray = intList.stream()
    .mapToInt(Integer::intValue)  // Integer → int
    .toArray();

4. List ↔ Map преобразования

List → Map:

// Способ 1: Используя индекс как ключ
List<String> list = Arrays.asList("apple", "banana", "cherry");
Map<Integer, String> indexMap = new HashMap<>();
for (int i = 0; i < list.size(); i++) {
    indexMap.put(i, list.get(i));
}
// Результат: {0=apple, 1=banana, 2=cherry}

// Способ 2: Stream API с индексом
Map<Integer, String> streamIndexMap = IntStream.range(0, list.size())
    .boxed()
    .collect(Collectors.toMap(
        Function.identity(),  // индекс как ключ
        list::get             // значение из списка
    ));

// Способ 3: Используя элемент как ключ
List<User> users = Arrays.asList(
    new User(1, "John"),
    new User(2, "Jane")
);
Map<Integer, User> userMap = users.stream()
    .collect(Collectors.toMap(
        User::getId,      // ключ
        Function.identity() // значение
    ));

// Способ 4: Элемент как ключ и значение
List<String> words = Arrays.asList("apple", "banana");
Map<String, Integer> lengthMap = words.stream()
    .collect(Collectors.toMap(
        Function.identity(),      // ключ - само слово
        String::length            // значение - длина
    ));
// Результат: {apple=5, banana=6}

Map → List:

Map<Integer, String> map = new HashMap<>();
map.put(1, "apple");
map.put(2, "banana");

// Способ 1: Список ключей
List<Integer> keys = new ArrayList<>(map.keySet());

// Способ 2: Список значений
List<String> values = new ArrayList<>(map.values());

// Способ 3: Список пар Entry
List<Map.Entry<Integer, String>> entries = 
    new ArrayList<>(map.entrySet());

// Способ 4: Stream API - преобразование значений
List<String> uppercaseValues = map.values().stream()
    .map(String::toUpperCase)
    .collect(Collectors.toList());

// Способ 5: Преобразование в объекты
List<Pair<Integer, String>> pairs = map.entrySet().stream()
    .map(e -> new Pair<>(e.getKey(), e.getValue()))
    .collect(Collectors.toList());

5. Set ↔ Map преобразования

Set → Map:

Set<String> set = new HashSet<>(Arrays.asList("apple", "banana"));

// Способ 1: Элемент как ключ и значение
Map<String, String> map = set.stream()
    .collect(Collectors.toMap(
        Function.identity(),  // ключ
        Function.identity()   // значение
    ));

// Способ 2: Элемент как ключ, длину как значение
Map<String, Integer> lengthMap = set.stream()
    .collect(Collectors.toMap(
        Function.identity(),
        String::length
    ));

Map → Set:

Map<Integer, String> map = new HashMap<>();
map.put(1, "apple");
map.put(2, "banana");

// Способ 1: Set ключей
Set<Integer> keySet = map.keySet();

// Способ 2: Set значений (если есть дубликаты)
Set<String> valueSet = new HashSet<>(map.values());

// Способ 3: Set Entry объектов
Set<Map.Entry<Integer, String>> entrySet = map.entrySet();

6. Queue/Deque преобразования

List → Queue:

List<String> list = Arrays.asList("apple", "banana", "cherry");

// Способ 1: LinkedList (реализует Queue)
Queue<String> queue = new LinkedList<>(list);

// Способ 2: PriorityQueue (с сортировкой)
Queue<String> priorityQueue = new PriorityQueue<>(list);

// Способ 3: Deque (двусторонняя очередь)
Deque<String> deque = new LinkedList<>(list);

Queue → List:

Queue<String> queue = new LinkedList<>(Arrays.asList("apple", "banana"));

// Способ 1: Прямое преобразование
List<String> list = new ArrayList<>(queue);

// Способ 2: Stream API
List<String> streamList = queue.stream()
    .collect(Collectors.toList());

// ⚠️ Важно: очередь может быть изменена при преобразовании
// Используйте новый список перед удалением из очереди

7. Сложные преобразования с фильтрацией

Преобразование с фильтром:

List<String> list = Arrays.asList("apple", "banana", "apricot", "cherry");

// List с фильтром
List<String> filtered = list.stream()
    .filter(s -> s.startsWith("a"))  // Только слова на 'a'
    .collect(Collectors.toList());
// Результат: [apple, apricot]

// Set с фильтром
Set<String> filteredSet = list.stream()
    .filter(s -> s.length() > 5)
    .collect(Collectors.toSet());
// Результат: {banana, cherry, apricot}

// Map с фильтром
Map<String, Integer> filteredMap = list.stream()
    .filter(s -> s.length() > 5)
    .collect(Collectors.toMap(
        Function.identity(),
        String::length
    ));

8. Группировка при преобразовании

List → Map с группировкой:

List<User> users = Arrays.asList(
    new User(1, "John", "IT"),
    new User(2, "Jane", "HR"),
    new User(3, "Bob", "IT")
);

// Группируем по отделу
Map<String, List<User>> byDepartment = users.stream()
    .collect(Collectors.groupingBy(User::getDepartment));
// Результат: {
//   IT: [User(1), User(3)],
//   HR: [User(2)]
// }

// Группируем, но берём только имена
Map<String, List<String>> namesByDepartment = users.stream()
    .collect(Collectors.groupingBy(
        User::getDepartment,
        Collectors.mapping(User::getName, Collectors.toList())
    ));
// Результат: {
//   IT: [John, Bob],
//   HR: [Jane]
// }

// Группируем и считаем
Map<String, Long> countByDepartment = users.stream()
    .collect(Collectors.groupingBy(
        User::getDepartment,
        Collectors.counting()
    ));
// Результат: {IT: 2, HR: 1}

9. Практические примеры

Преобразование DTO в Entity:

List<UserDTO> dtos = getUserDTOs();

// DTO → Entity и сохранить в Set
Set<User> entities = dtos.stream()
    .map(dto -> new User(dto.getName(), dto.getEmail()))
    .collect(Collectors.toSet());

Преобразование Entity в DTO:

List<User> users = userService.findAll();

// Entity → DTO
List<UserDTO> dtos = users.stream()
    .map(u -> new UserDTO(u.getId(), u.getName(), u.getEmail()))
    .collect(Collectors.toList());

// или
List<UserDTO> dtos = users.stream()
    .map(UserDTO::fromEntity)  // Статический метод
    .collect(Collectors.toList());

Кеширование коллекции в Map:

List<Product> products = getProducts();

// Кешируем в Map по ID для быстрого доступа
Map<Long, Product> productCache = products.stream()
    .collect(Collectors.toMap(
        Product::getId,
        Function.identity()
    ));

// Использование
Product product = productCache.get(123L);

10. Производительность и выбор коллекции

Сложность операций:

List (ArrayList):
  get(index): O(1)
  add(end): O(1) amortized
  add(middle): O(n)
  remove: O(n)

Set (HashSet):
  add: O(1)
  remove: O(1)
  contains: O(1)

Map (HashMap):
  get: O(1)
  put: O(1)
  remove: O(1)

Queue (LinkedList):
  offer/poll: O(1)
  peek: O(1)

Чеклист преобразований

// Выбор правильного способа

// Нужен неизменяемый результат?
List<String> unmodifiable = Collections.unmodifiableList(list);
Set<String> unmodifiableSet = Collections.unmodifiableSet(set);

// Нужна синхронизация для многопоточности?
List<String> syncList = Collections.synchronizedList(new ArrayList<>(list));
Map<String, User> syncMap = Collections.synchronizedMap(new HashMap<>(map));

// Нужна параллельная обработка?
List<Result> results = data.parallelStream()
    .map(this::process)
    .collect(Collectors.toList());

Заключение

Преобразование типов коллекций в Java:

  1. List ↔ Set — через конструктор или Stream API
  2. List ↔ Array — Arrays.asList() или toArray()
  3. List ↔ Map — Collectors.toMap() с функциями преобразования
  4. Set ↔ Map — через keySet(), values(), entrySet()
  5. Queue — LinkedList реализует оба интерфейса
  6. Фильтрация — filter() в Stream API
  7. Группировка — Collectors.groupingBy()

Выбирайте Stream API для новых проектов — это функциональный, читаемый и эффективный способ. Для производительности критичных операций анализируйте сложность выбранной коллекции.

Как поменять тип коллекции | PrepBro