Java for Beginner
870 subscribers
1.01K photos
275 videos
14 files
1.69K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Варианты ответа:
Anonymous Quiz
10%
0
25%
3
20%
4
45%
Исключение
👍1
Вопрос с собеседований

Что такое CAS-операция? 🤓

Ответ:

Compare-And-Swap
— атомарная операция на уровне процессора.

Сравнивает текущее значение с ожидаемым и обновляет только при совпадении. Лежит в основе атомарных классов Java.

Позволяет создавать неблокирующие алгоритмы.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
История IT-технологий сегодня — 24 декабря


ℹ️ Кто родился в этот день

Не нашел(


🌐 Знаковые события

1906 – Реджинальд Фессенден передает первую радиопередачу , состоящую из чтения стихов, скрипичного соло и речи.

1968 Программа «Аполлон»: Экипаж «Аполлона-8» выходит на орбиту вокруг Луны, став первыми людьми, сделавшим это. Они совершили десять лунных витков, сделали фотографию восхода Земли, транслировали телепередачи в прямом эфире.


#Biography #Birth_Date #Events #24Декабря
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Чат GPT подвел итоги 2025 года.

Мои выглядят так.

А Ваши? 🙃

Делитесь
в комментариях😉
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Раздел 6. Коллекции в Java

Глава 7. Сравнение объектов

Практика: В «Библиотеке» реализовать сортировку книг: по названию (Comparable), по автору и году издания (Comparator)


Сегодня мы значительно расширим функциональность проекта «Библиотека», добавив возможность сортировки списка книг. Это один из самых важных навыков в работе с коллекциями — умение упорядочивать данные по разным критериям.

Мы реализуем два подхода:
Сортировка по названию — с помощью интерфейса Comparable<Book> (натуральный порядок).
Сортировка по автору и году издания — с помощью Comparator<Book> (внешние компараторы).


Перед началом убедитесь, что проект готов:
Класс Book с полями title (String), author (String), year (int), геттерами и методом printDetails().
Класс Library с List<Book> books = new ArrayList<>().
Методы добавления книг, поиска, вывода и т.д.



Импорты: Убедитесь, что в Library.java импортированы:
java.util.Comparator
java.util.Collections (для Collections.sort())
java.lang.Comparable (не обязателен импорт, но полезно знать)


Планирование: Мы добавим несколько методов сортировки в Library, чтобы можно было вызывать их по отдельности.


Реализация сортировки по названию (Comparable)

Первый способ — сделать класс Book реализующим интерфейс Comparable<Book>. Это означает, что книги будут иметь натуральный порядок — по умолчанию по названию.

Откройте класс Book.java.
Добавьте implements Comparable<Book> к объявлению класса:
public class Book implements Comparable<Book>


Реализуйте метод compareTo(Book other):
Метод должен возвращать int: отрицательное — если текущая книга "меньше", 0 — если равны, положительное — если "больше".
Сравнивайте по полю title.
Используйте this.title.compareTo(other.title) — это строковое сравнение с учетом регистра (можно compareToIgnoreCase для нечувствительности к регистру).
Обработайте null: если title == null, считайте книгу "меньше" или бросьте исключение (лучше проверить в конструкторе, что title не null).


Почему именно title? Это наиболее логичный натуральный порядок для книг — как в алфавитном каталоге библиотеки.


Реализация сортировки по автору и году (Comparator)

Второй способ — внешние компараторы. Это позволяет сортировать один и тот же список по разным критериям, не меняя класс Book.

Создайте компаратор по автору:
В классе Library создайте приватное статическое поле или отдельный метод, возвращающий Comparator<Book>.
Comparator.compare(Book b1, Book b2) должен сравнивать b1.getAuthor() и b2.getAuthor() (String.compareTo()).
Добавьте вторичное сравнение по году, если авторы совпадают: если авторы равны — b1.getYear() - b2.getYear().


Создайте компаратор по году и автору:
Аналогично, но сначала по году (b1.getYear() - b2.getYear()), затем по автору как tie-breaker.

Создайте компаратор по году (простой):
Только по году издания (возрастание или убывание — на выбор).


#Java #для_новичков #beginner #Comparable #Практика
👍1
Методы сортировки в классе Library

Теперь реализуйте методы, которые будут использовать эти компараторы.

Метод sortByTitle():
Используйте Collections.sort(books) — поскольку Book реализует Comparable, сортировка будет по натуральному порядку (названию).
Или books.sort(null) — эквивалентно.


Метод sortByAuthorThenYear():
Используйте books.sort(comparatorByAuthor) — где comparatorByAuthor — ваш компаратор.

Метод sortByYearThenAuthor():
Аналогично с другим компаратором.

Метод sortByYear():
Простой компаратор по году.

Метод printAllBooks() (обновите или создайте):
Добавьте нумерацию (int i = 1; i++) для удобства просмотра порядка после сортировки.


Тестирование в Main

Добавьте книги:
Создайте 6–8 книг с одинаковыми авторами, годами и названиями (для проверки tie-breaker).

Протестируйте сортировки:
Вызовите printAllBooks() — исходный порядок.
sortByTitle() → printAllBooks() — по алфавиту названий.
sortByAuthorThenYear() → printAllBooks() — по автору, затем году.
sortByYearThenAuthor() → printAllBooks().
sortByYear() → printAllBooks().


Проверка стабильности:
Убедитесь, что при равенстве основных полей вторичные работают (tie-breaker).


Нюансы и ловушки

Null в полях: Если title/author/year могут быть null — добавьте проверки в compareTo/comparator (NullPointerException иначе).
Регистр: compareTo чувствителен к регистру ("а" > "Я"). Используйте compareToIgnoreCase или String.CASE_INSENSITIVE_ORDER.
Стабильность сортировки: Collections.sort стабильна — равные элементы сохраняют относительный порядок.
Производительность: O(n log n) для sort.


Comparable vs Comparator:
Comparable — один натуральный порядок, меняет класс.
Comparator — множественные, внешние, гибче.


List.sort vs Collections.sort: List.sort(null) для Comparable, List.sort(comparator) — предпочтительнее (не создает копию).



Полезные советы для новичков

Comparator как анонимный класс или лямбда: В Java 8+ можно использовать лямбды: Comparator.comparing(Book::getAuthor).thenComparing(Book::getYear)
Chain компараторов: comparing(...).thenComparing(...) — удобно.
Reverse: comparator.reversed() для обратного порядка.
IDE помощь: После implements Comparable IDE предложит реализовать compareTo.
Тестирование: Добавляйте книги с одинаковыми значениями для проверки tie-breaker.



Практическое задание

Задача 1: Реализуйте Comparable по title с ignoreCase.
Задача 2: Создайте компаратор по длине названия (title.length()).
Задача 3: Добавьте метод sortByMultipleCriteria() с цепочкой: год → автор → название.
Задача 4: Протестируйте все сортировки с 8+ книгами, включая дубликаты.



#Java #для_новичков #beginner #Comparable #Практика
👍1
Что выведет код?

import java.util.*;

public class Task241225 {
public static void main(String[] args) {
Set<Integer> set = new LinkedHashSet<>(Arrays.asList(5, 2, 8, 1));

set.removeIf(x -> x > 3);

Iterator<Integer> iterator = set.iterator();
while (iterator.hasNext()) {
Integer x = iterator.next();
set.add(x * 2);
}

System.out.println("Set: " + set);
}
}


#Tasks
👍1
Вопрос с собеседований

Чем отличается FixedThreadPool от CachedThreadPool? 🤓

Ответ:

Fixed
создаёт ограниченное число потоков и очередь.

Cached создаёт неограниченное число потоков и уничтожает простаивающие.

Cached подходит для коротких задач, Fixed — для контролируемой нагрузки.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
История IT-технологий сегодня — 25 декабря


ℹ️ Кто родился в этот день

Исаа́к Нью́то́н (англ. Isaac Newton, английское произношение: [ˌaɪzək ˈnjuːtən]; 25 декабря 1642 [4 января 1643] — 20 [31] марта 1727) — английский физик, математик, механик и астроном, один из создателей классической физики и математического анализа.


🌐 Знаковые события

1946 – В советском ядерном реакторе Ф-1 инициирована первая в Европе самоподдерживающаяся ядерная цепная реакция.


#Biography #Birth_Date #Events #25Декабря
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🔥1
Современный RabbitMQ 2025: Фундаментальная сила в эпоху событийных архитектур

Введение: Почему RabbitMQ остаётся архитектурным столпом

RabbitMQ, реализация протокола AMQP (Advanced Message Queuing Protocol — расширенный протокол очередей сообщений), продолжает быть критически важным компонентом в распределённых системах, несмотря на появление множества альтернатив. Его устойчивость объясняется не просто «историческим наследием», а фундаментальными архитектурными принципами, которые идеально соответствуют ряду современных паттернов разработки. В 2025 году RabbitMQ — это не просто брокер сообщений, а полноценная платформа для управления потоками данных и событий, эволюционировавшая для удовлетворения требований cloud-native эпохи.


Проблемы, которые RabbitMQ решает в 2025 году

Управление асинхронной коммуникацией

Современные системы состоят из десятков и сотен сервисов, написанных на разных языках, размещённых в различных средах (on-premise, облако, edge-устройства). RabbitMQ обеспечивает универсальный транспортный слой, абстрагирующий протоколы и форматы данных. Его поддержка множества протоколов (AMQP 1.0, MQTT, STOMP, HTTP через Web-STOMP) делает его идеальным связующим звеном для разнородных компонентов системы.

Реализация устойчивых Event-Driven Architectures (EDA)

Event-Driven Architecture (EDA) — архитектура, управляемая событиями, где компоненты системы реагируют на события, генерируемые другими компонентами. RabbitMQ предоставляет надежную инфраструктуру для создания таких систем через механизмы обменников (exchanges) и очередей (queues), гарантируя доставку сообщений даже в условиях частичных отказов.

Контроль над потоком данных и предотвращение каскадных отказов

В распределённых системах внезапный всплеск нагрузки может привести к коллапсу сервисов.

RabbitMQ реализует паттерн Circuit Breaker (автоматический выключатель) на уровне инфраструктуры через:
Настройки QoS (Quality of Service — качество обслуживания) на канал
Ограничения скорости потребления (prefetch count)
Отказоустойчивые очереди, которые аккумулируют нагрузку
Приоритизацию сообщений

Обеспечение transactional integrity в распределённых транзакциях

Хотя RabbitMQ не является системой распределённых транзакций в классическом понимании, он предоставляет механизмы для обеспечения согласованности:
Подтверждение доставки (publisher confirms)
Транзакционные операции с сообщениями
Интеграция с паттерном Transactional Outbox (исходящий почтовый ящик) для гарантированной доставки событий при обновлении базы данных


Позиционирование в современном стеке технологий

В микросервисных архитектурах

RabbitMQ служит «кровеносной системой» микросервисов, обеспечивая:
Слабую связность (loose coupling) — сервисы не знают о существовании друг друга, взаимодействуя только через сообщения
Сервисное обнаружение (service discovery) через паттерн «публикация-подписка»
Репликацию данных между bounded context в Domain-Driven Design
Буферизацию запросов между API-гейтвеями и backend-сервисами

В событийно-ориентированных системах (Event-Driven)

RabbitMQ эволюционировал от простого брокера задач (task queue) к полноценной платформе для обработки событий:
Event Carrying State Transfer — передача состояния через события
Event Sourcing — хранение состояния системы как последовательности событий (часто в комбинации с Apache Kafka для долгосрочного хранения)
CQRS (Command Query Responsibility Segregation) — разделение ответственности на команды и запросы, где RabbitMQ обрабатывает команды и синхронизирует read-модели


#Java #middle #RabbitMQ
👍4
В serverless и FaaS архитектурах

RabbitMQ идеально дополняет serverless-функции:
Источник событий для триггеров функций в AWS Lambda, Azure Functions, Google Cloud Functions
Буфер для batch-обработки — накопление событий для последующей обработки пакетами
Мост между legacy-системами и cloud-native окружением благодаря поддержке стандартных протоколов

В edge computing и IoT

С поддержкой MQTT 5.0 RabbitMQ стал ключевым компонентом IoT-архитектур:

Агрегация данных с тысяч устройств
Преобразование протоколов между MQTT устройствами и backend-системами через AMQP
Локализованная обработка данных на edge-нодах с последующей синхронизацией с центральными системами


Реальные кейсы использования в 2025 году

Финансовый сектор: обработка транзакций в реальном времени

Крупные банки используют RabbitMQ для:
Маршрутизации платежных инструкций между legacy mainframe системами и modern digital banking платформами
Обеспечения гарантированной доставки fraud detection событий с strict ordering (строгим порядком доставки)
Балансировки нагрузки между инстансами скоринговых систем с predictable latency (предсказуемой задержкой)

Электронная коммерция: управление пиковыми нагрузками

Известные ритейлеры строят на RabbitMQ:
Инвентаризационные системы, где обновления наличия товаров распространяются на сотни нод кэша
Системы уведомлений, обрабатывающие миллионы push-нотификаций во время распродаж
Асинхронные pipeline для обработки заказов с компенсирующими транзакциями (Saga pattern)

Телекоммуникации: обработка событий сетевого оборудования

Телеком-операторы применяют RabbitMQ для:
Сбора телеметрии с сетевого оборудования через MQTT с последующей агрегацией
Распределения конфигурационных обновлений на тысячи устройств
Обработки CDR (Call Detail Records) в реальном времени для биллинга


Новые возможности в версиях 3.13+

Quorum Queues как очередь по умолчанию

Quorum Queues — это тип очередей, основанный на алгоритме консенсуса Raft, обеспечивающий высокую доступность и согласованность данных без потери сообщений.

С версии 3.13 они становятся рекомендуемым выбором для большинства сценариев:
Гарантия безопасности данных — сообщения реплицируются на большинство узлов кластера перед подтверждением отправителю
Автоматическое восстановление при выходе узлов из строя без необходимости ручного вмешательства
Упрощенная операционная модель по сравнению с классическими mirrored queues
Поддержка poison message handling — автоматическое перемещение проблемных сообщений в dead-letter очередь после нескольких неудачных попыток обработки


Улучшения в RabbitMQ Streams

Streams — это дополнение к традиционным очередям, добавляющее семантику потока данных с сохранением истории:
Увеличенная пропускная способность — оптимизации позволили достичь миллионов сообщений в секунду на одном узле
Эффективное хранение с дедупликацией данных и компрессией
Поддержка потребителей с разной скоростью через offset management (управление смещениями)
Интеграция с клиентскими библиотеками Kafka через совместимый протокол


#Java #middle #RabbitMQ
👍3
Полноценная поддержка MQTT 5.0

MQTT 5.0 — существенное обновление протокола для IoT, и RabbitMQ полностью реализует его возможности:
Session Expiry — контроль времени жизни сессий для мобильных и IoT устройств
Message Expiry — автоматическое удаление устаревших сообщений
Shared Subscriptions — балансировка нагрузки между несколькими подписчиками на одну тему
Request/Response паттерн — нативный механизм запросов-ответов поверх publish/subscribe


Мосты в Apache Kafka

RabbitMQ теперь предоставляет встроенные возможности интеграции с экосистемой Kafka:
Двунаправленные мосты — синхронизация данных между Kafka topics и RabbitMQ exchanges
Трансформация протоколов на лету между AMQP и Kafka wire protocol
Поддержка exactly-once семантики в определенных конфигурациях
Автоматическая реконнект-логика при временной недоступности кластера Kafka


Почему не только Kafka, но и RabbitMQ?

Различные архитектурные парадигмы

Apache Kafka и RabbitMQ решают принципиально разные задачи:
RabbitMQ — это message broker (брокер сообщений), оптимизированный для маршрутизации, управления очередями и гарантированной доставки индивидуальных сообщений
Kafka — это distributed log (распределенный журнал), оптимизированный для обработки потоков данных с высокой пропускной способностью и долгосрочным хранением

Сравнительные характеристики

RabbitMQ предпочтительнее когда нужно:

Сложная маршрутизация сообщений на основе заголовков, тем или других атрибутов
Гарантированная доставка с индивидуальными подтверждениями от потребителей
Приоритизация сообщений и управление временем жизни (TTL)
Работа с относительно небольшими сообщениями (до десятков мегабайт)
Быстрое прототипирование и изменение топологий обмена сообщениями
Требуется богатый набор протоколов для интеграции унаследованных систем

Kafka предпочтительнее когда нужно:
Обработка непрерывных потоков данных с экстремальной пропускной способностью
Долгосрочное хранение данных для повторной обработки или аудита
Обработка логов, метрик и событий телеметрии
Exactly-once семантика в рамках экосистемы Kafka Connect и Kafka Streams
Обработка окон временных данных (tumbling windows, sliding windows)

Гибридные архитектуры

В современных системах часто используются оба решения в комбинации:
RabbitMQ для оркестрации сервисов и обработки команд (command bus)
Kafka для хранения событий и обработки потоков данных (event store)
Мосты между ними для синхронизации состояний и передачи агрегированных данных

Такая архитектура позволяет использовать сильные стороны каждой технологии: гибкость маршрутизации RabbitMQ и масштабируемость потоковой обработки Kafka.


#Java #middle #RabbitMQ
👍3
Что выведет код?

import java.util.HashMap;
import java.util.Map;

public class Task251225 {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("a", 1);
map.put("b", 2);
map.put("c", 3);

long count = map.entrySet().stream()
.filter(entry -> {
if (entry.getKey().equals("b")) {
map.put("b", 20);
}
return entry.getValue() > 1;
})
.count();

System.out.println("Count: " + count);
System.out.println("Map: " + map);
}
}


#Tasks
👍2🔥1
Вопрос с собеседований

Что такое backpressure? 🤓

Ответ:

Backpressure
— механизм, позволяющий потребителю регулировать скорость производителя данных.

Без него быстрый источник перегружает систему.

Реализуется в Reactive Streams через запросы определённого количества элементов.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
История IT-технологий сегодня — 26 декабря


ℹ️ Кто родился в этот день

Ма́ртин Ку́пер (англ. Martin Cooper, род. 26 декабря 1928, Чикаго) — американский инженер и физик, известен как человек, совершивший первый звонок по сотовому телефону.

3 апреля 1973 года Купер совершил первый публичный звонок с портативного мобильного телефона, работая в компании Motorola, с тротуара Манхэттена своему коллеге из конкурирующей компании Bell Labs . В 1973 году Купер создал первый портативный сотовый мобильный телефон (отличный от автомобильного телефона) и возглавил команду, которая переработала его и вывела на рынок в 1983 году. Он считается «отцом (портативного) сотового телефона», и получил премию IEEE Masaru Ibuka Consumer Electronics Award 2015 года за эту работу.


🌐 Знаковые события

1898 – Мария и Пьер Кюри объявляют об выделении радия.


#Biography #Birth_Date #Events #26Декабря
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Раздел 6. Коллекции в Java

Глава 8. Дополнительные аспекты коллекций


Неизменяемые коллекции: List.of, Set.of, Collections.unmodifiableList

Неизменяемость (immutability) представляет собой одну из фундаментальных парадигм современного программирования, уходящую корнями в функциональное программирование и математику. В контексте коллекций неизменяемость означает, что после создания коллекция не может быть модифицирована — ни добавлением, ни удалением, ни изменением существующих элементов. Эта концепция противостоит традиционному императивному подходу, где мутация состояния является нормой, и предлагает альтернативный путь к созданию более надежных, предсказуемых и безопасных систем.


Историческая эволюция неизменяемых коллекций в Java

До Java 9 разработчики вынуждены были использовать обходные пути для создания неизменяемых коллекций. Основным инструментом был класс Collections с его методами unmodifiableXXX, которые создавали обертки над изменяемыми коллекциями. Однако эти обертки имели существенные ограничения и могли быть обойдены при неправильном использовании.

С выходом Java 9 была представлена революционная концепция фабричных методов для создания истинно неизменяемых коллекций: List.of(), Set.of(), Map.of(). Эти методы не просто создавали обертки, а возвращали специализированные реализации, которые с самого начала проектировались как неизменяемые.



Фундаментальные принципы неизменяемых коллекций

Неизменяемые коллекции воплощают декларативный подход к программированию. Вместо того чтобы описывать, как изменять состояние коллекции (императивный подход), разработчик описывает, какая коллекция должна существовать (декларативный подход).

Это смещение парадигмы приводит к нескольким важным следствиям:
Упрощение рассуждений о коде: Не нужно отслеживать последовательность мутаций
Повышение надежности: Исключены побочные эффекты от неожиданных изменений
Улучшение тестируемости: Состояние фиксировано и предсказуемо


Принцип безвредности (No Side Effects)

Неизменяемые коллекции строго следуют принципу отсутствия побочных эффектов. Операции над ними не изменяют исходные данные, а создают новые коллекции. Этот принцип заимствован из функционального программирования и математики, где функции не имеют побочных эффектов.


Фабричные методы в Java 9+: List.of(), Set.of(), Map.of()

Введение фабричных методов в Java 9 стало результатом многолетнего развития языка и осознания важности неизменяемости. Эти методы представляют собой не просто синтаксический сахар, а фундаментальное изменение в дизайне API коллекций.


List.of(): Создание неизменяемых списков


List.of() предоставляет 12 перегруженных версий для разного количества элементов:
// Различные сигнатуры
List.of() // Пустой список
List.of(e1) // Один элемент
List.of(e1, e2) // Два элемента
// ... до 10 элементов
List.of(e1, e2, ..., e10) // Десять элементов
List.of(elements...) // Varargs для любого количества


Такая вариативность — результат компромисса между удобством использования и производительностью. Перегрузки для конкретного количества элементов позволяют избежать создания массива при вызове varargs метода.

За фасадом List.of() скрываются специализированные реализации:
Пустой список: Возвращается синглтон ImmutableCollections.EMPTY_LIST
Список из 1-2 элементов: Используются компактные классы ImmutableCollections.List1, List2
Списки более 2 элементов: Используется общая реализация ImmutableCollections.ListN
Каждая из этих реализаций оптимизирована для своего сценария использования, что обеспечивает минимальный overhead по памяти и максимальную производительность.


Особенности семантики

Запрет null элементов: Все методы List.of() выбрасывают NullPointerException при попытке добавить null
Структурная неизменяемость: Не поддерживаются операции добавления, удаления, замены
Итераторы: Возвращаются итераторы, не поддерживающие операцию remove()
Сериализация: Специальная поддержка для эффективной сериализации


#Java #для_новичков #beginner #immutability #Collection #List_of #Set_of
👍4
Set.of(): Неизменяемые множества

В отличие от списков, множества предъявляют дополнительное требование — уникальность элементов.


Методы Set.of() строго проверяют это требование:
Set.of("a", "b", "c");        // Допустимо
Set.of("a", "b", "a"); // IllegalArgumentException: дубликат


Внутренняя структура


Для множеств также существуют оптимизированные реализации:
Пустое множество: Синглтон ImmutableCollections.EMPTY_SET
Множество из 1 элемента: ImmutableCollections.Set1
Множество из 2 элементов: Используется специальная структура для двух элементов
Большие множества: Используется ImmutableCollections.SetN на основе хэш-таблицы


Особенности производительности

Малые множества (до 2 элементов) используют особые алгоритмы сравнения, что делает операции contains() чрезвычайно эффективными — O(1) с очень малой константой.


Map.of(): Неизменяемые отображения

Для создания неизменяемых отображений используются два подхода:
// Прямое создание пар (до 10 пар)
Map.of(k1, v1, k2, v2, ..., k10, v10)

// Создание из пар Map.Entry
Map.ofEntries(
Map.entry(k1, v1),
Map.entry(k2, v2),
// ...
)


Требования к ключам

Как и для множеств, ключи в Map.of() должны быть уникальными. Попытка создания отображения с дублирующимися ключами приводит к IllegalArgumentException.

Внутренняя оптимизация

Для малых отображений используются специализированные реализации:
Пустое отображение: ImmutableCollections.EMPTY_MAP
Отображение из 1 пары: ImmutableCollections.Map1
Отображение из 2 пар: Используется оптимизированная структура
Для больших отображений используется массив пар ключ-значение с линейным поиском, что для небольших N (до ~10) оказывается эффективнее хэш-таблиц.



Collections.unmodifiableXXX(): Подход до Java 9

Методы Collections.unmodifiableList(), unmodifiableSet(), unmodifiableMap() и другие создают обертки над существующими изменяемыми коллекциями. Эти обертки делегируют операции чтения исходной коллекции, но запрещают операции модификации.

Механизм работы

Архитектура обертки
// Концептуальная реализация unmodifiableList
public static <T> List<T> unmodifiableList(List<? extends T> list) {
return (list instanceof UnmodifiableList) ?
(List<T>) list :
new UnmodifiableList<>(list);
}

static class UnmodifiableList<E> implements List<E> {
private final List<E> list;

UnmodifiableList(List<E> list) {
this.list = list;
}

public E get(int index) {
return list.get(index); // Делегирование
}

public void add(int index, E element) {
throw new UnsupportedOperationException(); // Запрет модификации
}
// ... остальные методы
}


Уровни неизменяемости


Важно понимать, что unmodifiableXXX создают только поверхностную (shallow) неизменяемость:
Структурная неизменяемость: Размер и состав коллекции не могут быть изменены
Элементная изменяемость: Объекты внутри коллекции могут быть изменяемыми


List<StringBuilder> list = new ArrayList<>();
list.add(new StringBuilder("Hello"));
List<StringBuilder> unmodifiable = Collections.unmodifiableList(list);

// Нельзя изменить структуру
unmodifiable.add(new StringBuilder("World")); // UnsupportedOperationException

// Но можно изменить содержимое элементов
unmodifiable.get(0).append(" World"); // Допустимо!


Исторический контекст


До Java 9 подход с unmodifiableXXX был единственным стандартным способом создания неизменяемых представлений.

Однако у него было несколько существенных недостатков:
Изменяемость исходной коллекции: Обертка отражает изменения в исходной коллекции
Возможность обхода защиты: Через приведение типов или reflection
Производительность: Дополнительный уровень индирекции



#Java #для_новичков #beginner #immutability #Collection #List_of #Set_of
👍5
Сравнительный анализ подходов

Null-безопасность

Методы List.of() и аналогичные полностью запрещают null элементы, что способствует написанию более безопасного кода. В противоположность этому, unmodifiableXXX позволяют null, если их разрешает исходная коллекция.

Поведение при модификации

// Пример с List.of()
List<String> immutable = List.of("A", "B", "C");
// Любая попытка модификации: UnsupportedOperationException

// Пример с unmodifiableList
List<String> mutable = new ArrayList<>(Arrays.asList("A", "B", "C"));
List<String> wrapper = Collections.unmodifiableList(mutable);

mutable.add("D"); // Изменяем исходный список
System.out.println(wrapper); // ["A", "B", "C", "D"] - обертка отражает изменения
Это фундаментальное различие: List.of() создает полностью независимую коллекцию, тогда как unmodifiableList() создает зависимое представление.


Производительность в деталях

Для List.of() с малым количеством элементов доступ по индексу может быть реализован через прямое поле:
// Концептуально для List.of(e1, e2)
class List2<E> extends AbstractImmutableList<E> {
private final E e0, e1;

public E get(int index) {
return switch (index) {
case 0 -> e0;
case 1 -> e1;
default -> throw new IndexOutOfBoundsException();
};
}
}


В то время как unmodifiableList всегда требует двойной диспетчеризации: вызов метода обертки → делегирование исходной коллекции.

Итерация

Итераторы для List.of() не имеют логики проверки модификаций и не поддерживают remove(), что делает их более легковесными.


Принципы проектирования неизменяемых коллекций

Паттерн "Builder" для сложных случаев

Для создания сложных неизменяемых коллекций Java предоставляет строители (builders):
// Для List
List<String> list = List.<String>builder()
.add("A")
.addAll(anotherList)
.build();

// Для Map
Map<String, Integer> map = Map.<String, Integer>builder()
.put("key1", 1)
.put("key2", 2)
.build();

Эти строители позволяют создавать неизменяемые коллекции инкрементально, что особенно полезно при динамическом построении.


Копирование с преобразованием

Частый паттерн — создание неизменяемой коллекции на основе существующей с фильтрацией или преобразованием:
List<String> mutable = Arrays.asList("A", "B", "C", null, "D");

// Фильтрация null и создание неизменяемого списка
List<String> immutable = mutable.stream()
.filter(Objects::nonNull)
.map(String::toUpperCase)
.collect(Collectors.toUnmodifiableList());



Безопасность в многопоточных сценариях

Потокобезопасность по умолчанию

Неизменяемые коллекции от природы потокобезопасны. Поскольку их состояние не может быть изменено после создания, множество потоков может одновременно читать коллекцию без какой-либо синхронизации.

Memory visibility


Благодаря принципам Java Memory Model, правильно опубликованная неизменяемая коллекция гарантирует, что все потоки увидят корректное состояние ее элементов:
// Безопасная публикация
public class Configuration {
public static final List<String> SETTINGS = List.of("A", "B", "C");
// Все потоки увидят полностью инициализированную коллекцию
}


Отсутствие race conditions

Поскольку нет операций модификации, полностью исключены race conditions, связанные с конкурентным доступом на запись.

Сравнение с synchronized коллекциями
// Synchronized подход (устаревший)
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
// Требует внешней синхронизации для compound операций

// CopyOnWriteArrayList (частичная неизменяемость)
CopyOnWriteArrayList<String> copyOnWrite = new CopyOnWriteArrayList<>();
// Дорогие операции записи, но безопасное чтение

// Полностью неизменяемый подход
List<String> immutable = List.of("A", "B", "C");
// Идеальная потокобезопасность без накладных расходов



#Java #для_новичков #beginner #immutability #Collection #List_of #Set_of
👍5