Коллекции в Java
Глава 1. Введение в коллекции
Обзор Java Collections Framework. Интерфейсы Collection и Map. Иерархия коллекций. Отличия коллекций от массивов
Java Collections Framework (JCF) — это набор интерфейсов, классов и алгоритмов в пакете java.util, предназначенный для работы с коллекциями данных. JCF предоставляет унифицированный способ хранения и манипуляции объектами, делая код более гибким и эффективным.
- Компоненты JCF:
- Интерфейсы: Определяют контракт (что можно делать с коллекцией).
- Реализации: Конкретные классы, реализующие интерфейсы (например, ArrayList для List).
- Алгоритмы: Встроенные методы для сортировки, поиска и т.д. (в классе Collections).
JCF введен в Java 1.2 и значительно улучшен в Java 5 с generics (обобщениями), которые обеспечивают типобезопасность.
- Преимущества JCF:
- Гибкость: Динамический размер, в отличие от массивов.
- Типобезопасность: С generics — компилятор проверяет типы.
- Эффективность: Разные реализации для разных сценариев (быстрый доступ, уникальность элементов и т.д.).
- Полиморфизм: Работа через интерфейсы, легко менять реализации.
Интерфейсы Collection и Map
JCF построен вокруг двух основных интерфейсов: Collection для последовательностей объектов и Map для пар ключ-значение.
1. Интерфейс Collection<E>:
- Это базовый интерфейс для коллекций, где E — тип элементов (generics).
- Представляет группу объектов, позволяя добавлять, удалять, перебирать.
- Не гарантирует порядок или уникальность — зависит от реализации.
- Основные методы:
- add(E e): Добавляет элемент.
- remove(Object o): Удаляет элемент.
- size(): Возвращает размер.
- isEmpty(): Проверяет пустоту.
- iterator(): Для перебора (Iterator).
- contains(Object o): Проверяет наличие.
- Нюанс: Collection не индексирован (нет get(int index)), для этого — подинтерфейсы как List.
2. Интерфейс Map<K, V>:
- Представляет отображение: пары ключ-значение, где K — тип ключа, V — тип значения.
- Ключи уникальны, значения могут дублироваться.
- Не является подтипом Collection (Map не коллекция элементов, а ассоциация).
- Основные методы:
- put(K key, V value): Добавляет/обновляет пару.
- get(Object key): Возвращает значение по ключу.
- remove(Object key): Удаляет по ключу.
- size(), isEmpty().
- keySet(): Коллекция ключей (Set<K>).
- values(): Коллекция значений (Collection<V>).
- entrySet(): Коллекция пар (Set<Map.Entry<K, V>>).
- Нюанс: Map не упорядочен (кроме SortedMap), ключи не null (в большинстве реализаций).
#Java #для_новичков #beginner #Collections #Map
Глава 1. Введение в коллекции
Обзор Java Collections Framework. Интерфейсы Collection и Map. Иерархия коллекций. Отличия коллекций от массивов
Java Collections Framework (JCF) — это набор интерфейсов, классов и алгоритмов в пакете java.util, предназначенный для работы с коллекциями данных. JCF предоставляет унифицированный способ хранения и манипуляции объектами, делая код более гибким и эффективным.
- Компоненты JCF:
- Интерфейсы: Определяют контракт (что можно делать с коллекцией).
- Реализации: Конкретные классы, реализующие интерфейсы (например, ArrayList для List).
- Алгоритмы: Встроенные методы для сортировки, поиска и т.д. (в классе Collections).
JCF введен в Java 1.2 и значительно улучшен в Java 5 с generics (обобщениями), которые обеспечивают типобезопасность.
- Преимущества JCF:
- Гибкость: Динамический размер, в отличие от массивов.
- Типобезопасность: С generics — компилятор проверяет типы.
- Эффективность: Разные реализации для разных сценариев (быстрый доступ, уникальность элементов и т.д.).
- Полиморфизм: Работа через интерфейсы, легко менять реализации.
Интерфейсы Collection и Map
JCF построен вокруг двух основных интерфейсов: Collection для последовательностей объектов и Map для пар ключ-значение.
1. Интерфейс Collection<E>:
- Это базовый интерфейс для коллекций, где E — тип элементов (generics).
- Представляет группу объектов, позволяя добавлять, удалять, перебирать.
- Не гарантирует порядок или уникальность — зависит от реализации.
- Основные методы:
- add(E e): Добавляет элемент.
- remove(Object o): Удаляет элемент.
- size(): Возвращает размер.
- isEmpty(): Проверяет пустоту.
- iterator(): Для перебора (Iterator).
- contains(Object o): Проверяет наличие.
- Нюанс: Collection не индексирован (нет get(int index)), для этого — подинтерфейсы как List.
2. Интерфейс Map<K, V>:
- Представляет отображение: пары ключ-значение, где K — тип ключа, V — тип значения.
- Ключи уникальны, значения могут дублироваться.
- Не является подтипом Collection (Map не коллекция элементов, а ассоциация).
- Основные методы:
- put(K key, V value): Добавляет/обновляет пару.
- get(Object key): Возвращает значение по ключу.
- remove(Object key): Удаляет по ключу.
- size(), isEmpty().
- keySet(): Коллекция ключей (Set<K>).
- values(): Коллекция значений (Collection<V>).
- entrySet(): Коллекция пар (Set<Map.Entry<K, V>>).
- Нюанс: Map не упорядочен (кроме SortedMap), ключи не null (в большинстве реализаций).
#Java #для_новичков #beginner #Collections #Map
👍5
  Иерархия коллекций в JCF
JCF имеет иерархию интерфейсов и реализаций. Вот подробная структура:
1. Иерархия Collection:
- Collection<E> (базовый):
- List<E>: Упорядоченная коллекция, позволяет дубликаты, индексация.
- Реализации: ArrayList (быстрый доступ), LinkedList (быстрые вставки/удаления), Vector (устаревший, synchronized).
- Set<E>: Неупорядоченная коллекция уникальных элементов.
- Реализации: HashSet (быстрый поиск), TreeSet (отсортированный), LinkedHashSet (сохраняет порядок вставки).
- Queue<E>: Для очередей (FIFO), или приоритетных.
- Реализации: LinkedList (как Queue), PriorityQueue (приоритетная), ArrayDeque (deque).
- Deque<E>: Двусторонняя очередь (добавление/удаление с обоих концов).
- Реализации: ArrayDeque, LinkedList.
2. Иерархия Map:
- Map<K, V> (базовый):
- HashMap<K, V>: Быстрый поиск по хэшу, не упорядочен.
- TreeMap<K, V>: Отсортированный по ключам (SortedMap).
- LinkedHashMap<K, V>: Сохраняет порядок вставки.
- Hashtable<K, V>: Устаревший, synchronized.
- Generics: С Java 5: Collection<String> list = new ArrayList<>(); — типобезопасно.
- Нюансы иерархии:
- Все реализации — concrete классы, кроме абстрактных helper-классов (AbstractList).
- Synchronized: Для многопоточности используйте Collections.synchronized*() или Concurrent* классы (ConcurrentHashMap).
- Performance: Выбирайте по нуждам — HashSet O(1) поиск, TreeSet O(log n) с сортировкой.
- Immutability: Collections.unmodifiable*() для read-only коллекций.
Отличия коллекций от массивов
Массивы — базовый тип в Java для хранения элементов фиксированного размера. Коллекции — более гибкий инструмент из JCF.
- Подробное сравнение:
1. Размер:
- Массивы: Фиксированный (int[] arr = new int[10]; — нельзя изменить).
- Коллекции: Динамический (ArrayList.add() расширяет автоматически).
2. Типы элементов:
- Массивы: Могут хранить примитивы (int[]) или объекты.
- Коллекции: Только объекты (Collection<Integer> для примитивов через wrapper).
3. Методы:
- Массивы: Ограничены (длина .length, доступ по индексу).
- Коллекции: Богатый API (add, remove, contains, sort, iterator).
4. Generics:
- Массивы: Нет (Object[] может хранить всё, но без проверки).
- Коллекции: С generics — типобезопасно (компилятор проверяет).
5. Performance:
- Массивы: Быстрее для фиксированного размера и примитивов.
- Коллекции: Overhead, но удобнее; ArrayList близок к массиву.
6. Многомерность:
- Массивы: Легко (int[][]).
- Коллекции: Вложенные (List<List<Integer>>).
7. Null и дубликаты:
- Оба позволяют, но Set в коллекциях запрещает дубликаты.
Пример перехода от массива к коллекции:
Массив:
Коллекция:
- Нюанс: Коллекции используют массивы внутри (ArrayList — resizable array).
Как работать с JCF в IntelliJ IDEA
1. Импорт: Импортируйте java.util.* или конкретно (IDE подскажет Ctrl+Space).
2. Generics: Напишите List<String> — IDE проверит типы.
3. Коллекции: New → Collection → Выберите реализацию.
4. Методы: Автодополнение для add, remove и т.д.
5. Debug: В отладке смотрите содержимое коллекций.
Полезные советы для новичков
- Выбирайте интерфейс: Кодьте под List, а не ArrayList — легко сменить реализацию.
- Generics всегда: Избегайте raw types (List без <E> — устарело).
- Коллекции vs массивы: Массивы для фиксированных примитивов, коллекции для всего остального.
- Performance: ArrayList для доступа, LinkedList для вставок, HashSet для уникальности.
#Java #для_новичков #beginner #Collections #Map
JCF имеет иерархию интерфейсов и реализаций. Вот подробная структура:
1. Иерархия Collection:
- Collection<E> (базовый):
- List<E>: Упорядоченная коллекция, позволяет дубликаты, индексация.
- Реализации: ArrayList (быстрый доступ), LinkedList (быстрые вставки/удаления), Vector (устаревший, synchronized).
- Set<E>: Неупорядоченная коллекция уникальных элементов.
- Реализации: HashSet (быстрый поиск), TreeSet (отсортированный), LinkedHashSet (сохраняет порядок вставки).
- Queue<E>: Для очередей (FIFO), или приоритетных.
- Реализации: LinkedList (как Queue), PriorityQueue (приоритетная), ArrayDeque (deque).
- Deque<E>: Двусторонняя очередь (добавление/удаление с обоих концов).
- Реализации: ArrayDeque, LinkedList.
2. Иерархия Map:
- Map<K, V> (базовый):
- HashMap<K, V>: Быстрый поиск по хэшу, не упорядочен.
- TreeMap<K, V>: Отсортированный по ключам (SortedMap).
- LinkedHashMap<K, V>: Сохраняет порядок вставки.
- Hashtable<K, V>: Устаревший, synchronized.
- Generics: С Java 5: Collection<String> list = new ArrayList<>(); — типобезопасно.
- Нюансы иерархии:
- Все реализации — concrete классы, кроме абстрактных helper-классов (AbstractList).
- Synchronized: Для многопоточности используйте Collections.synchronized*() или Concurrent* классы (ConcurrentHashMap).
- Performance: Выбирайте по нуждам — HashSet O(1) поиск, TreeSet O(log n) с сортировкой.
- Immutability: Collections.unmodifiable*() для read-only коллекций.
Отличия коллекций от массивов
Массивы — базовый тип в Java для хранения элементов фиксированного размера. Коллекции — более гибкий инструмент из JCF.
- Подробное сравнение:
1. Размер:
- Массивы: Фиксированный (int[] arr = new int[10]; — нельзя изменить).
- Коллекции: Динамический (ArrayList.add() расширяет автоматически).
2. Типы элементов:
- Массивы: Могут хранить примитивы (int[]) или объекты.
- Коллекции: Только объекты (Collection<Integer> для примитивов через wrapper).
3. Методы:
- Массивы: Ограничены (длина .length, доступ по индексу).
- Коллекции: Богатый API (add, remove, contains, sort, iterator).
4. Generics:
- Массивы: Нет (Object[] может хранить всё, но без проверки).
- Коллекции: С generics — типобезопасно (компилятор проверяет).
5. Performance:
- Массивы: Быстрее для фиксированного размера и примитивов.
- Коллекции: Overhead, но удобнее; ArrayList близок к массиву.
6. Многомерность:
- Массивы: Легко (int[][]).
- Коллекции: Вложенные (List<List<Integer>>).
7. Null и дубликаты:
- Оба позволяют, но Set в коллекциях запрещает дубликаты.
Пример перехода от массива к коллекции:
Массив:
String[] names = new String[3];
names[0] = "Алексей";
// Нет add, нужно вручную управлять размером
Коллекция:
List<String> names = new ArrayList<>();
names.add("Алексей"); // Динамично
names.remove(0); // Легко удалить
- Нюанс: Коллекции используют массивы внутри (ArrayList — resizable array).
Как работать с JCF в IntelliJ IDEA
1. Импорт: Импортируйте java.util.* или конкретно (IDE подскажет Ctrl+Space).
2. Generics: Напишите List<String> — IDE проверит типы.
3. Коллекции: New → Collection → Выберите реализацию.
4. Методы: Автодополнение для add, remove и т.д.
5. Debug: В отладке смотрите содержимое коллекций.
Полезные советы для новичков
- Выбирайте интерфейс: Кодьте под List, а не ArrayList — легко сменить реализацию.
- Generics всегда: Избегайте raw types (List без <E> — устарело).
- Коллекции vs массивы: Массивы для фиксированных примитивов, коллекции для всего остального.
- Performance: ArrayList для доступа, LinkedList для вставок, HashSet для уникальности.
#Java #для_новичков #beginner #Collections #Map
👍5
  Реактивное программирование
Базовые операторы в Reactor: map, filter, flatMap
Операторы — это методы на Mono/Flux, которые позволяют строить конвейеры: преобразовывать, фильтровать и комбинировать данные асинхронно. Представьте их как звенья в цепи: каждый берёт входной поток, меняет его и передаёт дальше. Сегодня разберём три фундаментальных: map (преобразование элементов), filter (фильтрация) и flatMap (плоское преобразование, для слияния подпотоков). Эти операторы — основа для сложных сценариев, они решают проблемы из первого поста, позволяя писать декларативный код вместо ручных циклов и ожиданий.
Операторы в Reactor — декларативные: вы описываете, что делать с данными, а библиотека заботится об асинхронности, backpressure и ошибках. Они не меняют исходный поток (иммутабельны), а создают новый. Это делает код читаемым и тестируемым.
Map: простое преобразование элементов
Map — оператор для изменения каждого элемента потока. Он берёт входной элемент, применяет функцию и выдаёт результат. Синхронный: функция должна быть быстрой и без блокировок. Идеален для конвертации типов, вычислений или форматирования.
Пример на Flux:
На Mono:
Почему map полезен? В традиционных подходах (как в CompletableFuture.thenApply) вы строите цепочки, но рискуете вложенностью. В Reactor map делает конвейер линейным: читается как последовательный код, но работает асинхронно. Поддерживает backpressure: если подписчик запрашивает n, map передаёт запрос upstream (источнику).
Filter: отбор элементов по условию
Filter — для пропуска только нужных элементов. Принимает предикат (функцию, возвращающую true/false) и пропускает те, для которых true. Остальные игнорируются — поток "сужается".
Пример на Flux:
На Mono:
Filter экономит ресурсы: ненужные элементы не обрабатываются дальше в цепи. В отличие от императивных циклов (где вы фильтруете в for с if), здесь всё асинхронно и с backpressure — запросы передаются источнику только для прошедших элементов.
Комбинация с map: numbers.filter(num -> num > 5).map(num -> num * 10).subscribe(); // 60, 70, 80, 90, 100
Это строит конвейер: фильтр → преобразование, без ручных переменных.
#Java #middle #Reactor #map #filter #flatMap
Базовые операторы в Reactor: map, filter, flatMap
Операторы — это методы на Mono/Flux, которые позволяют строить конвейеры: преобразовывать, фильтровать и комбинировать данные асинхронно. Представьте их как звенья в цепи: каждый берёт входной поток, меняет его и передаёт дальше. Сегодня разберём три фундаментальных: map (преобразование элементов), filter (фильтрация) и flatMap (плоское преобразование, для слияния подпотоков). Эти операторы — основа для сложных сценариев, они решают проблемы из первого поста, позволяя писать декларативный код вместо ручных циклов и ожиданий.
Операторы в Reactor — декларативные: вы описываете, что делать с данными, а библиотека заботится об асинхронности, backpressure и ошибках. Они не меняют исходный поток (иммутабельны), а создают новый. Это делает код читаемым и тестируемым.
Map: простое преобразование элементов
Map — оператор для изменения каждого элемента потока. Он берёт входной элемент, применяет функцию и выдаёт результат. Синхронный: функция должна быть быстрой и без блокировок. Идеален для конвертации типов, вычислений или форматирования.
Пример на Flux:
import reactor.core.publisher.Flux;
Flux<String> originalFlux = Flux.just("яблоко", "банан", "вишня");
Flux<String> transformed = originalFlux.map(fruit -> fruit.toUpperCase()); // Преобразование в верхний регистр
transformed.subscribe(System.out::println); // Вывод: "ЯБЛОКО", "БАНАН", "ВИШНЯ"
Здесь map применяет лямбду к каждому элементу последовательно. Если ошибка в функции — сработает onError.
На Mono:
Mono<Integer> num = Mono.just(5).map(x -> x * 2); // Результат: 10
Почему map полезен? В традиционных подходах (как в CompletableFuture.thenApply) вы строите цепочки, но рискуете вложенностью. В Reactor map делает конвейер линейным: читается как последовательный код, но работает асинхронно. Поддерживает backpressure: если подписчик запрашивает n, map передаёт запрос upstream (источнику).
Filter: отбор элементов по условию
Filter — для пропуска только нужных элементов. Принимает предикат (функцию, возвращающую true/false) и пропускает те, для которых true. Остальные игнорируются — поток "сужается".
Пример на Flux:
Flux<Integer> numbers = Flux.range(1, 10);
Flux<Integer> evenNumbers = numbers.filter(num -> num % 2 == 0); // Только чётные
evenNumbers.subscribe(System.out::println); // Вывод: 2, 4, 6, 8, 10
Если поток пустой или ничего не проходит — onComplete сработает без onNext.
На Mono:
Mono<String> word = Mono.just("привет").filter(w -> w.length() > 7); // Не пройдёт — пустой MonoFilter экономит ресурсы: ненужные элементы не обрабатываются дальше в цепи. В отличие от императивных циклов (где вы фильтруете в for с if), здесь всё асинхронно и с backpressure — запросы передаются источнику только для прошедших элементов.
Комбинация с map: numbers.filter(num -> num > 5).map(num -> num * 10).subscribe(); // 60, 70, 80, 90, 100
Это строит конвейер: фильтр → преобразование, без ручных переменных.
#Java #middle #Reactor #map #filter #flatMap
👍3
  FlatMap: плоское преобразование для асинхронных подпотоков
FlatMap — мощный оператор для случаев, когда из одного элемента нужно создать подпоток (Publisher), и слить их в плоский результат. Это как map, но для асинхронных или множественных выходов: он "разворачивает" вложенные потоки. Полезен для запросов в цикле: например, для каждого пользователя — асинхронно запросить данные.
Пример на Flux:
Асинхронный пример: симулируем API-запросы.
Почему flatMap решает проблемы? В традиционных подходах (циклы с Future) вы ждёте каждый запрос, блокируя. Здесь — асинхронное слияние, без ожиданий и callback-ада: цепочка читаема.
Практические советы и подводные камни
Читаемость: цепочки операторов пишите по строкам для ясности: flux.filter(...).map(...).flatMap(...);
Ошибки: если в map/flatMap исключение — onError. Используйте handle() для условной обработки.
Производительность: в flatMap устанавливайте concurrency (default 256) для контроля параллелизма: flatMap(func, 4) — max 4 подпотока одновременно.
Камень: блокирующий код в лямбдах — сломает асинхронность. Для IO — используйте flatMap с Mono.fromCallable и publishOn(Schedulers.boundedElastic()).
Тестирование: StepVerifier.create(flux.map(...)).expectNext("ЯБЛОКО").verifyComplete();
#Java #middle #Reactor #map #filter #flatMap
FlatMap — мощный оператор для случаев, когда из одного элемента нужно создать подпоток (Publisher), и слить их в плоский результат. Это как map, но для асинхронных или множественных выходов: он "разворачивает" вложенные потоки. Полезен для запросов в цикле: например, для каждого пользователя — асинхронно запросить данные.
Пример на Flux:
Flux<String> fruits = Flux.just("яблоко", "банан");
Flux<Character> letters = fruits.flatMap(fruit -> Flux.fromArray(fruit.toCharArray())); // Из строки — поток символов
letters.subscribe(System.out::println); // Вывод: я, б, л, о, к, о, б, а, н, а, н (в возможном перемешанном порядке, если асинхронно)
Здесь flatMap берёт строку, создаёт Flux из символов и сливает всё в один поток. В отличие от map (который вернул бы Flux<Flux<Character>> — вложенный), flatMap "сплющивает".Асинхронный пример: симулируем API-запросы.
import java.time.Duration;
Flux<String> users = Flux.just("user1", "user2");
Flux<String> data = users.flatMap(user -> Mono.just("Данные для " + user).delayElement(Duration.ofSeconds(1))); // Асинхронный подпоток с задержкой
data.subscribe(System.out::println); // Вывод через секунды: "Данные для user1", "Данные для user2" (параллельно, если scheduler позволяет)
FlatMap уважает backpressure: запрашивает у подпотоков по мере нужды. Но осторожно: если подпотоки бесконечные — рискуете перегрузкой. Параметр concurrency (flatMap(func, concurrency)) ограничивает параллелизм.
Почему flatMap решает проблемы? В традиционных подходах (циклы с Future) вы ждёте каждый запрос, блокируя. Здесь — асинхронное слияние, без ожиданий и callback-ада: цепочка читаема.
Практические советы и подводные камни
Читаемость: цепочки операторов пишите по строкам для ясности: flux.filter(...).map(...).flatMap(...);
Ошибки: если в map/flatMap исключение — onError. Используйте handle() для условной обработки.
Производительность: в flatMap устанавливайте concurrency (default 256) для контроля параллелизма: flatMap(func, 4) — max 4 подпотока одновременно.
Камень: блокирующий код в лямбдах — сломает асинхронность. Для IO — используйте flatMap с Mono.fromCallable и publishOn(Schedulers.boundedElastic()).
Тестирование: StepVerifier.create(flux.map(...)).expectNext("ЯБЛОКО").verifyComplete();
#Java #middle #Reactor #map #filter #flatMap
👍3
  Раздел 6. Коллекции в Java
Глава 5. Map — отображения (словари)
Интерфейс Map<K, V> — это часть Java Collections Framework (JCF) из пакета java.util, который представляет структуру для хранения ассоциативных данных. В отличие от других коллекций, таких как List или Set, которые хранят отдельные элементы, Map хранит пары, где каждый ключ (K) связан с значением (V). Это позволяет быстро находить значение по ключу, как в словаре или телефонной книге.
Основные понятия:
Ключ (Key): Уникальный идентификатор для доступа к значению. Ключи не могут дублироваться — если добавить пару с существующим ключом, значение перезапишется.
Значение (Value): Данные, ассоциированные с ключом. Значения могут дублироваться.
Пара (Entry): Единица хранения в Map — комбинация ключа и значения.
Map моделирует математическое отображение (mapping), где каждый ключ maps to ровно одно значение. Это делает Map идеальным для сценариев, где нужна ассоциация, например, ID пользователя — профиль, слово — перевод.
Отличия от Collection:
Map не расширяет Collection<E> — это отдельная ветвь JCF.
Collection — последовательность элементов, Map — ассоциативный массив.
В Map нет индексации (нет get(int index)), доступ только по ключу.
Размер Map — количество пар, не элементов.
Generics в Map: <K, V> обеспечивает типобезопасность: ключи одного типа (например, Integer), значения другого (String). Без generics (raw Map) — устарело и небезопасно.
Хранение пар «ключ–значение»: Особенности
Map хранит данные в форме пар, где ключ — уникальный, а значение — связанное с ним. Это позволяет эффективно решать задачи поиска и ассоциации.
Уникальность ключей:
Ключи всегда уникальны: Map не позволяет дубликаты ключей. Если ключ уже существует, значение обновляется.
Уникальность определяется методами equals() и hashCode() (в hash-based реализациях) или compareTo() (в sorted).
Нюанс: Для custom ключей обязательно переопределите equals() и hashCode() — иначе уникальность по ссылке, не по значению.
Дубликаты значений:
Значения могут повторяться: Несколько ключей могут ссылаться на одно значение.
Нюанс: Если значение — mutable объект, изменения в одном месте отразятся везде (по ссылке).
Null в Map:
Ключи: Большинство реализаций позволяют один null-ключ (HashMap, LinkedHashMap), но TreeMap — нет (NullPointerException).
Значения: Null разрешен всегда.
Порядок в Map:
В общем случае нет (зависит от реализации): Не полагайтесь на порядок пар.
Нюанс: Map не упорядочен, как List, но некоторые реализации добавляют порядок.
Размер и емкость:
Размер (size()) — количество пар.
Емкость: В hash-based — initial capacity и load factor (например, 0.75 — при заполнении >75% ресайз).
Производительность:
В среднем O(1) для доступа по ключу в hash-based, O(log n) в tree-based.
Нюанс: Зависит от качества hashCode() — плохие хэши приводят к деградации до O(n).
Полезные советы для новичков
Выбор типов K/V: Ключи — immutable (String, Integer), чтобы избежать изменений, влияющих на хэш.
Custom ключи: Переопределяйте equals/hashCode (IDE поможет: Generate → equals() and hashCode()).
Map vs другие коллекции: Используйте Map для ассоциаций, Set для уникальных элементов, List для последовательностей.
#Java #для_новичков #beginner #Map
Глава 5. Map — отображения (словари)
Интерфейс Map<K, V> — это часть Java Collections Framework (JCF) из пакета java.util, который представляет структуру для хранения ассоциативных данных. В отличие от других коллекций, таких как List или Set, которые хранят отдельные элементы, Map хранит пары, где каждый ключ (K) связан с значением (V). Это позволяет быстро находить значение по ключу, как в словаре или телефонной книге.
Основные понятия:
Ключ (Key): Уникальный идентификатор для доступа к значению. Ключи не могут дублироваться — если добавить пару с существующим ключом, значение перезапишется.
Значение (Value): Данные, ассоциированные с ключом. Значения могут дублироваться.
Пара (Entry): Единица хранения в Map — комбинация ключа и значения.
Map моделирует математическое отображение (mapping), где каждый ключ maps to ровно одно значение. Это делает Map идеальным для сценариев, где нужна ассоциация, например, ID пользователя — профиль, слово — перевод.
Отличия от Collection:
Map не расширяет Collection<E> — это отдельная ветвь JCF.
Collection — последовательность элементов, Map — ассоциативный массив.
В Map нет индексации (нет get(int index)), доступ только по ключу.
Размер Map — количество пар, не элементов.
Generics в Map: <K, V> обеспечивает типобезопасность: ключи одного типа (например, Integer), значения другого (String). Без generics (raw Map) — устарело и небезопасно.
Хранение пар «ключ–значение»: Особенности
Map хранит данные в форме пар, где ключ — уникальный, а значение — связанное с ним. Это позволяет эффективно решать задачи поиска и ассоциации.
Уникальность ключей:
Ключи всегда уникальны: Map не позволяет дубликаты ключей. Если ключ уже существует, значение обновляется.
Уникальность определяется методами equals() и hashCode() (в hash-based реализациях) или compareTo() (в sorted).
Нюанс: Для custom ключей обязательно переопределите equals() и hashCode() — иначе уникальность по ссылке, не по значению.
Дубликаты значений:
Значения могут повторяться: Несколько ключей могут ссылаться на одно значение.
Нюанс: Если значение — mutable объект, изменения в одном месте отразятся везде (по ссылке).
Null в Map:
Ключи: Большинство реализаций позволяют один null-ключ (HashMap, LinkedHashMap), но TreeMap — нет (NullPointerException).
Значения: Null разрешен всегда.
Порядок в Map:
В общем случае нет (зависит от реализации): Не полагайтесь на порядок пар.
Нюанс: Map не упорядочен, как List, но некоторые реализации добавляют порядок.
Размер и емкость:
Размер (size()) — количество пар.
Емкость: В hash-based — initial capacity и load factor (например, 0.75 — при заполнении >75% ресайз).
Производительность:
В среднем O(1) для доступа по ключу в hash-based, O(log n) в tree-based.
Нюанс: Зависит от качества hashCode() — плохие хэши приводят к деградации до O(n).
Полезные советы для новичков
Выбор типов K/V: Ключи — immutable (String, Integer), чтобы избежать изменений, влияющих на хэш.
Custom ключи: Переопределяйте equals/hashCode (IDE поможет: Generate → equals() and hashCode()).
Map vs другие коллекции: Используйте Map для ассоциаций, Set для уникальных элементов, List для последовательностей.
#Java #для_новичков #beginner #Map
👍4
  Раздел 6. Коллекции в Java
Глава 5. Map — отображения (словари)
Реализации: HashMap, LinkedHashMap, TreeMap и остальные
JCF предоставляет богатый набор реализаций Map, каждая оптимизирована под конкретные нужды.
Все они реализуют Map<K, V>, но различаются по:
Хранению: Хэш-таблица (HashMap), связный список + хэш (LinkedHashMap), красно-черное дерево (TreeMap).
Порядку: Нет (HashMap), вставки (LinkedHashMap), сортировка по ключам (TreeMap).
Производительности: O(1) для хэш, O(log n) для дерево.
Дополнительно: Специальные для enum, слабых ссылок и т.д.
1. HashMap<K, V>: Основная реализация
Описание: HashMap — сердце Map в Java, основанная на хэш-таблице. Хранит пары в массиве "бакетов" (buckets), где каждый бакет — список узлов (node) с ключом, значением и хэш-кодом.
Внутренняя структура:
Массив Node<K,V>[] table (initial capacity 16, load factor 0.75).
При put: Вычисляет hash = key.hashCode() ^ (hash >>> 16) для равномерности.
Индекс бакета: hash & (table.length - 1).
Коллизия: LinkedList или Tree (с Java 8, если > 8 узлов — дерево для O(log n)).
Ресайз: При >75% заполнения — удваивает размер, перехэширует все элементы.
Big O:
put/get/remove/containsKey: O(1) средний, O(n) worst (плохие хэши).
Итерация: O(capacity).
Особенности:
Порядок: Нет (iteration order не гарантирован).
Null: Один null-ключ, несколько null-значений.
Thread-safe: Нет (ConcurrentModificationException при параллельном доступе).
Initial capacity/load factor: new HashMap<>(16, 0.75f) для оптимизации.
Нюансы и ловушки:
hashCode/equals: Критичны! Плохой hashCode — деградация до O(n). Изменение ключа после put — потеря элемента.
Ресайз: O(n) время, но редко.
Java 8+: Tree nodes для коллизий (>8 узлов).
Remove: Если null-ключ — специальная обработка.
Итерация: entrySet(), keySet(), values() — O(capacity), не size().
Пример кода:
2. LinkedHashMap<K, V>: HashMap с порядком
Описание: Расширение HashMap с двусвязным списком для сохранения порядка вставки (insertion-order) или доступа (access-order для LRU-кэша).
Внутренняя структура: HashMap + Entry с prev/next ссылками. Два режима: INSERTION_ORDER (default) или ACCESS_ORDER (constructor flag).
Big O: O(1) для put/get/remove, как HashMap.
Особенности:
Порядок: Вставки (по умолчанию) или доступа (get/put обновляет позицию).
Null: Да.
Thread-safe: Нет.
Нюансы:
LRU кэш: new LinkedHashMap<>(16, 0.75f, true) — access-order, removeEldestEntry для eviction.
Итерация: В порядке вставки/доступа.
Ресайз: Как HashMap, но сохраняет порядок.
Пример:
#Java #для_новичков #beginner #Map #HashMap #LinkedHashMap #TreeMap #Hashtable #IdentityHashMap #EnumMap #WeakHashMap
  Глава 5. Map — отображения (словари)
Реализации: HashMap, LinkedHashMap, TreeMap и остальные
JCF предоставляет богатый набор реализаций Map, каждая оптимизирована под конкретные нужды.
Все они реализуют Map<K, V>, но различаются по:
Хранению: Хэш-таблица (HashMap), связный список + хэш (LinkedHashMap), красно-черное дерево (TreeMap).
Порядку: Нет (HashMap), вставки (LinkedHashMap), сортировка по ключам (TreeMap).
Производительности: O(1) для хэш, O(log n) для дерево.
Дополнительно: Специальные для enum, слабых ссылок и т.д.
1. HashMap<K, V>: Основная реализация
Описание: HashMap — сердце Map в Java, основанная на хэш-таблице. Хранит пары в массиве "бакетов" (buckets), где каждый бакет — список узлов (node) с ключом, значением и хэш-кодом.
Внутренняя структура:
Массив Node<K,V>[] table (initial capacity 16, load factor 0.75).
При put: Вычисляет hash = key.hashCode() ^ (hash >>> 16) для равномерности.
Индекс бакета: hash & (table.length - 1).
Коллизия: LinkedList или Tree (с Java 8, если > 8 узлов — дерево для O(log n)).
Ресайз: При >75% заполнения — удваивает размер, перехэширует все элементы.
Big O:
put/get/remove/containsKey: O(1) средний, O(n) worst (плохие хэши).
Итерация: O(capacity).
Особенности:
Порядок: Нет (iteration order не гарантирован).
Null: Один null-ключ, несколько null-значений.
Thread-safe: Нет (ConcurrentModificationException при параллельном доступе).
Initial capacity/load factor: new HashMap<>(16, 0.75f) для оптимизации.
Нюансы и ловушки:
hashCode/equals: Критичны! Плохой hashCode — деградация до O(n). Изменение ключа после put — потеря элемента.
Ресайз: O(n) время, но редко.
Java 8+: Tree nodes для коллизий (>8 узлов).
Remove: Если null-ключ — специальная обработка.
Итерация: entrySet(), keySet(), values() — O(capacity), не size().
Пример кода:
javaimport java.util.HashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String, Integer> ages = new HashMap<>();
ages.put("Алексей", 35);
ages.put("Мария", 28);
ages.put("Алексей", 36); // Перезапись
System.out.println(ages.get("Алексей")); // 36
ages.put(null, 0); // Null-ключ
System.out.println(ages.size()); // 3
// Итерация
for (Map.Entry<String, Integer> entry : ages.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}
}
}
Когда использовать: 99% случаев — быстрый поиск/кэш (userId -> User).
2. LinkedHashMap<K, V>: HashMap с порядком
Описание: Расширение HashMap с двусвязным списком для сохранения порядка вставки (insertion-order) или доступа (access-order для LRU-кэша).
Внутренняя структура: HashMap + Entry с prev/next ссылками. Два режима: INSERTION_ORDER (default) или ACCESS_ORDER (constructor flag).
Big O: O(1) для put/get/remove, как HashMap.
Особенности:
Порядок: Вставки (по умолчанию) или доступа (get/put обновляет позицию).
Null: Да.
Thread-safe: Нет.
Нюансы:
LRU кэш: new LinkedHashMap<>(16, 0.75f, true) — access-order, removeEldestEntry для eviction.
Итерация: В порядке вставки/доступа.
Ресайз: Как HashMap, но сохраняет порядок.
Пример:
javaimport java.util.LinkedHashMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<String, Integer> map = new LinkedHashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("A", 3); // Обновляет, но порядок сохраняется
for (String key : map.keySet()) {
System.out.println(key); // A, B — порядок вставки
}
// Access-order
Map<String, Integer> lru = new LinkedHashMap<>(16, 0.75f, true);
lru.put("A", 1);
lru.get("A"); // "A" перемещается в конец
}
}
Когда использовать: Кэш с порядком (LRU), когда нужен predictable iteration.
#Java #для_новичков #beginner #Map #HashMap #LinkedHashMap #TreeMap #Hashtable #IdentityHashMap #EnumMap #WeakHashMap
3. TreeMap<K, V>: Отсортированная Map
Описание: Реализация SortedMap<K, V> на красно-черном дереве (red-black tree). Ключи всегда отсортированы.
Внутренняя структура: Дерево узлов с left/right/child ссылками, цветом для баланса.
Big O: O(log n) для put/get/remove/containsKey.
Особенности:
Порядок: Сортировка по ключам (Comparable или Comparator).
Null-ключ: Нет (NPE).
Null-значение: Да.
Thread-safe: Нет.
Нюансы:
Comparator: new TreeMap<>(comparator) для custom сортировки.
Дополнительные методы: firstKey(), lastKey(), headMap(K to), tailMap(K from), subMap.
Custom ключи: Comparable<K> или Comparator.
Баланс: Автоматический, O(log n) гарантировано.
Пример:
Остальные реализации: Hashtable, IdentityHashMap, EnumMap, WeakHashMap
Hashtable<K, V> (устаревшая)
Описание: Первая Map в Java (1.0), synchronized версия HashMap.
Особенности: Thread-safe (synchronized методы), нет null, порядок нет.
Big O: O(1).
Нюансы: Медленнее HashMap (locks на каждый метод), legacy — используйте ConcurrentHashMap.
Когда: Только legacy код.
IdentityHashMap<K, V>
Описание: HashMap с == вместо equals/hashCode (по ссылке).
Особенности: Для объектов, где важна идентичность (graph algorithms).
Big O: O(1).
Нюансы: Load factor 0.5, double hash для коллизий.
Когда: Редко, для identity сравнения.
EnumMap<K extends Enum<K>, V>
Описание: Оптимизированная Map для enum ключей (массив вместо хэш).
Особенности: O(1), порядок enum, нет null-ключа.
Нюансы: Ключи — enum, values any.
Когда: State machines, enum configs.
WeakHashMap<K, V>
Описание: HashMap с weak keys (GC может удалить entry, если ключ недостижим).
Особенности: Для кэшей, где память критична.
Big O: O(1).
Нюансы: Values strong, cleanup не мгновенный.
Когда: Canonicalizing mappings (interning).
Полезные советы для новичков
HashMap 95% случаев: Начните с неё.
LinkedHashMap для кэша: removeEldestEntry для LRU.
TreeMap для сортировки: Comparator для reverse.
Custom ключи: IDE генерирует equals/hashCode.
Initial capacity: new HashMap<>(expectedSize) для избежания ресайза.
Ошибки: NPE в TreeMap с null-ключом; ClassCast в TreeMap без Comparable.
#Java #для_новичков #beginner #Map #HashMap #LinkedHashMap #TreeMap #Hashtable #IdentityHashMap #EnumMap #WeakHashMap
Описание: Реализация SortedMap<K, V> на красно-черном дереве (red-black tree). Ключи всегда отсортированы.
Внутренняя структура: Дерево узлов с left/right/child ссылками, цветом для баланса.
Big O: O(log n) для put/get/remove/containsKey.
Особенности:
Порядок: Сортировка по ключам (Comparable или Comparator).
Null-ключ: Нет (NPE).
Null-значение: Да.
Thread-safe: Нет.
Нюансы:
Comparator: new TreeMap<>(comparator) для custom сортировки.
Дополнительные методы: firstKey(), lastKey(), headMap(K to), tailMap(K from), subMap.
Custom ключи: Comparable<K> или Comparator.
Баланс: Автоматический, O(log n) гарантировано.
Пример:
javaimport java.util.TreeMap;
import java.util.Map;
public class Main {
public static void main(String[] args) {
Map<Integer, String> map = new TreeMap<>();
map.put(3, "Три");
map.put(1, "Один");
map.put(2, "Два");
for (Integer key : map.keySet()) {
System.out.println(key + ": " + map.get(key)); // 1: Один, 2: Два, 3: Три
}
System.out.println(map.firstKey()); // 1
}
}
Когда использовать: Отсортированные ключи (диапазонные запросы, алфавитный словарь).
Остальные реализации: Hashtable, IdentityHashMap, EnumMap, WeakHashMap
Hashtable<K, V> (устаревшая)
Описание: Первая Map в Java (1.0), synchronized версия HashMap.
Особенности: Thread-safe (synchronized методы), нет null, порядок нет.
Big O: O(1).
Нюансы: Медленнее HashMap (locks на каждый метод), legacy — используйте ConcurrentHashMap.
Когда: Только legacy код.
IdentityHashMap<K, V>
Описание: HashMap с == вместо equals/hashCode (по ссылке).
Особенности: Для объектов, где важна идентичность (graph algorithms).
Big O: O(1).
Нюансы: Load factor 0.5, double hash для коллизий.
Когда: Редко, для identity сравнения.
EnumMap<K extends Enum<K>, V>
Описание: Оптимизированная Map для enum ключей (массив вместо хэш).
Особенности: O(1), порядок enum, нет null-ключа.
Нюансы: Ключи — enum, values any.
Когда: State machines, enum configs.
WeakHashMap<K, V>
Описание: HashMap с weak keys (GC может удалить entry, если ключ недостижим).
Особенности: Для кэшей, где память критична.
Big O: O(1).
Нюансы: Values strong, cleanup не мгновенный.
Когда: Canonicalizing mappings (interning).
Полезные советы для новичков
HashMap 95% случаев: Начните с неё.
LinkedHashMap для кэша: removeEldestEntry для LRU.
TreeMap для сортировки: Comparator для reverse.
Custom ключи: IDE генерирует equals/hashCode.
Initial capacity: new HashMap<>(expectedSize) для избежания ресайза.
Ошибки: NPE в TreeMap с null-ключом; ClassCast в TreeMap без Comparable.
#Java #для_новичков #beginner #Map #HashMap #LinkedHashMap #TreeMap #Hashtable #IdentityHashMap #EnumMap #WeakHashMap
👍1
  