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
Вопрос с собеседований

Чем отличается 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
Практические паттерны использования

Конфигурации и константы
public class ApplicationConstants {
// Конфигурационные параметры
public static final List<String> SUPPORTED_LANGUAGES =
List.of("en", "es", "fr", "de");

public static final Map<String, Integer> DEFAULT_SETTINGS =
Map.of("timeout", 30, "retries", 3, "cacheSize", 1000);
}


Возврат из методов

public List<String> getActiveUsers() {
// Вместо возврата изменяемого списка
return List.copyOf(internalUserList); // Защитная копия как неизменяемый список
}


Параметры методов
public void processItems(List<String> items) {
// items должен быть неизменяемым или защищенной копией
List<String> safeItems = List.copyOf(items);
// Далее работаем с safeItems
}



Ограничения и когда не использовать

Динамические коллекции

Неизменяемые коллекции не подходят для сценариев, где требуется частое изменение состава:
// НЕПРАВИЛЬНО: постоянное создание новых коллекций
List<String> items = List.of();
for (Item item : source) {
items = Stream.concat(items.stream(), Stream.of(item.getName()))
.collect(Collectors.toUnmodifiableList()); // Очень дорого!
}

// ПРАВИЛЬНО: использование изменяемого построителя
List<String> itemsBuilder = new ArrayList<>();
for (Item item : source) {
itemsBuilder.add(item.getName());
}
List<String> items = List.copyOf(itemsBuilder);


Большие коллекции

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


Best practices

1. Предпочитайте List.of() над Arrays.asList()
// Хорошо
List<String> good = List.of("A", "B", "C");

// Плохо (возвращает изменяемый список, но фиксированного размера)
List<String> bad = Arrays.asList("A", "B", "C");


2. Защитное копирование при необходимости
public class SafeApi {
private final List<String> data;

public SafeApi(List<String> input) {
// Защитное копирование в неизменяемый список
this.data = List.copyOf(input);
}
}


3. Документируйте неизменяемость
/**
* Возвращает неизменяемый список активных пользователей.
* Попытки модификации приведут к UnsupportedOperationException.
*/
public List<User> getActiveUsers() {
return Collections.unmodifiableList(internalList);
}


4. Используйте соответствующие типы в сигнатурах
// Хорошо: ясно указывает на намерение
public void processItems(List<? extends String> items) {
// items может быть любым списком строк, включая неизменяемые
}

// Или даже лучше в Java 16+
public void processItems(SequencedCollection<String> items) {
// Явное указание на коллекцию с определенным порядком
}



Отладка и диагностика

Выявление скрытых модификаций

Для отладки проблем с неожиданными модификациями можно использовать обертки с логированием:
public static <T> List<T> loggingUnmodifiableList(List<T> list) {
return new AbstractList<T>() {
@Override
public T get(int index) {
return list.get(index);
}

@Override
public int size() {
return list.size();
}

@Override
public void add(int index, T element) {
logError("Attempt to modify unmodifiable list at index " + index);
throw new UnsupportedOperationException();
}
};
}


Профилирование использования памяти

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

Профилирование помогает выявить такие проблемы:
// Мониторинг создания коллекций
public class CollectionMonitor {
private static final AtomicLong listCreations = new AtomicLong();

public static <E> List<E> monitoredListOf(E... elements) {
listCreations.incrementAndGet();
return List.of(elements);
}

public static long getCreationCount() {
return listCreations.get();
}
}



#Java #для_новичков #beginner #immutability #Collection #List_of #Set_of
👍4
Что выведет код?

import java.util.*;

public class Task261225 {
public static void main(String[] args) {
Integer[] array = {1, 2, 3};
List<Integer> list1 = Arrays.asList(array);
List<Integer> list2 = List.of(array);
List<Integer> list3 = Collections.unmodifiableList(list1);

array[1] = 20;

System.out.println(list2.get(1));
System.out.println(list3.get(1));
}
}


#Tasks
👍3
Варианты ответа:
Anonymous Quiz
0%
20 20
25%
2 20
25%
20 2
50%
2 2
👍1😱1
Вопрос с собеседований

Как именно JVM определяет, что объект доступен для GC? 🤓

Ответ:

JVM использует алгоритмы достижимости (reachability analysis).

Объект считается живым, если до него можно добраться от GC Roots: локальных переменных стека, статических полей, активных потоков, JNI-ссылок.

Если путь отсутствует — объект помечается как мусор.


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


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

Не нашел((


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

2004 – Излучение от взрыва магнетара SGR 1806-20 достигает Земли. Это самое яркое из известных внесолнечных явлений, наблюдавшихся на планете.


#Biography #Birth_Date #Events #27Декабря
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
Предлагаю завтра встретиться в 16:00 по МСК и наконец-то понять, что такое Tree и как оно используется в Java! 🤓

Информацию готовит @ElizaFanat, за что ему огромное спасибо!

С собой берите предновогоднее настроение 🎄 и неподдельный интерес. На входе будет досмотр 😉😄

Жду всех!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
История IT-технологий сегодня — 28 декабря


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

Ли́нус Бенедикт То́рвальдс (встречается написание Ту́рвальдс) (швед. Linus Benedict Torvalds МФА: [ˈliːn.ɵs ˈtuːr.valds]о файле; род. 28 декабря 1969, Хельсинки) — финно-американский программист. Воодушевлённый прочтением книги Эндрю Таненбаума, посвящённой операционной системе Minix, Линус создал Linux — ядро операционной системы GNU/Linux, являющейся на данный момент самой распространённой из свободных операционных систем, а также наиболее популярной серверной ОС.

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

1895 – Вильгельм Рентген публикует статью, в которой подробно описывает свое открытие нового типа излучения , которое впоследствии станет известно как рентгеновские лучи.


#Biography #Birth_Date #Events #28Декабря
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Всем привет! ✌️

Напоминаю, что сегодня в 16:00 бот выдаст Вам ссылку на встречу, где вы точно узнаете что такое Tree в Java.

Приходите будет интересно. 🤫
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3