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

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

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Что такое @Autowired в Spring и как он работает? 🤓

Ответ:

@Autowired — это аннотация Spring для внедрения зависимостей (Dependency Injection).

Может применяться к конструкторам, сеттерам, полям и методам. Spring сканирует контекст и находит бин соответствующего типа.

Если найдено несколько бинов одного типа, используется 
@Qualifier или @Primary. Начиная с Spring 4.3, @Autowired для конструктора можно не писать, если у класса один конструктор.

Лучшая практика — внедрение через конструктор (для неизменяемых зависимостей и тестируемости).



#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История технологии сегодня — 08 августа

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

Михаил Владимирович Донской (8 августа 1948 — 13 января 2009, Москва) — российский программист и предприниматель, один из создателей шахматной программы «Каисса» — первого чемпиона мира среди шахматных программ (1974 год), создатель и глава информационно-технологической компании «ДИСКо».

Ро́джер Пенро́уз (англ. Roger Penrose; род. 8 августа 1931, Колчестер, Англия) — британский физик и математик, работающий в различных областях математики, общей теории относительности и квантовой теории; автор теории твисторов. Нобелевская премия по физике (2020) «за открытие того, что образование чёрных дыр с необходимостью следует из общей теории относительности».

Поль Адриен Морис Дира́к (англ. Paul Adrien Maurice Dirac; 8 августа 1902, Бристоль — 20 октября 1984, Таллахасси) — британский физик-теоретик, один из создателей квантовой механики. Лауреат Нобелевской премии по физике 1933 года (совместно с Эрвином Шрёдингером). Работы Дирака посвящены квантовой физикетеории элементарных частицобщей теории относительности. Он является автором основополагающих трудов по квантовой механике (общая теория преобразований), квантовой электродинамике (метод вторичного квантования и многовременной формализм) и квантовой теории поля (квантование систем со связями). Предложенное им релятивистское уравнение электрона позволило естественным образом объяснить спин и ввести представление об античастицах.

Эрнест Орландо Ло́уренс (англ. Ernest Orlando Lawrence; 8 августа 1901, Кантон, Южная Дакота, США — 27 августа 1958, Пало-Алто, Калифорния, США) — американский физик-ядерщик, создатель первого циклотрона (1930), за что он был удостоен Нобелевской премии (1939). Проводил исследования по ядерной физике и принимал участие в создании атомной бомбы.


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

1899 — американский изобретатель из Миннесоты Альберт Маршалл запатентовал холодильник.


#Biography #Birth_Date #Events #08августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
В бота добавил еще 3 задачи!

Каждого уровня по одной) Дерзайте и делитесь результатами в специальной группе бота. Ссылка в вкладке "от автора".

@Review_Trainer_Bot

@Oleborn
👍4
История технологии сегодня — 09 августа

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

Ма́рвин Ли Ми́нский (англ. Marvin Lee Minsky; 9 августа 1927 — 24 января 2016) — американский учёный в области искусственного интеллекта, сооснователь Лаборатории искусственного интеллекта в Массачусетском технологическом институте.

Никола́й Си́дорович Хло́пкин (9 августа 1923, село Ильинка, Владимирская губерния — 19 декабря 2012, Москва) — советский и российский учёный, доктор технических наук, специалист в области ядерной энергетики и теплофизики.

Анато́лий Ива́нович Кито́в (9 августа 1920, Самара — 14 октября 2005, Москва) — советский и российский учёный, пионер советской кибернетики и информатики, разработчик электронно-вычислительной техники в СССР.

Уи́льям А́лфред Фа́улер (англ. William Alfred Fowler; 9 августа 1911, Питтсбург, Пенсильвания, США — 14 марта 1995, Пасадина, Калифорния, США) — американский физик и астрофизик. Лауреат Нобелевской премии по физике 1983 года — «за теоретическое и экспериментальное исследование ядерных реакций, имеющих важное значение для образования химических элементов Вселенной».

Эрих Арманд Артур Йозеф Хюккель (нем. Erich Armand Arthur Joseph Hückel; 9 августа 1896, Берлин — 16 февраля 1980, Марбург) — немецкий учёный, физик и химик, один из основоположников квантовой химии, создатель теории сильных электролитов (совместно с П. Дебаем).


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

1859 — американец Натан Эймс (Nathan Ames) запатентовал эскалатор.

1910 — американец из Чикаго Альва Джон Фишер запатентовал электрическую стиральную машину.


#Biography #Birth_Date #Events #09августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Наш "Темный попутчик"

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

“О, уведомление в телефоне, хм...”
“Пойду налью кофе/чай/вискарика, а то не сосредоточусь”
“Так, а может завтра тоже есть время?”


И вот он уже рядом. Сел поудобнее рядом и улыбается.

Тёмный попутчик - ПРОКРАСТИНАЦИЯ🏝


Но на самом деле, все не так страшно ☺️

Давай разбираться
😉

Прокрастинация — это не лень ❗️

Серьёзно.
Если бы это была просто лень — ты бы не испытывал вину за бездействие.
Ты бы не планировал, не страдал, не искал решения.


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

"Прокрастинация — это не проблема управления временем. Это проблема управления эмоциями."
— Тимоти Пихл, профессор психологии, автор исследований по теме.

То есть ты откладываешь не потому что «плохо спланировал день», а потому что в моменте задача вызывает дискомфорт, страх, перфекционизм или даже неосознанную тревогу провала.
(И мозг такой: “А может не надо испытывать всё это прямо сейчас?.. Давай YouTube-чик?..”)


Ты можешь спросить: Это как «Синдром самозванца» из предыдущей статьи?

Да.
И они очень часто идут рука об руку. 🤝

Синдром самозванца шепчет тебе: "Ты не справишься. Ты недостаточно хорош. Это не для тебя".
А прокрастинация отвечает: "Окей! Давай немного отложим! На потом! А пока посмотрим видосы про котиков".
🆘

Сочетание этих двух — вражеский тандем внутри твоей головы. Один пугает, другой уводит от страха. В итоге ты вроде и не бездельничаешь (ну, ты же чем-то занят!), но никуда не продвигаешься.



Откуда приходит прокрастинация?

Психологи выделяют несколько корней прокрастинации:
Эмоциональное избегание – когда ты еще не начал задачу, но уже стрессуешь, что она сложная и ты не справишься. И вместо поиска решения, залипаешь в тик-ток.
Перфекционизм – когда задача кажется слишком важной, и хочется сделать ее «идеально». Но идеал недостижим → страшно, что не получится → откладываем.
Низкая саморегуляция – отсутствие способности справляться с своими внутренними импульсами. Ты просто не можешь заставить себя сесть за задачу.



И что делать-то?

1. Принять, что это НОРМАЛЬНО.
Если ты осознал, что прокрастинируешь — не страшно. Я, ты, даже суперуспешные программисты — все откладывают. Просто надо научиться держать этот хаос под контролем.🧑‍💻

2. Обманывать мозг.
Сказать себе: “Сделаю 10 минут, и всё, можно будет отдыхать”. И, о чудо — через 30 минут ты уже глубоко в дебрях кода.
Это называется “техника маленьких шагов” — не грузить себя “большой задачей”, а начинать с малого. Упростить задачу, выбрав, что полегче и начать.
Работает почти всегда.


3. Выбери что-то одно.
Когда у тебя открыто множество обучающих вкладок: “Выучить Spring”, “Новое по Hibernate” или новая статья на канале “ Java for Beginner” — угадай, чем всё закончится? Правильно: YouTube, котики и стирка носков.
Выбери ОДНО и делай. Остальное — в «позже» (а может и в "нафиг"...
☺️).

4. Используй "tecnica del pomodoro"
25 минут работаешь, 5 отдыхаешь. Простой трюк, но мозгу легче "терпеть" неприятное, если знает, что скоро — пауза.
Это методика из когнитивно-поведенческой психологии — дробление задач снижает тревожность.



Но главное: не жди, что мотивация заняться задачей появится. 🤫

Если честно — мотивация в 90% случаев НЕ приходит.
Если прокрастинация в разгаре, то можно провалиться в окончательную лень и перестать бороться.
Начинать нужно без неё. Начинать нужно через "нехочу".

А вот когда пошел процесс, когда что-то получилось — появляется и мотивация.

Старт → действие → результат → мотивация.



Прокрастинация — не отсутствие силы воли. Это просто неправильный диалог с собой.

Мозг не против работать. Он просто не хочет страдать.
Договорись с темным попутчиком, обмани, разбей задачу, убери лишние эмоции — и действуй.



А теперь — иди и начни делать то, что откладывал, прокрастинируя и залипая в эту статью! 💪

😎

#motivation
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Ждете? ☺️

Скоро
...
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥10
История технологии сегодня — 10 августа

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

Алекса́ндр Григо́рьевич Столе́тов (29 июля [10 августа] 1839, Владимир — 16 [28] мая 1896, Москва) — русский физикзаслуженный профессор Императорского Московского университета.
Получил кривую намагничивания железа (1872), систематически исследовал внешний 
фотоэффект (1888—1890), открыл первый закон фотоэффекта. Исследовал газовый разряд, критическое состояние и другие явления. Основал физическую лабораторию в Императорском Московском университете.

Во́льфганг Па́уль (нем. Wolfgang Paul, МФА: [ˈvɔlfɡaŋ ˈpaʊ̯l]о файле; 10 августа 1913, Лоренцкирх[вд], Саксония — 7 декабря 1993, Бонн, Северный Рейн-Вестфалия) — немецкий физик, профессор, лауреат Нобелевской премии по физике в 1989 году (половина премии совместно с Хансом Демельтом) «за разработку метода удержания одиночных ионов». Вторую половину премии получил Норман Рамзей «за изобретение метода раздельных колебательных полей и его использование в водородном мазере и других атомных часах».

Луис Брюс (англ. Louis E. Brus — Луис Юджин Брус; 10 августа 1943, Кливленд, США — 11 января 2026) — американский физик, специалист по физической химии. Пионер в области квантовых точек. Лауреат Нобелевской премии по химии (2023).


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

2004 — телескоп Хаббл обнаружил галактику NGC3949, похожую на Млечный путь, и лишился одного из видеосенсоров.


#Biography #Birth_Date #Events #10августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
18. Кэширование в микросервисах: когда, зачем и какой ценой

В этом видео разбираем кэширование не как "подключить Redis", а как полноценное архитектурное решение — с ценой, альтернативами и осознанным выбором.

Что вас ждёт:

🔹 О чем надо подумать до того, как выбрать технологию — разбор всех альтернатив (реплика для чтения, денормализация, апгрейд железа) и почему кэш — не единственный и не всегда правильный ответ
🔹 Когда кэш вообще не нужен — универсальное правило: чем выше цена устаревших данных, тем осторожнее нужно кэшировать
🔹 Проверка гипотезы через HashMap — и почему это эксперимент, а не продакшен-код
🔹 Переход на Caffeine — вытеснение, TTL, контроль памяти
🔹 А что если просто @Cacheable? Честно разбираем, где стандартная Spring-абстракция полностью решает задачу, а где — нет
🔹 Устаревшие данные и согласованность: TTL vs Cache Evict vs их комбинация
🔹 Cache Hit Ratio как метрика успеха

Исходный код проекта на GitHub наверняка заслуживает Ваших звезд! 🙂

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

Смотрите, ставьте лайки, подписывайтесь на каналы!✌️

Жду ваших реакций и оценок
🙂
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥1🤯1😱1
Раздел 11. Работа с файлами, I/O и сетью (NIO.2)

Глава 3. Сериализация и форматы обмена

Protocol Buffers (Protobuf) — бинарный формат сериализации от Google

Protocol Buffers (Protobuf) — это механизм нейтрального к платформе и языку расширяемого сериализации структурированных данных, разработанный Google. Первый публичный релиз состоялся в 2008 году, хотя внутри Google формат использовался с 2001 года. На момент 2026 года актуальная версия спецификации — proto3 (Protocol Buffers версии 3), выпущенная в 2016 году, с последующими обновлениями языка и runtime.

Protobuf решает фундаментальную проблему текстовых форматов вроде JSON и XML: они удобны для человека, но неэффективны для машины. Каждый символ в JSON занимает байт (или несколько в UTF-8), каждая фигурная скобка, запятая и кавычка — это накладные расходы. В высоконагруженных распределённых системах, где сервисы обмениваются миллионами сообщений в секунду, эти накладные расходы становятся bottleneck на уровне CPU, памяти и сетевой пропускной способности. Protobuf заменяет текстовое представление на компактное бинарное, при этом сохраняя строгую типизацию и возможность эволюции схемы.

Bottleneck — это узкое место в системе, которое ограничивает общую производительность. В контексте сериализации bottleneck часто проявляется в виде высокой нагрузки на CPU при парсинге текстовых форматов, избыточном потреблении памяти кучи и низкой пропускной способности сети из-за раздутого размера сообщений.



Архитектура: схема как контракт


В основе Protobuf лежит идея schema-first (сначала схема). Разработчик описывает структуру данных в файле с расширением .proto на специальном языке описания интерфейсов (IDL — Interface Definition Language), а затем компилирует этот файл в код на целевом языке программирования. Этот подход кардинально отличается от JSON, где схема существует только в головах разработчиков или в отдельном документе (OpenAPI), но не является частью процесса сериализации.
IDL (Interface Definition Language) — это язык формальной спецификации интерфейсов программных компонентов. В контексте Protobuf IDL описывает структуру сообщений, их поля, типы и правила версионирования.


Пример .proto файла

syntax = "proto3";

package library;

// Опция java_package переопределяет пакет для сгенерированных Java-классов
option java_package = "com.example.library.proto";
option java_multiple_files = true;

// Сообщение Book описывает структуру книги
message Book {
// Поле с номером тега 1. Тег — это уникальный идентификатор поля в пределах сообщения
string title = 1;

// Поле с номером тега 2
string author = 2;

// int32 — 32-битное целое со знаком
int32 year = 3;

// double — 64-битное число с плавающей точкой
double price = 4;

// bool — булево значение
bool available = 5;

// repeated — повторяющееся поле, аналог списка или массива
repeated string tags = 6;

// Вложенное сообщение
message Publisher {
string name = 1;
string country = 2;
}

Publisher publisher = 7;
}


Ключевые элементы синтаксиса:

syntax = "proto3" — указание версии языка. proto3 — современная версия, упрощённая по сравнению с proto2. В proto3 все поля технически optional, нет required-полей, нет значений по умолчанию для полей сообщений.

message — единица структуры данных, аналог класса в ООП. Каждое сообщение компилируется в класс на целевом языке.
field_type field_name = field_number — объявление поля. Тип, имя и номер тега. Номер тега — целое число от 1 до 536870911 (2^29 - 1), но рекомендуется использовать 1–15 для частых полей, так как они кодируются одним байтом.

repeated — модификатор, указывающий, что поле является коллекцией. В proto3 repeated-поля кодируются как packed по умолчанию для скалярных типов, что экономит пространство.
option — метаданные компиляции. java_package задаёт пакет Java-классов, java_multiple_files = true генерирует отдельный файл для каждого сообщения вместо одного большого файла с вложенными классами.
Тег (field number) — это уникальный числовой идентификатор поля в пределах сообщения Protobuf. Тег, а не имя поля, записывается в бинарное представление. Это позволяет изменять имена полей в схеме, не ломая бинарную совместимость, так как парсер опирается на номера тегов.



#Java #для_новичков #beginner #IO #NIO #Serialize #Protobuf
👍4
Бинарное кодирование: wire format

Protobuf использует собственный бинарный формат передачи — wire format. Он основан на принципе TLV (Tag-Length-Value) для сложных типов и TV (Tag-Value) для скаляров переменной длины. Каждое поле сообщения кодируется независимо, и порядок полей в бинарном потоке не обязан совпадать с порядком объявления в .proto файле.
Wire format — это конкретное бинарное представление сообщения Protobuf при передаче по сети или записи на диск. Оно определяет, как типы данных, номера полей и значения упаковываются в последовательность байтов.



Структура поля в wire format


Каждое поле кодируется как:
[tag][value]


Тег состоит из двух компонентов, упакованных в varint:
field number (номер поля, 3 бита wire type + оставшиеся биты на номер)
wire type (тип кодирования значения, 3 бита)
Wire types определены спецификацией:
0 — Varint (целые числа, булевы, enum)
1 — 64-bit (fixed64, sfixed64, double)
2 — Length-delimited (string, bytes, вложенные сообщения, packed repeated)
3 — Start group (устаревший, не используется в proto3)
4 — End group (устаревший)
5 — 32-bit (fixed32, sfixed32, float)

Varint: переменная длина целых чисел
Varint (variable-length integer) — это способ кодирования целых чисел в виде последовательности байтов переменной длины. Каждый байт varint содержит 7 бит данных и 1 бит-флаг продолжения (most significant bit). Если флаг установлен, следует ещё один байт.

Значение 1:
Бинарное: 00000001
Varint: 00000001 (1 байт)

Значение 150:
Бинарное: 10010110
Varint: 10010110 00000001 (2 байта)
Разбор: младшие 7 бит первого байта = 1001010 (22), старший бит = 1 (продолжение)
второй байт = 0000001 (1), итого: 1 * 128 + 22 = 150

Varint позволяет кодировать малые числа компактно: числа от 0 до 127 занимают 1 байт. Это главная причина, по которой рекомендуется использовать теги 1–15 для частых полей — теговый байт тоже кодируется как varint, и малые номера полей занимают 1 байт.

ZigZag: кодирование отрицательных чисел
Стандартный varint плохо подходит для отрицательных чисел в знаковых типах (sint32, sint64), так как в дополнительном коде (two's complement) отрицательные числа имеют установленные старшие биты и кодируются максимальной длиной (5 байт для sint32, 10 байт для sint64). Для решения этой проблемы Protobuf использует ZigZag encoding.
ZigZag encoding — это схема отображения целых чисел со знаком на целые без знака, при которой малые по модулю числа (положительные и отрицательные) отображаются на малые положительные числа. Формула: (n << 1) ^ (n >> 31) для 32-битных чисел.

Исходное значение -> Закодированное
0 -> 0
-1 -> 1
1 -> 2
-2 -> 3
2 -> 4

Таким образом, -1 кодируется как 1 и занимает 1 байт вместо 5. Для полей, которые могут содержать отрицательные значения, в .proto следует использовать sint32 или sint64 вместо int32/int64.

Length-delimited: строки и вложенные сообщения
Для типов с переменной длиной (string, bytes, вложенные message) используется wire type 2.

Формат:
[tag][length][data]

Где length — varint, указывающий количество байт в data. Это позволяет парсеру пропустить неизвестные поля (unknown fields) или поля с неправильным типом, не читая их содержимое байт за байтом.

Packed repeated fields
В proto3 скалярные числовые repeated-поля кодируются как packed по умолчанию. Это означает, что вместо отдельного тега для каждого элемента массива весь массив кодируется как один length-delimited блок:
[tag][total_length][value1][value2][value3]...

Это значительно экономит пространство по сравнению с unpacked-форматом, где каждый элемент имел бы свой тег.

Компиляция: от .proto к Java

Компилятор protoc (Protocol Buffers Compiler) трансформирует .proto файлы в исходный код на целевом языке.

Для Java процесс выглядит так:
# Установка компилятора (например, через Maven plugin или скачивание бинарника)
protoc --java_out=./src/main/java library.proto


Флаг --java_out указывает директорию для сгенерированных Java-файлов. Результат компиляции сообщения Book из примера выше:
// Сгенерированный класс Book.java
package com.example.library.proto;

public final class Book extends GeneratedMessageV3 implements BookOrBuilder {

// Приватные поля — immutable объект
private volatile Object title_;
private volatile Object author_;
private int year_;
private double price_;
private boolean available_;
// Repeated поле — хранится как ProtocolStringList (оптимизированная реализация List<String>)
private LazyStringList tags_;
private Publisher publisher_;

// Приватный конструктор — объекты создаются через Builder
private Book() {
title_ = "";
author_ = "";
tags_ = LazyStringArrayList.EMPTY;
}

// Геттеры
public String getTitle() { ... }
public String getAuthor() { ... }
public int getYear() { ... }
public List<String> getTagsList() { ... }
public Publisher getPublisher() { ... }

// Сериализация в OutputStream
public void writeTo(CodedOutputStream output) throws IOException {
// Кодирование каждого поля в wire format
if (!getTitleBytes().isEmpty()) {
GeneratedMessageV3.writeString(output, 1, title_);
}
if (!getAuthorBytes().isEmpty()) {
GeneratedMessageV3.writeString(output, 2, author_);
}
if (year_ != 0) {
output.writeInt32(3, year_);
}
// ... и так далее для каждого поля
}

// Десериализация из InputStream
public static Book parseFrom(InputStream input) throws IOException {
return parseFrom(input, DEFAULT_INSTANCE);
}

// Вложенный класс Builder — реализация паттерна Builder
public static final class Builder extends GeneratedMessageV3.Builder<Builder> {
// Мутабельная копия полей для построения объекта
public Builder setTitle(String value) { ... }
public Builder setAuthor(String value) { ... }
public Builder setYear(int value) { ... }
public Builder addTags(String value) { ... }
public Book build() { ... } // создаёт immutable Book
}

// Singleton-экземпляр DEFAULT_INSTANCE для пустого сообщения
private static final Book DEFAULT_INSTANCE;
static {
DEFAULT_INSTANCE = new Book();
}
}


Ключевые особенности сгенерированного кода:
Immutability (неизменяемость): после создания через build() объект Book не может быть изменен. Все поля private final (или private volatile для строк), сеттеров нет. Изменение требует создания нового объекта через toBuilder().
Builder pattern: создание объекта идёт через вложенный класс Builder, что позволяет конструировать объект пошагово и гарантирует валидность на момент build().
LazyStringList: оптимизированная реализация List<String> для repeated string-полей. Хранит строки как ByteString или byte[] до первого обращения как String, что экономит перекодирование UTF-8.
CodedOutputStream / CodedInputStream: низкоуровневые потоки для записи и чтения wire format. Работают напрямую с byte[], минуя промежуточные текстовые представления.
Immutability (неизменяемость) — это свойство объекта, при котором его состояние не может быть изменено после создания. Неизменяемые объекты потокобезопасны по определению, так как их нельзя изменить из любого потока. В Protobuf immutability гарантирует, что сериализованное сообщение не изменится во время передачи.

Builder pattern (паттерн строитель) — это порождающий паттерн проектирования, который позволяет создавать сложные объекты пошагово. В Protobuf Builder изолирует мутабельное состояние на этапе конструирования, а финальный объект остаётся immutable.


#Java #для_новичков #beginner #IO #NIO #Serialize #Protobuf
👍4
Практический пример: сериализация и десериализация

import com.example.library.proto.Book;
import com.example.library.proto.Book.Publisher;
import com.google.protobuf.ByteString;
import java.io.FileOutputStream;
import java.io.FileInputStream;

public class ProtobufExample {

public void createAndSerialize() throws Exception {
// Создание объекта через Builder
Book book = Book.newBuilder()
.setTitle("Clean Code")
.setAuthor("Robert C. Martin")
.setYear(2008)
.setPrice(42.50)
.setAvailable(true)
.addTags("programming")
.addTags("software engineering")
.setPublisher(
Publisher.newBuilder()
.setName("Prentice Hall")
.setCountry("USA")
.build()
)
.build();

// Сериализация в байтовый массив
byte[] bytes = book.toByteArray();
System.out.println("Serialized size: " + bytes.length + " bytes");
// Для сравнения: JSON-представление этого же объекта заняло бы ~250-300 байт

// Запись в файл
try (FileOutputStream fos = new FileOutputStream("book.pb")) {
book.writeTo(fos);
}

// Десериализация из файла
try (FileInputStream fis = new FileInputStream("book.pb")) {
Book restored = Book.parseFrom(fis);
System.out.println("Restored: " + restored.getTitle() + " by " + restored.getAuthor());
}

// Десериализация из байтового массива
Book fromBytes = Book.parseFrom(bytes);
}
}

Метод toByteArray() сериализует сообщение в компактный byte[]. Метод parseFrom() выполняет обратную операцию. Обратите внимание: parseFrom() не выбрасывает checked-исключений при невалидном формате — вместо этого выбрасывается InvalidProtocolBufferException (unchecked, наследник IOException в старых версиях, но в proto3 runtime это RuntimeException).

Версионирование и эволюция схемы

Одно из ключевых преимуществ Protobuf — встроенная поддержка backward и forward compatibility через правила изменения схемы.
Backward compatibility (обратная совместимость) — это свойство системы, при котором новая версия может корректно обрабатывать данные, созданные старой версией. Forward compatibility (прямая совместимость) — это свойство, при котором старая версия может корректно обрабатывать данные, созданные новой версией.


Правила безопасного изменения схемы


Добавление полей: можно добавлять новые поля с новыми тегами. Старый код проигнорирует неизвестные теги (wire parser пропускает их по length-delimiter или varint-размеру). Новый код получит default value для отсутствующих в старом сообщении полей.
Удаление полей: поле можно удалить, но его тег нельзя повторно использовать (чтобы избежать коллизий со старыми сообщениями, где это поле ещё может присутствовать). Рекомендуется помечать удалённые поля как reserved.
Изменение типа: нельзя менять wire type поля (например, int32 на string), так как это сломает бинарный парсинг. Но можно менять тип в пределах совместимых wire type: int32 на int64 (wire type 0), string на bytes (wire type 2).
Изменение имени: имя поля можно менять свободно, так как в wire format хранится только тег, а не имя.
Default values: в proto3 поля всегда имеют zero-value по умолчанию (0 для чисел, пустая строка, false, первое значение enum). Это означает, что невозможно отличить "поле не было установлено" от "поле было установлено в значение по умолчанию". Для явного контроля наличия поля в proto3 используется обёртка google.protobuf.BoolValueInt32Value и т.д. (well-known types).
message BookV2 {
string title = 1;
string author = 2;
int32 year = 3;

// Новое поле — старый код проигнорирует тег 8
string isbn = 8;

// Зарезервированные теги и имена — нельзя использовать повторно
reserved 4, 5, 6;
reserved "price", "available";
}



Преимущества Protobuf


Компактность
Бинарное представление Protobuf значительно меньше JSON. Для сообщения Book из примера:
JSON с отступами: ~280 байт.
JSON minified: ~200 байт.
Protobuf binary: ~55-65 байт (в зависимости от длины строк).
Экономия достигается за счёт:
Отсутствия имён полей в бинарном потоке (только числовые теги).
Varint-кодирования малых целых чисел.
Packed repeated-полей.
Отсутствия запятых, скобок, кавычек.
Для высоконагруженных систем экономия 70-80% трафика критична. В микросервисной архитектуре, где сервисы обмениваются через сеть, снижение размера сообщений прямо пропорционально снижению задержек (latency) и стоимости сетевой инфраструктуры.
Latency — это задержка между отправкой запроса и получением ответа. В распределённых системах latency складывается из времени сериализации, передачи по сети, десериализации и обработки. Компактные форматы снижают время передачи и десериализации.


Скорость

Protobuf парсится быстрее JSON по нескольким причинам:
Отсутствие текстового разбора: не нужно искать кавычки, запятые, скобки, обрабатывать escape-последовательности. Парсер читает байты последовательно, используя заранее известную структуру.
Нет рефлексии при десериализации: сгенерированный код содержит жёстко заданные инструкции вида "тег 1 — строка, записать в поле title". В Jackson для JSON требуется рефлексия или runtime-генерация bytecode.
Zero-copy для строкByteString и LazyStringList позволяют избежать копирования строк при передаче между слоями приложения.
Предсказуемость аллокаций: размер сообщения известен до сериализации (вызов getSerializedSize()), что позволяет выделить точный byte[] без переаллокаций.
В бенчмарках (JMH — Java Microbenchmark Harness) сериализация/десериализация Protobuf в Java обычно в 3–10 раз быстрее Jackson JSON для типичных сообщений, и в 20+ раз быстрее для сложных вложенных структур.
JMH (Java Microbenchmark Harness) — это фреймворк от OpenJDK для написания корректных микробенчмарков Java-кода. Он решает проблемы JIT-оптимизаций, warmup-фазы и статистической значимости результатов.


Строгая типизация

.proto файл является контрактом. Компилятор protoc гарантирует, что сгенерированный код соответствует схеме. Невозможно случайно записать строку в числовое поле — это будет ошибкой компиляции, а не runtime-ошибкой парсинга. Это снижает количество ошибок интеграции между сервисами.

Кроссплатформенность и межъязыковая совместимость
Один .proto файл компилируется в C++, Java, Python, Go, C#, JavaScript, Ruby, Objective-C, PHP, Dart, Kotlin и другие языки. Это означает, что бэкенд на Java, мобильное приложение на Kotlin и фронтенд на JavaScript могут использовать одну и ту же схему данных, гарантируя совместимость на уровне wire format.


#Java #для_новичков #beginner #IO #NIO #Serialize #Protobuf
👍4
Интеграция с gRPC
gRPC — это фреймворк удалённого вызова процедур (RPC — Remote Procedure Call), разработанный Google и построенный поверх HTTP/2 с Protobuf как форматом сериализации сообщений.

gRPC использует .proto файлы для определения не только сообщений, но и сервисов с методами:
service LibraryService {
rpc GetBook(GetBookRequest) returns (Book);
rpc ListBooks(ListBooksRequest) returns (stream Book);
rpc CreateBooks(stream Book) returns (CreateBooksResponse);
}

RPC (Remote Procedure Call) — это парадигма межпроцессного взаимодействия, при которой вызов удалённой функции выглядит как вызов локальной. gRPC генерирует клиентский stub и серверный skeleton из .proto файла, скрывая детали сетевого взаимодействия.


Stub — это сгенерированный клиентский код, который предоставляет интерфейс, идентичный серверному сервису, но реализующий сетевое взаимодействие под капотом. Skeleton — серверная заглушка, принимающая сетевые запросы и делегирующая их реальной реализации.


Недостатки Protobuf


Нечитаемость для человека
Бинарный wire format не поддаётся чтению без специальных инструментов. Для отладки требуется protoc --decode или специализированные декодеры. Это усложняет отладку сетевых проблем: нельзя просто посмотреть перехваченный TCP-пакет в текстовом виде, как с JSON.

Требование схемы и кодогенерации
Каждое изменение структуры данных требует:
Изменения .proto файла.
Перекомпиляции всех зависимых проектов.
Редеплоя артефактов.
Это создаёт friction в agile-разработке, где структуры данных часто меняются на ранних этапах. JSON позволяет добавить новое поле в ответ API, не трогая клиентский код. В Protobuf это тоже возможно (благодаря forward compatibility), но требует дисциплины: новое поле должно получить новый тег, а клиент должен быть перекомпилирован, если он хочет работать с новым полем типобезопасно.

Кривая обучения
Разработчику нужно освоить:
Синтаксис .proto и семантику proto3.
Правила версионирования и reserved fields.
Различия между scalar types и их wire-типами (int32 vs sint32 vs fixed32).
Особенности generated code (Builder pattern, immutability, default values).
Интеграцию protoc в build pipeline (Maven, Gradle, Bazel).

Ограниченные типы данных
Protobuf не поддерживает напрямую:
Большие целые числа без знака больше 64 бит (нет nativе BigInteger).
Даты и время (есть well-known type Timestamp, но это message, а не примитив).
Полиморфизм (есть oneof и Any, но они более ограничены, чем наследование в ООП).
Графы с циклическими ссылками (Protobuf предназначен для деревьев, не для произвольных графов).


Сравнение Protobuf и JSON


По скорости
Protobuf значительно быстрее при сериализации и десериализации.

Jackson JSON требует:
Парсинга текстовой строки посимвольно.
Построения промежуточного дерева (JsonNode) или рефлексии для маппинга на POJO.
Обработки escape-последовательностей и Unicode.
Динамического поиска полей по имени.
Protobuf использует:
Последовательное чтение байтов с известной структурой.
Прямую запись в поля объекта без рефлексии (сгенерированный код).
Простые битовые операции для varint и zigzag.
Предсказуемость аллокаций: размер сообщения известен до сериализации (вызов getSerializedSize()), что позволяет выделить точный byte[] без переаллокаций.
В типичных микросервисных нагрузках разница составляет 3–10x в пользу Protobuf. При этом стоит учитывать, что в современных JVM с JIT-компиляцией Jackson может достигать высокой производительности после warmup-фазы, но Protobuf остаётся предсказуемо быстрее из-за отсутствия текстового парсинга.
JIT (Just-In-Time compilation) — это компиляция байткода Java в нативный машинный код во время выполнения. HotSpot JVM компилирует часто выполняемые методы в оптимизированный машинный код, что значительно ускоряет их выполнение после периода "разогрева" (warmup).


По размеру

Protobuf обычно в 2–5 раз компактнее minified JSON и в 5–10 раз компактнее pretty-printed JSON. Ключевые факторы:
В JSON имя каждого поля повторяется в каждом сообщении. В Protobuf имя заменено на 1–2 байта тега.
Числа в JSON — ASCII-текст. 12345 занимает 5 байт. В Protobuf 12345 как varint занимает 2 байта.
Булевы значения в JSON: true — 4 байта. В Protobuf: 1 байт (тег + значение).
JSON требует запятых, скобок, кавычек. Protobuf не имеет разделителей между полями.

По строгости
Protobuf требует схему на этапе компиляции.

Это:
Плюс: ошибки типов ловятся на этапе компиляции, а не в runtime.
Плюс: контракт между сервисами формализован и версионируется.
Минус: меньшая гибкость для ad-hoc структур и прототипирования.
JSON не требует схемы. Это:
Плюс: быстрое прототипирование и гибкость.
Минус: runtime-ошибки при несовпадении типов или отсутствии полей.
Минус: неявный контракт, который легко нарушить.

По отладке и observability
JSON превосходит Protobuf в читаемости. Логи, перехваченные HTTP-запросы, сообщения в Kafka можно сразу прочитать. Protobuf требует инструментов: protoc --decode, gRPC reflection, специализированные декодеры в Wireshark. В современных системах этот недостаток часто компенсируется: gRPC сервисы экспортируют схемы через reflection, а observability-платформы (Jaeger, Zipkin) умеют декодировать Protobuf на лету.
Observability (наблюдаемость) — это свойство системы, позволяющее понимать её внутреннее состояние по внешним выходным данным: метрикам, логам и трассировкам. В распределённых системах observability критична для диагностики проблем.


По интеграции с вебом

JSON нативно поддерживается браузерами и JavaScript.

Protobuf в браузере требует:
Использования protobuf-js для сериализации/десериализации.
Передачи бинарных данных через ArrayBuffer или base64.
gRPC-Web для взаимодействия с gRPC-сервисами (требует прокси, например Envoy).
Поэтому для публичных API, потребляемых браузерными клиентами, JSON остаётся стандартом. Protobuf доминирует во внутреннем межсервисном взаимодействии (backend-to-backend).


#Java #для_новичков #beginner #IO #NIO #Serialize #Protobuf
👍4
Путь байтов в памяти JVM при работе с Protobuf

1. Генерация кода и загрузка классов

.proto файл компилируется protoc в .java файлы, которые затем компилируются javac в .class файлы. При загрузке классов JVM (например, Book.class) класс попадает в Metaspace — область памяти для метаданных классов. Book.classBook.Builder.classBookOrBuilder.class и внутренние классы занимают Metaspace. Эти классы остаются там до выгрузки ClassLoader.
В отличие от JSON, где парсер (Jackson) использует рефлексию для анализа POJO-классов во время выполнения, Protobuf-классы уже содержат весь необходимый код сериализации/десериализации. Это означает, что нет runtime-аллокаций объектов MethodFieldConstructor при каждой операции — всё решено на этапе кодогенерации.

2. Создание сообщения: Builder и аллокации
Book book = Book.newBuilder()
.setTitle("Clean Code")
.setYear(2008)
.build();


При вызове Book.newBuilder():
Создаётся объект Book.Builder в Young Generation (Eden). Builder содержит мутабельные поля, соответствующие всем полям сообщения.
Каждый вызов setTitle() создаёт внутреннее представление строки. В Protobuf строки хранятся как ByteString — обёртка над byte[], содержащая UTF-8 байты. При передаче Java-String происходит кодирование UTF-16 (внутреннее представление Java-строки) в UTF-8. Это создаёт временный byte[] в Eden
ByteString — это immutable обёртка над массивом байтов в Protobuf Java runtime. Она аналогична String, но для сырых байтов, и предоставляет zero-copy операции (например, substring() без копирования массива).

При вызове build() Builder создаёт финальный immutable объект Book. Это новая аллокация в Eden. Builder проверяет валидность (например, required-поля в proto2; в proto3 такой проверки нет) и копирует состояние в Book. После build() объект Builder становится мусором (если на него не осталось ссылок).
Важно: Book — immutable. Все его поля либо примитивы (хранятся в самом объекте), либо ссылки на immutable объекты (ByteString, другие сообщения). Это означает, что Book безопасно передавать между потоками без синхронизации.

3. Сериализация: от объекта к байтам

Вызов book.toByteArray():
Сначала вычисляется размер сериализованного сообщения через getSerializedSize(). Этот метод рекурсивно обходит все поля, суммируя размеры тегов, значений и length-delimiters. Для вложенных сообщений вызывается их getSerializedSize(). Этот проход не создаёт новых объектов, только читает поля и выполняет арифметику на стеке.
Выделяется byte[] точного размера в Young Generation (Eden). Это единственная аллокация для всей сериализации (не считая временных объектов для строк, если они ещё не закодированы).
CodedOutputStream оборачивает byte[] и пишет в него wire format. Каждое поле кодируется напрямую: примитивы через битовые операции, строки через копирование ByteString/byte[] в целевой массив.
Возвращается byte[]. Этот массив — единственный объект, который покидает метод сериализации. Все промежуточные вычисления происходят на стеке или с использованием существующих объектов.
Если byte[] передаётся в сетевой слой (Netty, gRPC), он может быть обёрнут в ByteBuf — абстракцию над байтовым буфером в Netty. ByteBuf может использовать прямую (direct) память вне кучи JVM, что позволяет передать данные в сокет через zero-copy без участия GC.
Direct memory (прямая память, off-heap) — это область нативной памяти вне кучи JVM, выделяемая через ByteBuffer.allocateDirect(). Данные в direct memory не подлежат сборке мусора JVM и могут передаваться напрямую в системные вызовы ОС (например, запись в сокет), минуя копирование из кучи.


4. Десериализация: от байтов к объекту


Вызов Book.parseFrom(byte[] data):
Создаётся CodedInputStream — лёгкий объект, оборачивающий byte[] и отслеживающий позицию чтения. Аллокация в Eden.
parseFrom создаёт Book.Builder (аллокация в Eden).
Парсер читает байты последовательно. Для каждого поля:
Читает тег (varint) — определяет field number и wire type.
По field number находит соответствующее поле в сгенерированном коде (switch по номеру).
Читает значение: для varint — декодирует число; для length-delimited — читает длину, затем byte[], оборачивает в ByteString.
Устанавливает значение в Builder.
После прочтения всех полей вызывается build(), который создаёт immutable Book в Eden.
CodedInputStream и Builder становятся мусором. Если сообщение большое и парсинг длительный, Builder может пережить Minor GC и попасть в Survivor Space.

5. Работа GC с Protobuf-объектами

Protobuf спроектирован с учётом минимизации давления на GC:
Immutable объекты: после создания Book не изменяется. GC не тратит время на отслеживание изменений состояния.
Отсутствие рефлексии: нет постоянного создания объектов FieldMethod, аннотаций. Всё статически скомпилировано.
Повторное использование Builder: в высоконагруженных системах можно использовать пул Builder-ов, чтобы избежать аллокаций на каждое сообщение. Однако стандартный generated code не поддерживает пулинг из коробки — это требует ручной реализации или использования фреймворков вроде grpc-java, который переиспользует буферы.
Object pooling (пулинг объектов) — это паттерн, при котором созданные объекты не уничтожаются, а возвращаются в пул для повторного использования. Это снижает нагрузку на GC, но требует аккуратного управления состоянием объектов.

ByteString и пул строкByteString хранит byte[] напрямую. Если одна и та же строка встречается в тысячах сообщений, каждое сообщение содержит свой ByteString со своим byte[]. В отличие от Java-StringByteString не интернируется автоматически. Для часто повторяющихся строковых значений можно использовать ByteString.copyFromUtf8(string).toStringUtf8() с ручным кэшированием, но это нестандартная практика.
Large messages: если сообщение содержит большое поле bytes (например, изображение 10 МБ), соответствующий byte[] создаётся в куче. Если это repeated поле с множеством больших объектов, они могут быстро заполнить Old Generation. В таких случаях используются потоковые API или разбиение на чанки.

6. Вложенные сообщения и глубина рекурсии

Вложенные сообщения в Protobuf создают дерево объектов в куче. Каждый уровень вложенности — это отдельная аллокация. Для глубоко вложенных сообщений (глубина 10+) это создаёт давление на Eden. CodedInputStream имеет лимит на глубину вложенности (по умолчанию 100), чтобы предотвратить stack overflow и утечки памяти при парсинге злонамеренных сообщений.

7. Сравнение аллокаций: Protobuf vs JSON

Для сообщения Book из примера:
Protobuf сериализация: аллокации = Book.Builder (если ещё не создан) + byte[] результата. Временных объектов минимум.
Jackson JSON сериализация: аллокации = StringWriter или byte[] + промежуточные char[]/byte[] для кодирования + объекты JsonGenerator. При сериализации в String — объект String + внутренний byte[].
Protobuf десериализация: аллокации = CodedInputStream + Book.Builder + Book + ByteString для каждой строки.
Jackson JSON десериализация: аллокации = JsonParser + JsonNode дерево или POJO + String для каждого поля + объекты рефлексии (при первом использовании класса).
Protobuf создаёт в 2–5 раз меньше объектов в куче при сериализации/десериализации, что напрямую снижает частоту Minor GC.


#Java #для_новичков #beginner #IO #NIO #Serialize #Protobuf
👍4
Продвинутые возможности proto3

Well-known types

Proto3 предоставляет стандартные типы в пакете google.protobuf:
Timestamp — точка во времени (секунды + наносекунды с эпохи Unix).
Duration — временной интервал.
Any — контейнер для произвольного сообщения (типа Object в Java).
Empty — пустое сообщение для методов без параметров/результата.
StructValueListValue — динамически типизированные структуры (аналог JSON-объектов).
Wrapper types: Int32Value, StringValue, BoolValue — обёртки для скалярных типов, позволяющие отличать отсутствие поля от значения по умолчанию.
import "google/protobuf/timestamp.proto";

message Event {
string name = 1;
google.protobuf.Timestamp occurred_at = 2;
}


Maps

Proto3 поддерживает нативные ассоциативные массивы:
message Library {
map<string, Book> books_by_isbn = 1;
}


На уровне wire format map кодируется как repeated message, где каждый элемент — message с двумя полями: key и value. В Java маппится на Map<String, Book>.

Oneof

oneof — это конструкция, гарантирующая, что только одно из перечисленных полей может быть установлено в один момент времени. Аналог union в C.
message Result {
oneof payload {
Book book = 1;
string error = 2;
}
}


В Java oneof генерирует enum PayloadCase и методы hasBook(), hasError(), getPayloadCase().


Custom options

Protobuf позволяет определять собственные опции через расширения:
extend google.protobuf.FieldOptions {
string validation_regex = 50001;
}

message User {
string email = 1 [(validation_regex) = "^[a-z]+@[a-z]+\\.[a-z]+$"];
}

Эти опции не влияют на wire format, но доступны через reflection API Protobuf для генерации валидаторов, документации и т.д.


#Java #для_новичков #beginner #IO #NIO #Serialize #Protobuf
👍4
Что выведет код?

public class task100826 {

static class Person100826 {

private String name;
private int age;

public boolean hasName() { return name != null; }
public String getName() { return name == null ? "" : name; }

public int getAge() {
return age;
}
}

public static void main(String[] args) {
Person100826 p = new Person100826();
System.out.println(p.hasName());
System.out.println(p.getName().isEmpty());
System.out.println(p.getAge());
}
}


#Tasks
👍4
👍2
Что такое @Component@Service@Repository@Controller? 🤓

Ответ:

Это стереотипные аннотации Spring, которые помечают классы как бины для автоматического обнаружения при component-scanning. 

@Component — общая аннотация для любого бина. 
@Service — для бизнес-логики (сервисный слой). 
@Repository — для DAO (работа с БД), добавляет поддержку исключений (DataAccessException). 
@Controller — для веб-контроллеров (MVC).

Все они являются мета-аннотациями 
@Component. Использование правильной аннотации улучшает читаемость и позволяет Spring применять специфическую обработку (например, @Repository включает трансляцию исключений).


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
История технологии сегодня — 11 августа

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

Сти́вен Гэ́ри (Стив) Во́зняк (англ. Stephen Gary (Steve) Wozniak; род. 11 августа 1950, Сан-Хосе, США), известный как Воз (англ. Woz) — американский изобретательинженер-электронщик и программист, соучредитель компании Apple Computer (ныне Apple Inc.) вместе со Стивом Джобсом и Рональдом Уэйном в 1976 году. В середине 1970-х в одиночку спроектировал компьютеры Apple I и Apple II, которые начали «микрокомпьютерную революцию» и определили развитие отрасли.

Том Килберн (Tom Kilburn 11 августа 1921 г. – 17 января 2001 г.) — Британский учёный-инженер, один из разработчиков первых электронных ЭВМ (включая Manchester Baby) и соавтор памяти Williams–Kilburn; ключевая фигура ранней вычислительной техники.


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

2023 — запуск автоматической межпланетной станции «Луна-25».


#Biography #Birth_Date #Events #11августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
[Совет по Java #070]

Тема: PriorityQueue не гарантирует порядок при итерации — только при извлечении (poll()).

Проблема: PriorityQueue — это реализация очереди на основе бинарной кучи (heap). Она упорядочивает элементы согласно их естественному порядку или переданному компаратору, но порядок гарантируется только при извлечении элементов через poll()remove() или peek() (который показывает минимальный элемент).

Однако метод iterator() и все операции обхода (например, forEachtoArray()) не следуют порядку приоритета. Итератор проходит по внутреннему массиву кучи в том порядке, в котором элементы физически расположены в памяти, а этот порядок не является отсортированным. Многие разработчики ошибочно полагают, что итерация по PriorityQueue вернёт элементы в порядке возрастания приоритета, и используют её в циклах, не догадываясь, что получают случайный порядок. Это приводит к логическим ошибкам, особенно при выводе содержимого, сериализации или агрегации данных.

Решение: Для получения элементов в порядке приоритета всегда используйте метод poll() в цикле, который удаляет и возвращает наименьший (или наибольший, в зависимости от компаратора) элемент. Если нужно просто просмотреть элементы без удаления, скопируйте очередь в массив и отсортируйте его, либо создайте новую PriorityQueue и последовательно извлекайте элементы.

Для отладки и логирования используйте toArray() и затем сортируйте, либо преобразуйте в список и применяйте Collections.sort(). Никогда не полагайтесь на порядок итератора, так как он специфичен для реализации и может меняться между версиями JDK.
import java.util.*;

public class PriorityQueueOrder {

public static void main(String[] args) {
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.add(5);
pq.add(1);
pq.add(3);
pq.add(2);
pq.add(4);

//Итератор не гарантирует порядок
System.out.print("Итерация (неупорядоченно): ");
for (Integer i : pq) {
System.out.print(i + " "); // Может вывести 1, 2, 3, 4, 5, но это не гарантировано
}
System.out.println();

//poll() выдает элементы в правильном порядке
System.out.print("Извлечение через poll(): ");
while (!pq.isEmpty()) {
System.out.print(pq.poll() + " "); // 1, 2, 3, 4, 5
}
System.out.println();

// Восстанавливаем очередь
pq.addAll(Arrays.asList(5, 1, 3, 2, 4));

//Просмотр без удаления: копия и сортировка
List<Integer> sorted = new ArrayList<>(pq);
Collections.sort(sorted);
System.out.println("Копия + сортировка: " + sorted);

//Альтернатива: извлечение с сохранением (создаем копию)
PriorityQueue<Integer> copy = new PriorityQueue<>(pq);
List<Integer> inOrder = new ArrayList<>();
while (!copy.isEmpty()) {
inOrder.add(copy.poll());
}
System.out.println("Из копии: " + inOrder);
}
}


Объяснение:
 PriorityQueue хранит элементы в массиве, где позиция родителя всегда меньше (или больше) дочерних элементов согласно компаратору.

Это свойство кучи обеспечивает быстрый доступ к минимальному элементу за O(1) и извлечение за O(log n). Однако хранение в виде кучи не подразумевает полной сортировки массива: порядок элементов может быть любым, главное, чтобы выполнялось условие кучи (например, каждый родитель меньше своих детей).

Итератор обходит массив по индексам, следуя физическому расположению, которое не сохраняет глобальный порядок. Поэтому единственный способ получить элементы в порядке приоритета — многократно вызывать poll(), который удаляет корень и восстанавливает свойство кучи. При проектировании API, возвращающего PriorityQueue, обязательно документируйте, что итерация не гарантирует упорядоченность, и предоставляйте методы для извлечения отсортированных данных.


#Java #советы
👍4