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

Конфигурации и константы
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
Я б поржать сходил 😂


https://t.me/Java_for_beginner_dev

#Mems
🔥3
Интересно это про какой фраймворк? 🤔


https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
🤓1🆒1
У всех сеньоров порой так бывает? 🤓


https://t.me/Java_for_beginner_dev

#Mems
Please open Telegram to view this post
VIEW IN TELEGRAM
🤓2
👾3
Встреча создана!

Бот @JFB_admin_bot выдаст ссылку. Для корректной работы лучше его перезапустить)

Залетаем ✈️
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3
Tree в Java.
Самая сложная коллекция.

В представленном видео, мы подробно разобрали, что такое Tree и как они представлены в Java.

Огромное спасибо @ElizaFanat за рассказ и демонстрации. 🙂

Ссылка на Youtube
Ссылка на Рутьюб

Смотрите, ставьте лайки, подписывайтесь на каналы!
✌️
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥2
История IT-технологий сегодня — 29 декабря


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

Ян Ливингстон (англ. Ian Livingstone; 29 декабря 1949, Престбери, Чешир, Англия) — английский автор-фантаст и антрепренёр. Соавтор первой книги-игры The Warlock of Firetop Mountain из серии Fighting Fantasy и сооснователь Games Workshop.

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

Не нашел(


#Biography #Birth_Date #Events #29Декабря
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Глубокая архитектура и внутреннее устройство RabbitMQ

AMQP 1.0 vs AMQP 0-9-1: эволюция протокола

AMQP 0-9-1: классическая модель RabbitMQ

AMQP 0-9-1 (Advanced Message Queuing Protocol версии 0-9-1) — это протокол, вокруг которого строился RabbitMQ с момента его создания.

Его ключевые характеристики:
Строгая топологическая модель с явным объявлением exchanges, queues и bindings
Frame-based протокол с четкой структурой кадров (frames)
Каналы (Channels) — виртуальные соединения внутри одного TCP-соединения для уменьшения накладных расходов
Подтверждения (Acknowledgements) на уровне потребителя и издателя
Транзакции через механизм tx.commit/tx.rollback

В 2025 году AMQP 0-9-1 остается основным протоколом для RabbitMQ, особенно для сценариев, требующих сложной маршрутизации и гарантий доставки.

AMQP 1.0: стандартизация и упрощение

AMQP 1.0 — это стандартизированная версия протокола, разработанная OASIS, с существенными изменениями:
Более абстрактная модель без явных понятий exchanges и bindings
Сообщения как первоклассные сущности с расширенными заголовками и свойствами
Связи (Links) вместо каналов, с разделением на sender и receiver links
Улучшенная обработка ошибок со стандартизированными кодами
Поддержка транзакций через распределенные транзакции (не полностью реализовано в RabbitMQ)

Сравнительный анализ

Когда использовать AMQP 0-9-1:
При работе со сложными маршрутизационными сценариями (headers exchange, topic exchange)
Когда необходима максимальная совместимость с существующими клиентскими библиотеками
Для использования расширенных функций RabbitMQ (политики, shovel, federation)
При миграции legacy систем без переписывания логики маршрутизации

Когда использовать AMQP 1.0:

При интеграции с системами, поддерживающими только AMQP 1.0 (Azure Service Bus, Apache Qpid)
Для межплатформенной совместимости в гетерогенных средах
Когда требуется стандартизированная обработка сообщений без vendor lock-in
В сценариях, где важнее семантика сообщений, а не топология маршрутизации


Поддержка в RabbitMQ 3.13+

RabbitMQ поддерживает оба протокола одновременно через разные порты:
AMQP 0-9-1: порт 5672 по умолчанию
AMQP 1.0: порт 5671 (или отдельно настроенный)

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


Низкоуровневая архитектура: как работает RabbitMQ внутри

Основа на Erlang/OTP: философия отказоустойчивости

Erlang/OTP — это платформа для построения распределенных, отказоустойчивых систем с soft real-time характеристиками.

Выбор Erlang для RabbitMQ был стратегическим решением:
Actor model — каждый процесс Erlang (не системный процесс) изолирован и обрабатывает сообщения асинхронно
"Let it crash" философия — процессы проектируются с ожиданием сбоев, которые обрабатываются супервизорами
Hot code reloading — возможность обновления кода без остановки системы
Распределенная природа — встроенная поддержка кластеризации и межпроцессного взаимодействия

В RabbitMQ различные компоненты реализованы как процессы Erlang:
Одна очередь = один или несколько процессов Erlang
Каждое соединение клиента = процесс Erlang
Каждый канал внутри соединения = отдельный процесс


#Java #middle #RabbitMQ
👍2
Процессная модель и планировщики

Erlang VM использует вытесняющую многозадачность с планировщиками (schedulers).

В RabbitMQ 3.13+:
По умолчанию используется по одному планировщику на CPU core
Каждый планировщик имеет свою очередь исполняемых процессов
Reductions — единица измерения работы в Erlang, используемая для fair scheduling

Псевдокод работы планировщика Erlang:

function scheduler_loop(queue, time_slice) {
while (true) {
process = queue.dequeue()
reductions_executed = 0

while (process.has_messages() && reductions_executed < time_slice) {
message = process.next_message()
result = process.execute(message)
reductions_executed += calculate_reductions(result)

if (process.crashed()) {
notify_supervisor(process)
break
}
}

if (process.has_messages()) {
queue.enqueue(process) // Вернуть в конец очереди
}
}
}


Управление памятью и сборка мусора

Память в Erlang управляется через per-process heap и shared binary heap:
Process heap — небольшая частная куча для термов Erlang
Binary heap — общая куча для больших данных (тела сообщений в RabbitMQ)
Copying garbage collector для process heap, работающий при заполнении кучи

Reference counting для binary heap

Для сообщений размером более 64 байт (настраиваемый параметр) тело хранится в binary heap, а в очереди сохраняется только ссылка. Это позволяет эффективно обрабатывать большие сообщения с несколькими потребителями.


Protocol internals: от байтов к семантике

AMQP 0-9-1 Frame структура
Frame Structure:
+----------+----------+----------+----------+----------+----------+
| Type | Channel | Size | Payload | Frame End |
| (1 byte) | (2 bytes)| (4 bytes)| (size bytes) | (1 byte) |
+----------+----------+----------+----------+----------+----------+

Frame Types:
- METHOD (1) : Вызов метода AMQP (declare, publish, consume)
- HEADER (2) : Заголовки сообщения (properties, headers)
- BODY (3) : Часть тела сообщения (может быть несколько фреймов)
- HEARTBEAT (8) : Keep-alive фрейм


Пример последовательности фреймов для публикации:
[METHOD] Basic.Publish(exchange="amq.direct", routing_key="queue1")
[HEADER] properties={content_type: "text/plain"}, body_size=1024
[BODY] chunk 1 of 1024 bytes
[BODY] chunk 2 of 1024 bytes (если сообщение больше frame_max)


Процесс обработки входящего сообщения
// Псевдокод обработки publish на стороне брокера
handle_publish(frame) {
// 1. Парсинг и валидация фреймов
method_frame = parse_method_frame(frame)
header_frame = read_next_frame() // Ожидаем HEADER фрейм

// 2. Поиск exchange по имени
exchange = lookup_exchange(method_frame.exchange)
if (!exchange) {
if (method_frame.mandatory) {
send_basic_return() // Сообщение возвращается отправителю
}
return
}

// 3. Маршрутизация через exchange
routes = exchange.route(method_frame.routing_key, header_frame.properties)

// 4. Для каждого получателя (очереди)
for (queue in routes.queues) {
// 5. Проверка TTL сообщения
if (header_frame.properties.expiration && is_expired(header_frame)) {
continue
}

// 6. Сохранение в очередь
message = {
id: generate_message_id(),
properties: header_frame.properties,
body: read_body_frames() // Чтение всех BODY фреймов
}

// 7. В зависимости от типа очереди
if (queue.type == "quorum") {
quorum_queue_append(queue, message)
} else if (queue.type == "stream") {
stream_append(queue, message)
} else {
classic_queue_append(queue, message)
}
}

// 8. Подтверждение издателю (если включены publisher confirms)
if (connection.publisher_confirms) {
send_basic_ack(delivery_tag)
}
}



#Java #middle #RabbitMQ
👍2
Новые типы очередей в RabbitMQ 3.13+

Quorum Queues: консенсус как основа надежности

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

Архитектура Quorum Queue

Quorum Queue Architecture:
+-------------------+ +-------------------+ +-------------------+
| Лидер | | Последователь | | Последователь |
| (Leader) |<---->| (Follower) |<---->| (Follower) |
| | | | | |
| • Принимает запись| | • Реплицирует | | • Реплицирует |
| • Отвечает клиентам| | данные | | данные |
| • Управляет | | • Голосует за | | • Голосует за |
| логом Raft | | выборы лидера | | выборы лидера |
+-------------------+ +-------------------+ +-------------------+
| | |
| Кворум (N/2 + 1) узлов согласны |
+---------------------------------------------------+


Жизненный цикл сообщения в Quorum Queue
// Псевдокод обработки записи в Quorum Queue
quorum_queue_append(queue, message) {
// 1. Лидер добавляет запись в свой лог
log_entry = {
term: current_term,
index: next_index++,
command: "ADD_MESSAGE",
data: message
}

leader_log.append(log_entry)

// 2. Репликация на последователей
followers_acked = 1 // Лидер уже записал

for (follower in queue.followers) {
send_append_entries(follower, log_entry)

// 3. Ожидание подтверждения от большинства
if (wait_for_ack(follower, timeout)) {
followers_acked++

if (followers_acked >= quorum_size(queue)) {
// 4. Коммит записи (становится видимой для чтения)
log_entry.committed = true
apply_to_state_machine(queue, log_entry)
return SUCCESS
}
}
}

// 5. Если кворум не достигнут
if (followers_acked < quorum_size(queue)) {
// Возврат к предыдущему индексу
next_index--
return FAILURE
}
}


Преимущества Quorum Queues:
Автоматическое восстановление после потери узла без ручного вмешательства
Гарантия consistency над availability в условиях сетевого раздела (CP система)
Эффективная работа с poison messages через автоматический DLQ
Лучшая производительность при сетевых задержках по сравнению с mirrored queues


#Java #middle #RabbitMQ
👍2
Stream Queues: потоковая семантика

Stream Queues — это гибридный тип, сочетающий возможности традиционных очередей с характеристиками потоковых систем.

Ключевые особенности Stream Queues:
Append-only лог с сегментированным хранением на диске
Поддержка потребителей с разной скоростью через offset-based потребление
Дедупликация сообщений по message ID
Компрессия данных на уровне сегментов
// Псевдокод работы Stream Queue
stream_append(queue, message) {
// 1. Проверка дедупликации
if (queue.deduplication_enabled && message.id in seen_ids) {
return DUPLICATE
}

// 2. Добавление в текущий активный сегмент
segment = get_active_segment(queue)

// 3. Если сегмент заполнен, ротация
if (segment.size + message.size > segment.max_size) {
segment.close()
segment = create_new_segment(queue)
queue.active_segment = segment

// 4. Компрессия закрытых сегментов (асинхронно)
schedule_compression(closed_segments)
}

// 5. Запись в сегмент
write_result = segment.append(
offset: segment.next_offset++,
timestamp: current_time(),
message: message
)

// 6. Обновление индекса для быстрого поиска
update_index(queue, message.id, segment.id, write_result.position)

return write_result.offset
}



Classic Queues: legacy с ограничениями

Classic Queues — оригинальная реализация очередей в RabbitMQ, сохраняемая для обратной совместимости:

Хранение в памяти или на диске в зависимости от persistence флагов
Mirrored queues для репликации (устаревшие, заменяются на Quorum Queues)
Ограничения при сетевых разделах (может потерять сообщения)
Более высокая производительность для ephemeral сообщений

В 2025 году использование Classic Queues рекомендуется только:
Для временных очередей (auto-delete, exclusive)
В тестовых средах
При миграции очень старых систем без возможности изменений


Стратегии хранения сообщений

Журнальная архитектура (Write-Ahead Log)

RabbitMQ использует WAL (Write-Ahead Log) для гарантированной сохранности сообщений:
// Упрощенная схема работы журнала
wal_append(message) {
// 1. Запись в журнал (последовательная запись)
log_entry = serialize(message)
wal_file.append(log_entry)
fsync(wal_file) // Синхронизация с диском

// 2. Добавление в in-memory структуры для быстрого доступа
index_entry = {
message_id: message.id,
wal_position: current_position,
queue: message.queue,
status: "PERSISTED"
}

memory_index.add(index_entry)

// 3. Периодическая очистка устаревших записей
if (wal_file.size > max_wal_size) {
rotate_wal_file()
}
}


Стратегии persistence в зависимости от типа очереди

Для Quorum Queues:
Все сообщения записываются на диск на всех узлах кворума
Используется segment-based хранение с индексами
Политика удержания: настраиваемое время или размер диска

Для Stream Queues:
Все сообщения хранятся на диске в сегментах
Сегменты закрываются при достижении лимита (время или размер)
Старые сегменты могут удаляться или архивироваться

Для Classic Queues с persistence:
Сообщения с флагом persistent записываются в журнал
Индекс очереди хранится в памяти для производительности
При восстановлении после сбоя: перестроение индекса из журнала


Управление памятью: ограничения и алертинг

RabbitMQ 3.13+ включает продвинутые механизмы контроля памяти:
// Механизм flow control на основе памяти
check_memory_pressure() {
memory_used = get_memory_usage()

if (memory_used > memory_limit_high_watermark) {
// 1. Приостановка публикаций
block_publishers()

// 2. Принудительная выгрузка сообщений на диск
for (queue in queues) {
if (queue.messages_in_memory > threshold) {
page_to_disk(queue)
}
}

// 3. Если не помогло, отключение соединений
if (memory_used > memory_limit_critical) {
disconnect_clients_by_memory_usage()
}
}
}



#Java #middle #RabbitMQ
👍4