Ребят кому не сложно, накиньте пару лайков под статьей - https://habr.com/ru/articles/1065138/
Если вам конечно понравилось))) А то как то сиротливо смотрится))))))))))
Если вам конечно понравилось))) А то как то сиротливо смотрится))))))))))
Хабр
"__TypeId__": как один Kafka-заголовок незаметно связывает микросервисы именами Java-классов
Всем привет! Пока ищу работу, продолжаю знакомить Вас с внутренностями и неочевидными моментами работы распределенной микросервисной архитектуры в мире Java Spring. Сегодня на очереди Apache Kafka,...
🔥3 1
Java for Beginner
Ребят кому не сложно, накиньте пару лайков под статьей - https://habr.com/ru/articles/1065138/ Если вам конечно понравилось))) А то как то сиротливо смотрится))))))))))
Честно говоря я не пойму почему статья не зашла... Реально больная тема. Реально не все знают пути решения... Хм......
История технологии сегодня — 03 августа
ℹ️ Кто родился в этот день
Коити Танака, иногда Коичи Танака (яп. 田中 耕一 Танака Ко:ити, род. 3 августа 1959, Тояма, Япония) — японский инженер и химик, лауреат Нобелевской премии по химии 2002 года за разработку нового масс-спектрометрического метода исследования биологических макромолекул. Он единственный Нобелевский лауреат без научной степени.
🌐 Знаковые события
1929 — в Ростове-на-Дону стала работать первая в СССР автоматическая телефонная станция (АТС) на 6000 номеров, построенная при содействии шведской фирмы «Эрикссон».
2004 — запущена автоматическая межпланетная станция (АМС) MESSENGER для исследования Меркурия.
#Biography #Birth_Date #Events #03августа
Коити Танака, иногда Коичи Танака (яп. 田中 耕一 Танака Ко:ити, род. 3 августа 1959, Тояма, Япония) — японский инженер и химик, лауреат Нобелевской премии по химии 2002 года за разработку нового масс-спектрометрического метода исследования биологических макромолекул. Он единственный Нобелевский лауреат без научной степени.
1929 — в Ростове-на-Дону стала работать первая в СССР автоматическая телефонная станция (АТС) на 6000 номеров, построенная при содействии шведской фирмы «Эрикссон».
2004 — запущена автоматическая межпланетная станция (АМС) MESSENGER для исследования Меркурия.
#Biography #Birth_Date #Events #03августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
[Совет по Java #067]
Тема:
Проблема: Многие разработчики ошибочно полагают, что
На самом деле этот метод оборачивает переданный список в прокси-объект, который перехватывает все методы, изменяющие коллекцию (
Однако сам исходный список остается доступным через оригинальную ссылку, и любые его модификации немедленно отражаются в неизменяемом view. Это нарушает инкапсуляцию и может привести к неожиданному поведению: клиент, получивший неизменяемый список, ожидает, что его содержимое будет постоянным, но оно может измениться из-за внешних изменений. Особенно опасно в многопоточных сценариях, когда исходный список модифицируется конкурентно.
Этот паттерн часто называют "неизменяемая обертка" (unmodifiable wrapper), а не "иммутабельная коллекция" (immutable collection), в отличие от
Решение: Если вы хотите защитить данные от изменений, возвращая неизменяемый список, убедитесь, что исходный список больше не доступен для модификации в вашем коде.
Либо передавайте только view клиентам и храните исходный список только внутри класса, с возможностью его изменения только через внутренние методы. Для полной изоляции создавайте копию исходного списка перед оборачиванием:
Однако такая копия защищает только от изменений через оригинальную ссылку, но сама копия все еще изменяема, если сохранить ссылку на нее. Лучшее решение — использовать
Объяснение:
Это часто используется в API для предоставления доступа "только для чтения" к внутреннему состоянию. Однако для гарантии неизменности данных нужно либо сделать исходный список недоступным для модификации (например, через
#Java #советы
Тема:
Collections.unmodifiableList возвращает view на исходный список.Проблема: Многие разработчики ошибочно полагают, что
Collections.unmodifiableList(list) создает независимую неизменяемую копию исходного списка. На самом деле этот метод оборачивает переданный список в прокси-объект, который перехватывает все методы, изменяющие коллекцию (
add, remove, set и др.), и выбрасывает UnsupportedOperationException. Однако сам исходный список остается доступным через оригинальную ссылку, и любые его модификации немедленно отражаются в неизменяемом view. Это нарушает инкапсуляцию и может привести к неожиданному поведению: клиент, получивший неизменяемый список, ожидает, что его содержимое будет постоянным, но оно может измениться из-за внешних изменений. Особенно опасно в многопоточных сценариях, когда исходный список модифицируется конкурентно.
Этот паттерн часто называют "неизменяемая обертка" (unmodifiable wrapper), а не "иммутабельная коллекция" (immutable collection), в отличие от
List.of() или Collections.emptyList(), которые действительно неизменяемы.Решение: Если вы хотите защитить данные от изменений, возвращая неизменяемый список, убедитесь, что исходный список больше не доступен для модификации в вашем коде.
Либо передавайте только view клиентам и храните исходный список только внутри класса, с возможностью его изменения только через внутренние методы. Для полной изоляции создавайте копию исходного списка перед оборачиванием:
Collections.unmodifiableList(new ArrayList<>(list)). Однако такая копия защищает только от изменений через оригинальную ссылку, но сама копия все еще изменяема, если сохранить ссылку на нее. Лучшее решение — использовать
List.copyOf() (Java 10+) или List.of() (Java 9+), которые создают действительно неизменяемые списки, не зависящие от оригинала. Если вы используете unmodifiableList, явно документируйте, что view отражает изменения исходного списка, и что клиент не должен рассчитывать на неизменность содержимого без внешних гарантий.public class UnmodifiableView {
public static void main(String[] args) {
List<String> original = new ArrayList<>(Arrays.asList("A", "B", "C"));
List<String> unmodifiable = Collections.unmodifiableList(original);
System.out.println("Original: " + original); // [A, B, C]
System.out.println("Unmodifiable: " + unmodifiable); // [A, B, C]
// Изменяем исходный список
original.add("D");
System.out.println("После изменения оригинала:");
System.out.println("Original: " + original); // [A, B, C, D]
System.out.println("Unmodifiable: " + unmodifiable); // [A, B, C, D] — изменился!
// Попытка изменить view вызовет исключение
try {
unmodifiable.add("E"); // UnsupportedOperationException
} catch (UnsupportedOperationException e) {
System.err.println("Нельзя изменить view");
}
//Решение 1: копия + обертка (все равно оригинал может быть изменен, если доступен)
List<String> copyAndWrap = Collections.unmodifiableList(new ArrayList<>(original));
original.add("F");
System.out.println("Copy+wrap не изменился: " + copyAndWrap); // [A, B, C, D] — не изменился
//Решение 2: List.copyOf (Java 10+) — действительно неизменяемый
List<String> immutable = List.copyOf(original);
original.add("G");
System.out.println("List.copyOf: " + immutable); // [A, B, C, D, F] — не изменился
//Решение 3: List.of (Java 9+) — для фиксированного набора значений
List<String> fixed = List.of("X", "Y", "Z");
// fixed не зависит от внешних списков
}
}Объяснение:
Collections.unmodifiableList использует паттерн декоратор. Возвращаемый объект — внутренний класс UnmodifiableList, который делегирует все методы чтения (get, size, iterator) исходному списку, а все методы записи переопределяет, бросая исключение. Поскольку он хранит ссылку на исходный список, любые изменения в исходном списке видны через view. Это часто используется в API для предоставления доступа "только для чтения" к внутреннему состоянию. Однако для гарантии неизменности данных нужно либо сделать исходный список недоступным для модификации (например, через
private и отсутствие сеттеров), либо использовать действительно неизменяемые коллекции. List.copyOf() и List.of() возвращают экземпляры, которые не содержат ссылок на внешние изменяемые структуры, и их содержимое гарантированно не изменяется. #Java #советы
👍5
Что выведет код?
#Tasks
import java.util.*;
public class Task030826 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3));
List<Integer> unmod = Collections.unmodifiableList(list);
list.add(4);
try {
unmod.add(5);
} catch (UnsupportedOperationException e) {
System.out.print("ex ");
}
System.out.println(unmod.size());
}
}
#Tasks
👍4
👍4
Что такое 🤓
Ответ:
Collectors.teeing() (Java 12) — это составной коллектор, который принимает два коллектора и функцию объединения их результатов.
Позволяет выполнить две независимые операции над одним стримом за один проход.
Пример: Collectors.teeing(Collectors.summingInt(Item::getPrice), Collectors.counting(), (sum, count) -> sum / count) — вычисляет среднюю цену за один проход.
Полезно, когда нужно несколько агрегаций, но стрим нельзя переиспользовать.
#собеседование
Collectors.teeing()? Collectors.teeing() (Java 12) — это составной коллектор, который принимает два коллектора и функцию объединения их результатов.
Позволяет выполнить две независимые операции над одним стримом за один проход.
Пример: Collectors.teeing(Collectors.summingInt(Item::getPrice), Collectors.counting(), (sum, count) -> sum / count) — вычисляет среднюю цену за один проход.
Полезно, когда нужно несколько агрегаций, но стрим нельзя переиспользовать.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологии сегодня — 04 августа
ℹ️ Кто родился в этот день
Джорджо Паризи (итал. Giorgio Parisi; род. 4 августа 1948 года) — итальянский физик-теоретик. Труды в основном посвящены квантовой теории поля, статистической механике и сложным системам. Соавтор уравнения ДГЛАП, уравнений Кардара — Паризи — Жанга. Нобелевская премия по физике (2021) за «открытие того, как беспорядок и флуктуации взаимодействуют в физических системах в масштабах от атомов до планет».
🌐 Знаковые события
1954 — свой первый полёт совершил британский сверхзвуковой самолёт P-1.
2007 — запущен космический аппарат НАСА «Феникс», предназначенный для исследования Марса.
#Biography #Birth_Date #Events #04августа
Джорджо Паризи (итал. Giorgio Parisi; род. 4 августа 1948 года) — итальянский физик-теоретик. Труды в основном посвящены квантовой теории поля, статистической механике и сложным системам. Соавтор уравнения ДГЛАП, уравнений Кардара — Паризи — Жанга. Нобелевская премия по физике (2021) за «открытие того, как беспорядок и флуктуации взаимодействуют в физических системах в масштабах от атомов до планет».
1954 — свой первый полёт совершил британский сверхзвуковой самолёт P-1.
2007 — запущен космический аппарат НАСА «Феникс», предназначенный для исследования Марса.
#Biography #Birth_Date #Events #04августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Раздел 11. Работа с файлами, I/O и сетью (NIO.2)
Глава 3. Сериализация и форматы обмена
JSON — современный стандарт обмена данными
JSON (JavaScript Object Notation) — это текстовый формат сериализации данных, изначально выведенный из синтаксиса литералов объектов языка JavaScript. Несмотря на происхождение, JSON является полностью языконезависимым форматом и определён стандартом RFC 8259 (декабрь 2017), который заменил RFC 7159. Сегодня JSON де-факто является стандартным форматом обмена данными в веб-сервисах, конфигурационных файлах, логах, сообщениях брокеров и хранилищах документов.
Что такое JSON
JSON представляет собой текстовый формат, основанный на двух структурах:
Коллекция пар ключ-значение — в разных языках это реализуется как объект, запись, структура, словарь, хэш-таблица или ассоциативный массив.
Упорядоченный список значений — в большинстве языков это массив, вектор, список или последовательность.
Формат спроектирован так, чтобы быть легко читаемым для человека и легко парсящимся для машины. Это достигается за счёт минималистичного синтаксиса и строгих правил: каждый документ JSON — это либо один объект, либо один массив.
JSON как основа REST API
JSON стал доминирующим форматом представления ресурсов в REST API благодаря нескольким факторам:
Нативная поддержка в JavaScript, который исполняется в браузере клиента.
Простота генерации и парсинга на стороне сервера — любой язык имеет библиотеку для работы с JSON.
Читаемость при отладке — в отличие от бинарных форматов, JSON можно просмотреть в инструментах разработчика браузера или в логах.
Отсутствие необходимости в схеме для базового использования — в отличие от XML, JSON не требует DTD или XSD для валидации.
#Java #для_новичков #beginner #IO #NIO #Serialize #JSON
Глава 3. Сериализация и форматы обмена
JSON — современный стандарт обмена данными
JSON (JavaScript Object Notation) — это текстовый формат сериализации данных, изначально выведенный из синтаксиса литералов объектов языка JavaScript. Несмотря на происхождение, JSON является полностью языконезависимым форматом и определён стандартом RFC 8259 (декабрь 2017), который заменил RFC 7159. Сегодня JSON де-факто является стандартным форматом обмена данными в веб-сервисах, конфигурационных файлах, логах, сообщениях брокеров и хранилищах документов.
Сериализация — это процесс преобразования структуры данных или объекта в формат, который можно сохранить на диск, передать по сети или записать в базу данных, с возможностью последующего восстановления (десериализации) в исходную структуру.
RFC (Request for Comments) — серия документов Интернет-инженерного совета (IETF), описывающих стандарты, протоколы и технологии Интернета. RFC 8259 является официальной спецификацией формата JSON.
Что такое JSON
JSON представляет собой текстовый формат, основанный на двух структурах:
Коллекция пар ключ-значение — в разных языках это реализуется как объект, запись, структура, словарь, хэш-таблица или ассоциативный массив.
Упорядоченный список значений — в большинстве языков это массив, вектор, список или последовательность.
Формат спроектирован так, чтобы быть легко читаемым для человека и легко парсящимся для машины. Это достигается за счёт минималистичного синтаксиса и строгих правил: каждый документ JSON — это либо один объект, либо один массив.
Парсинг — это процесс анализа строки или потока данных в соответствии с правилами формального языка (грамматикой) с целью построения структурированного представления, обычно дерева разбора или абстрактного синтаксического дерева (AST).
JSON как основа REST API
REST (Representational State Transfer) — это архитектурный стиль проектирования распределённых систем, введённый Роем Филдингом в его докторской диссертации 2000 года. REST не является протоколом или стандартом в строгом смысле; это набор ограничений и принципов.
Ключевое ограничение — statelessness (отсутствие состояния): каждый запрос от клиента к серверу должен содержать всю информацию, необходимую для его обработки, и сервер не хранит контекст клиента между запросами.
JSON стал доминирующим форматом представления ресурсов в REST API благодаря нескольким факторам:
Нативная поддержка в JavaScript, который исполняется в браузере клиента.
Простота генерации и парсинга на стороне сервера — любой язык имеет библиотеку для работы с JSON.
Читаемость при отладке — в отличие от бинарных форматов, JSON можно просмотреть в инструментах разработчика браузера или в логах.
Отсутствие необходимости в схеме для базового использования — в отличие от XML, JSON не требует DTD или XSD для валидации.
DTD (Document Type Definition) и XSD (XML Schema Definition) — это механизмы определения структуры и допустимых элементов XML-документа. JSON изначально не имел встроенного механизма схем, хотя позже появились JSON Schema и OpenAPI.
#Java #для_новичков #beginner #IO #NIO #Serialize #JSON
👍3
Структура JSON
Спецификация JSON определяет шесть типов значений:
Объекты
Объект — это неупорядоченный набор пар ключ-значение, заключённый в фигурные скобки. Ключ — это строка, значение — любой допустимый JSON-тип. Пары разделяются запятыми.
В Java объект JSON обычно маппится на
Массивы
Массив — это упорядоченная последовательность значений, заключённая в квадратные скобки. Значения разделяются запятыми. Индексация начинается с нуля.
В Java массив JSON маппится на
Строки
Строка — это последовательность из нуля или более символов Unicode, заключённая в двойные кавычки. JSON поддерживает escape-последовательности:
Строки в JSON кодируются в UTF-8, UTF-16 или UTF-32. На практике UTF-8 доминирует, так как обеспечивает обратную совместимость с ASCII и экономит память для латинских текстов.
Числа
Числа в JSON записываются в десятичной системе и могут быть целыми или с плавающей точкой. Поддерживается экспоненциальная нотация. Нет различия между целыми и вещественными числами на уровне синтаксиса — это одна грамматическая категория.
Спецификация JSON не ограничивает точность или диапазон чисел. Однако на практике числа с плавающей точкой часто интерпретируются как IEEE 754 double-precision (64 бита), что даёт точность около 15–17 значащих цифр. Для финансовых расчётов, где критична точность до копеек, это может привести к ошибкам округления. В таких случаях числа передаются как строки.
Булевы значения
Два литерала:
Null
Литерал
Преимущества JSON
Читаемость
JSON читается без специальных инструментов. Структура вложенности визуально очевидна благодаря отступам. Это снижает порог входа для разработчиков и упрощает отладку. В отличие от бинарных форматов, JSON можно открыть в любом текстовом редакторе или даже в терминале через
Универсальная поддержка
Каждый современный язык программирования имеет библиотеку для работы с JSON. В Java экосистеме существуют Jackson, Gson, JSON-B, JSON-P, org.json и многие другие. В JavaScript JSON — нативный формат. В Python — модуль
Простота
Грамматика JSON минимальна: всего два контейнерных типа и четыре скалярных. Нет пространств имён, нет схем, нет атрибутов, нет комментариев (официально — комментарии не поддерживаются, хотя некоторые парсеры их принимают). Эта простота снижает сложность парсеров и уменьшает вероятность ошибок при сериализации.
Интеграция с веб-стеком
JSON родственен JavaScript, что делает его естественным выбором для веб-приложений. Fetch API, XMLHttpRequest, WebSocket — все эти API работают с JSON напрямую. Браузер предоставляет нативный объект
Недостатки JSON
Размер и текстовая природа
JSON — текстовый формат. Каждое число, булево значение или null записывается символами, а не бинарными данными. Ключи объектов повторяются в каждом документе. Для массовых данных это приводит к значительному overhead.
В этом примере ключи
Отсутствие строгой типизации
JSON не имеет схемы встроенной в сам документ. Поле
Отсутствие поддержки бинарных данных
JSON не имеет встроенного типа для бинарных данных. Для передачи бинарного контента (изображения, PDF, аудио) используется кодирование в Base64, что увеличивает размер данных примерно на 33%. Альтернативы — передача бинарных данных отдельно (multipart/form-data) или использование бинарных форматов.
Отсутствие комментариев
Спецификация JSON явно запрещает комментарии. Это создаёт проблемы для конфигурационных файлов, где комментарии полезны для документирования. Решения: использование JSON5 (расширение JSON с комментариями), YAML или TOML для конфигурации, либо отдельные файлы документации.
Производительность парсинга
Парсинг JSON требует посимвольного разбора строки, построения дерева объектов в памяти и часто — рефлексии для маппинга на Java-объекты. Для высоконагруженных систем это может стать bottleneck. Оптимизации включают потоковый парсинг (Jackson Streaming API), бинарные форматы на основе JSON (BSON, MessagePack) или полный отказ от JSON в пользу protobuf/Avro.
#Java #для_новичков #beginner #IO #NIO #Serialize #JSON
Спецификация JSON определяет шесть типов значений:
Объекты
Объект — это неупорядоченный набор пар ключ-значение, заключённый в фигурные скобки. Ключ — это строка, значение — любой допустимый JSON-тип. Пары разделяются запятыми.
{
"user": {
"id": 42,
"name": "Alice",
"active": true
}
}В Java объект JSON обычно маппится на
Map<String, Object> или на POJO (Plain Old Java Object — простой Java-объект без специальных требований к наследованию или аннотациям). Ключи в объекте JSON уникальны в пределах одного объекта, но спецификация не запрещает дубликаты — поведение при дубликатах зависит от парсера. Большинство парсеров используют последнее встреченное значение.Массивы
Массив — это упорядоченная последовательность значений, заключённая в квадратные скобки. Значения разделяются запятыми. Индексация начинается с нуля.
{
"orders": [
{ "id": 1, "total": 99.99 },
{ "id": 2, "total": 150.00 }
]
}В Java массив JSON маппится на
List<Object>, Object[] или типизированный список List<Order>, если используется библиотека с поддержкой дженериков.Строки
Строка — это последовательность из нуля или более символов Unicode, заключённая в двойные кавычки. JSON поддерживает escape-последовательности:
\n (перевод строки), \t (табуляция), \\ (обратный слеш), \" (кавычка), \uXXXX (символ Unicode в шестнадцатеричном виде).{
"description": "Line 1\nLine 2\tTabbed",
"emoji": "\uD83D\uDE00"
}Строки в JSON кодируются в UTF-8, UTF-16 или UTF-32. На практике UTF-8 доминирует, так как обеспечивает обратную совместимость с ASCII и экономит память для латинских текстов.
UTF-8 (Unicode Transformation Format, 8-bit) — это кодировка переменной длины, которая кодирует символы Unicode от 1 до 4 байтами. Символы ASCII (0–127) занимают 1 байт, что делает UTF-8 эффективной для англоязычных текстов.
Числа
Числа в JSON записываются в десятичной системе и могут быть целыми или с плавающей точкой. Поддерживается экспоненциальная нотация. Нет различия между целыми и вещественными числами на уровне синтаксиса — это одна грамматическая категория.
{
"integer": 42,
"negative": -17,
"float": 3.14159,
"exponential": 6.022e23,
"small": 1e-10
}Спецификация JSON не ограничивает точность или диапазон чисел. Однако на практике числа с плавающей точкой часто интерпретируются как IEEE 754 double-precision (64 бита), что даёт точность около 15–17 значащих цифр. Для финансовых расчётов, где критична точность до копеек, это может привести к ошибкам округления. В таких случаях числа передаются как строки.
IEEE 754 — это стандарт представления чисел с плавающей точкой в компьютерах. Double-precision использует 64 бита: 1 бит знака, 11 бит экспоненты и 52 бита мантиссы. Не все десятичные дроби точно представимы в двоичной системе, отсюда ошибки округления.
Булевы значения
Два литерала:
true и false. В Java маппятся на примитив boolean или объект Boolean.{
"enabled": true,
"debug": false
}Null
Литерал
null представляет отсутствие значения. В Java маппится на null.{
"middleName": null
}Преимущества JSON
Читаемость
JSON читается без специальных инструментов. Структура вложенности визуально очевидна благодаря отступам. Это снижает порог входа для разработчиков и упрощает отладку. В отличие от бинарных форматов, JSON можно открыть в любом текстовом редакторе или даже в терминале через
curl.Универсальная поддержка
Каждый современный язык программирования имеет библиотеку для работы с JSON. В Java экосистеме существуют Jackson, Gson, JSON-B, JSON-P, org.json и многие другие. В JavaScript JSON — нативный формат. В Python — модуль
json в стандартной библиотеке. В Go — пакет encoding/json. Это означает, что сервис на Java может бесшовно обмениваться данными с сервисом на Python, Go или Node.js.Простота
Грамматика JSON минимальна: всего два контейнерных типа и четыре скалярных. Нет пространств имён, нет схем, нет атрибутов, нет комментариев (официально — комментарии не поддерживаются, хотя некоторые парсеры их принимают). Эта простота снижает сложность парсеров и уменьшает вероятность ошибок при сериализации.
Интеграция с веб-стеком
JSON родственен JavaScript, что делает его естественным выбором для веб-приложений. Fetch API, XMLHttpRequest, WebSocket — все эти API работают с JSON напрямую. Браузер предоставляет нативный объект
JSON с методами parse() и stringify().Недостатки JSON
Размер и текстовая природа
JSON — текстовый формат. Каждое число, булево значение или null записывается символами, а не бинарными данными. Ключи объектов повторяются в каждом документе. Для массовых данных это приводит к значительному overhead.
{
"users": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
}В этом примере ключи
"id" и "name" повторяются для каждого элемента. В бинарном формате (например, Protocol Buffers) ключи заменяются числовыми тегами, а строковые значения могут быть закодированы более эффективно. JSON также не поддерживает сжатие на уровне формата — для уменьшения размера применяется внешнее сжатие (gzip, brotli).Protocol Buffers (protobuf) — бинарный формат сериализации, разработанный Google. В отличие от JSON, protobuf требует предварительного определения схемы (proto-файл), но обеспечивает компактное бинарное представление и строгую типизацию.
Отсутствие строгой типизации
JSON не имеет схемы встроенной в сам документ. Поле
"age" может содержать число в одном запросе и строку в другом. Это создаёт риск ошибок при десериализации, если клиент и сервер не согласовали контракт. Для решения этой проблемы используются JSON Schema, OpenAPI/Swagger или кодогенерация по proto-файлам.JSON Schema — это спецификация (draft 2020-12) для описания структуры JSON-документов. Она позволяет определять типы полей, обязательность, диапазоны значений, регулярные выражения для строк и другие ограничения.
Отсутствие поддержки бинарных данных
JSON не имеет встроенного типа для бинарных данных. Для передачи бинарного контента (изображения, PDF, аудио) используется кодирование в Base64, что увеличивает размер данных примерно на 33%. Альтернативы — передача бинарных данных отдельно (multipart/form-data) или использование бинарных форматов.
Base64 — это схема кодирования бинарных данных в текстовый формат с использованием 64 символов ASCII (A–Z, a–z, 0–9, +, /). Каждые 3 байта (24 бита) кодируются 4 символами Base64 (по 6 бит каждый), отсюда overhead в 33%.
Отсутствие комментариев
Спецификация JSON явно запрещает комментарии. Это создаёт проблемы для конфигурационных файлов, где комментарии полезны для документирования. Решения: использование JSON5 (расширение JSON с комментариями), YAML или TOML для конфигурации, либо отдельные файлы документации.
Производительность парсинга
Парсинг JSON требует посимвольного разбора строки, построения дерева объектов в памяти и часто — рефлексии для маппинга на Java-объекты. Для высоконагруженных систем это может стать bottleneck. Оптимизации включают потоковый парсинг (Jackson Streaming API), бинарные форматы на основе JSON (BSON, MessagePack) или полный отказ от JSON в пользу protobuf/Avro.
Bottleneck — это узкое место в системе, которое ограничивает общую производительность. В контексте JSON-парсинга bottleneck часто возникает из-за аллокации объектов в куче и работы GC при обработке больших JSON-документов.
#Java #для_новичков #beginner #IO #NIO #Serialize #JSON
👍3
Путь байтов в памяти JVM при работе с JSON
1. Получение JSON-строки
JSON-данные обычно поступают в JVM одним из трёх способов: как строка из HTTP-ответа, как содержимое файла, считанное через
Если JSON приходит по HTTP, процесс начинается на уровне сетевого стека ОС. Пакеты TCP собираются в сегменты, данные копируются из kernel space (пространство ядра) в user space (пользовательское пространство) в буфер сокета. Servlet-контейнер (Tomcat, Jetty, Netty) или фреймворк (Spring Boot) читает байты из сокета в буфер — обычно это
2. Декодирование байтов в строку
Байты из сети или файла представляют JSON в кодировке UTF-8. JVM декодирует их в объект
В Java 9+ строки хранятся как
3. Парсинг JSON: аллокация объектов в куче
Парсер (Jackson, Gson или стандартный
Jackson создаст следующие объекты в куче:
Один
Один
Два
Четыре
Два
Строковые ключи
Все эти объекты создаются в Young Generation, в области Eden. Для JSON-документа размером 10 КБ количество объектов может достигать сотен. При обработке тысяч запросов в секунду это создаёт огромное давление на Minor GC.
4. Маппинг на POJO: рефлексия и дополнительные аллокации
При десериализации JSON в Java-объекты (POJO) парсер использует рефлексию — механизм Java для интроспекции классов во время выполнения.
Рефлексия требует:
Создания объекта
Вызова
Установки полей через
Jackson оптимизирует это через
5. Работа GC с JSON-объектами
После десериализации JSON-строка и промежуточные структуры парсера (токены, узлы дерева) становятся мусором. Если использовался Jackson в режиме потокового парсинга (Streaming API), дерево не строится целиком — объекты создаются по мере чтения и сразу собираются GC. В режиме древовидного парсинга (Tree Model) всё дерево JSON хранится в памяти до явного освобождения.
Для высоконагруженных систем критично минимизировать аллокации:
В этом примере
6. Сериализация: обратный путь
При сериализации Java-объекта в JSON происходит обратный процесс:
Jackson обходит поля объекта через кэшированные сериализаторы.
Генерирует JSON-текст как
Если вывод идёт в
Если вывод идёт в
При сериализации в HTTP-ответ через Spring Boot используется
7. Ключевые строки и пул строк
Ключи JSON-объектов (
Интернирование строк — это процесс помещения строки в пул строк JVM через метод
8. Бинарные JSON-форматы и память
Для снижения давления на GC и размера данных используются бинарные форматы на основе JSON:
BSON (Binary JSON) — используется в MongoDB. Содержит типовые теги и длины полей, что ускоряет навигацию без полного парсинга.
MessagePack — бинарный формат, совместимый с JSON по структуре, но более компактный.
CBOR (Concise Binary Object Representation) — стандарт RFC 8949, разработанный IETF как бинарная альтернатива JSON.
Эти форматы парсятся быстрее, так как не требуют посимвольного разбора текста, и создают меньше объектов в куче.
#Java #для_новичков #beginner #IO #NIO #Serialize #JSON
1. Получение JSON-строки
JSON-данные обычно поступают в JVM одним из трёх способов: как строка из HTTP-ответа, как содержимое файла, считанное через
Files.readString(), или как сообщение из брокера (Kafka, RabbitMQ).Если JSON приходит по HTTP, процесс начинается на уровне сетевого стека ОС. Пакеты TCP собираются в сегменты, данные копируются из kernel space (пространство ядра) в user space (пользовательское пространство) в буфер сокета. Servlet-контейнер (Tomcat, Jetty, Netty) или фреймворк (Spring Boot) читает байты из сокета в буфер — обычно это
byte[] или ByteBuffer в куче JVM.Kernel space и user space — это два режима работы процессора. Kernel space — привилегированный режим, в котором работает код операционной системы и драйверов. User space — непривилегированный режим, в котором работают обычные приложения, включая JVM. Переход между режимами (context switch) — дорогая операция.
2. Декодирование байтов в строку
Байты из сети или файла представляют JSON в кодировке UTF-8. JVM декодирует их в объект
String — это массив byte[] (начиная с Java 9; ранее char[]) в куче, плюс объект-обёртка String со ссылкой на массив, хэш-кодом и флагами.В Java 9+ строки хранятся как
byte[] с кодировкой LATIN1 (1 байт на символ) или UTF-16 (2 байта на символ), в зависимости от содержимого. Компактные строки (compact strings) экономят память для ASCII-текстов. Для JSON, состоящего преимущественно из ASCII, это означает экономию ~50% по сравнению со старым char[].Compact strings — оптимизация, введённая в Java 9 (JEP 254). Строки, содержащие только символы Latin-1 (коды 0–255), хранятся в массиве
byte[]по одному байту на символ. Если встречается символ вне Latin-1, массив переключается на UTF-16 (2 байта на символ).
3. Парсинг JSON: аллокация объектов в куче
Парсер (Jackson, Gson или стандартный
org.json) читает строку посимвольно и строит дерево объектов. Для JSON-документа:{
"users": [
{ "id": 1, "name": "Alice" },
{ "id": 2, "name": "Bob" }
]
}Jackson создаст следующие объекты в куче:
Один
JsonNode (или LinkedHashMap при десериализации в Map) для корневого объекта.Один
ArrayNode (или ArrayList) для массива "users".Два
ObjectNode (или LinkedHashMap) для объектов пользователей.Четыре
IntNode / Integer для полей "id".Два
TextNode / String для полей "name".Строковые ключи
"users", "id", "name" — если они не интернированы, создаются как отдельные объекты String.Все эти объекты создаются в Young Generation, в области Eden. Для JSON-документа размером 10 КБ количество объектов может достигать сотен. При обработке тысяч запросов в секунду это создаёт огромное давление на Minor GC.
4. Маппинг на POJO: рефлексия и дополнительные аллокации
При десериализации JSON в Java-объекты (POJO) парсер использует рефлексию — механизм Java для интроспекции классов во время выполнения.
Рефлексия требует:
Создания объекта
Constructor через Class.getDeclaredConstructor().Вызова
Constructor.newInstance() — аллокация POJO в куче.Установки полей через
Field.set() или вызова сеттеров.Jackson оптимизирует это через
SerializerCache и DeserializerCache — кэши, хранящие скомпилированные сериализаторы и десериализаторы. После первого использования класса его метаданные кэшируются, и последующие операции не требуют полной рефлексии. Однако первый парсинг класса — дорогая операция, создающая множество временных объектов.5. Работа GC с JSON-объектами
После десериализации JSON-строка и промежуточные структуры парсера (токены, узлы дерева) становятся мусором. Если использовался Jackson в режиме потокового парсинга (Streaming API), дерево не строится целиком — объекты создаются по мере чтения и сразу собираются GC. В режиме древовидного парсинга (Tree Model) всё дерево JSON хранится в памяти до явного освобождения.
Для высоконагруженных систем критично минимизировать аллокации:
// Потоковый парсинг Jackson — минимум аллокаций
public void processLargeJson(InputStream in) throws IOException {
// JsonFactory — лёгкий фабричный объект для создания парсеров
JsonFactory factory = new JsonFactory();
// JsonParser — потоковый парсер, читает JSON без построения дерева
try (JsonParser parser = factory.createParser(in)) {
while (parser.nextToken() != JsonToken.END_OBJECT) {
String fieldName = parser.getCurrentName();
if ("users".equals(fieldName)) {
parser.nextToken(); // переходим к массиву
while (parser.nextToken() == JsonToken.START_OBJECT) {
// Обрабатываем каждый объект пользователя
int id = 0;
String name = null;
while (parser.nextToken() != JsonToken.END_OBJECT) {
String key = parser.getCurrentName();
parser.nextToken();
if ("id".equals(key)) {
id = parser.getIntValue();
} else if ("name".equals(key)) {
name = parser.getValueAsString();
}
}
// Обрабатываем пользователя без создания промежуточных объектов
processUser(id, name);
}
}
}
}
}
В этом примере
JsonParser читает JSON как поток токенов, не создавая дерево объектов. Память используется минимально, и давление на GC снижается на порядки по сравнению с mapper.readValue(json, UserList.class).6. Сериализация: обратный путь
При сериализации Java-объекта в JSON происходит обратный процесс:
Jackson обходит поля объекта через кэшированные сериализаторы.
Генерирует JSON-текст как
char[] или byte[] внутри StringWriter или OutputStream.Если вывод идёт в
OutputStream (HTTP-ответ, файл), байты записываются напрямую без промежуточной строки.Если вывод идёт в
String, создаётся объект String в куче, который затем передаётся дальше.При сериализации в HTTP-ответ через Spring Boot используется
MappingJackson2HttpMessageConverter, который пишет JSON напрямую в OutputStream ответа, минуя создание промежуточной строки. Это экономит аллокации и снижает нагрузку на GC.7. Ключевые строки и пул строк
Ключи JSON-объектов (
"id", "name", "users") — это строки, которые повторяются в каждом документе. Jackson может интернировать часто встречающиеся ключи через JsonFactory.Feature.INTERN_FIELD_NAMES. Интернирование помещает строки в пул строк (String Pool) в Metaspace, делая их доступными для повторного использования между запросами. Это снижает аллокации, но увеличивает потребление Metaspace — пул строк не собирается обычным GC.Интернирование строк — это процесс помещения строки в пул строк JVM через метод
String.intern(). Если строка с таким содержимым уже есть в пуле, возвращается существующий объект; иначе строка добавляется в пул. Интернирование экономит память при множестве одинаковых строк, но может привести к утечке памяти в Metaspace при интернировании уникальных строк.8. Бинарные JSON-форматы и память
Для снижения давления на GC и размера данных используются бинарные форматы на основе JSON:
BSON (Binary JSON) — используется в MongoDB. Содержит типовые теги и длины полей, что ускоряет навигацию без полного парсинга.
MessagePack — бинарный формат, совместимый с JSON по структуре, но более компактный.
CBOR (Concise Binary Object Representation) — стандарт RFC 8949, разработанный IETF как бинарная альтернатива JSON.
Эти форматы парсятся быстрее, так как не требуют посимвольного разбора текста, и создают меньше объектов в куче.
#Java #для_новичков #beginner #IO #NIO #Serialize #JSON
👍4
Что выведет код?
#Tasks
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Date;
public class Task040826 {
static class Event {
public String name;
public Date date;
Event(String name, Date date) {
this.name = name; this.date = date;
}
}
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
Event event = new Event("Party", new Date(0));
System.out.println(mapper.writeValueAsString(event));
}
}
#Tasks
👍3
Что такое 🤓
Ответ:
Predicate.not(Predicate<T> predicate) (Java 11) возвращает предикат, являющийся логическим отрицанием переданного.
Позволяет упростить фильтрацию: stream.filter(Predicate.not(String::isBlank)) вместо stream.filter(s -> !s.isBlank()).
Это делает код более читаемым и функциональным. Работает со ссылками на методы, улучшая выразительность лямбда-выражений.
#собеседование
Predicate.not() в Java 11? Ответ:
Predicate.not(Predicate<T> predicate) (Java 11)
Позволяет упростить фильтрацию: stream.filter(Predicate.not(String::isBlank)) вместо stream.filter(s -> !s.isBlank()).
Это делает код более читаемым и функциональным. Работает со ссылками на методы, улучшая выразительность лямбда-выражений.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История технологии сегодня — 05 августа
ℹ️ Кто родился в этот день
Нил О́лден А́рмстронг (англ. Neil Alden Armstrong; 5 августа 1930, Уопаконета, Огайо, США — 25 августа 2012, Цинциннати, Огайо, США) — американский астронавт НАСА, лётчик-испытатель, космический инженер, профессор университета, военно-морской лётчик США, первый человек, ступивший на Луну 21 июля 1969 года в ходе лунной экспедиции корабля «Аполлон-11».
Нильс Хе́нрик А́бель (норв. Niels Henrik Abel; 5 августа 1802, Финнёй — 6 апреля 1829, Фроланн) — норвежский математик. В теории специальных, особенно эллиптических и абелевых функций, Абель был признанным лидером-основателем наряду с Якоби. Он первый определил эллиптические функции как функции, обратные эллиптическим интегралам, распространил их определения на общий комплексный случай и глубоко исследовал их свойства.
🌐 Знаковые события
1921 — в американском Дейтоне (штат Огайо) успешно испытан первый в мире автомобиль, управляемый по радио.
1973 — стартовала советская космическая миссия «Марс-6».
#Biography #Birth_Date #Events #05августа
Нил О́лден А́рмстронг (англ. Neil Alden Armstrong; 5 августа 1930, Уопаконета, Огайо, США — 25 августа 2012, Цинциннати, Огайо, США) — американский астронавт НАСА, лётчик-испытатель, космический инженер, профессор университета, военно-морской лётчик США, первый человек, ступивший на Луну 21 июля 1969 года в ходе лунной экспедиции корабля «Аполлон-11».
Нильс Хе́нрик А́бель (норв. Niels Henrik Abel; 5 августа 1802, Финнёй — 6 апреля 1829, Фроланн) — норвежский математик. В теории специальных, особенно эллиптических и абелевых функций, Абель был признанным лидером-основателем наряду с Якоби. Он первый определил эллиптические функции как функции, обратные эллиптическим интегралам, распространил их определения на общий комплексный случай и глубоко исследовал их свойства.
1921 — в американском Дейтоне (штат Огайо) успешно испытан первый в мире автомобиль, управляемый по радио.
1973 — стартовала советская космическая миссия «Марс-6».
#Biography #Birth_Date #Events #05августа
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
[Совет по Java #068]
Тема:
Проблема: Фабричные методы
Они категорически запрещают передачу
Это сделано для упрощения контракта и предотвращения неоднозначности, связанной с
Решение: Если ваша бизнес-логика допускает использование
Для обеспечения неизменяемости с поддержкой
Объяснение:
Они не поддерживают
При выборе между
#Java #советы
Тема:
Set.of() и Map.of() не допускают null ключей/значений.Проблема: Фабричные методы
Set.of(), Map.of() и их перегрузки, появившиеся в Java 9, были спроектированы для создания неизменяемых коллекций с фиксированным набором элементов. Они категорически запрещают передачу
null в качестве ключа или значения, выбрасывая NullPointerException как на этапе создания, так и при попытке добавить null в уже существующую коллекцию. Это сделано для упрощения контракта и предотвращения неоднозначности, связанной с
null в неизменяемых структурах. Однако многие разработчики, привыкшие к HashMap и HashSet, которые позволяют хранить null (один null-ключ в Map и один null-элемент в Set), сталкиваются с неожиданными исключениями при переходе на новые API. Особенно это актуально в коде, где null может появляться из внешних источников (база данных, пользовательский ввод, внешние API). Ошибка проявляется на этапе создания коллекции, что может быть неочевидным при использовании Map.ofEntries или при передаче коллекций в методы.Решение: Если ваша бизнес-логика допускает использование
null в качестве ключей или значений, используйте традиционные изменяемые коллекции: HashMap, HashSet, TreeMap и т.д. Для обеспечения неизменяемости с поддержкой
null можно использовать Collections.unmodifiableMap(new HashMap<>(...)), но это не иммутабельная коллекция, а view с проверками во время выполнения. Для безопасной работы с null и неизменяемостью рассмотрите возможность обернуть null в специальный объект-маркер (например, Optional или пользовательский класс), либо использовать Map с типом значения Optional. import java.util.*;
public class NullInCollections {
public static void main(String[] args) {
//Антипаттерн: Set.of() с null
try {
Set<String> set = Set.of("a", null, "b"); // NullPointerException
} catch (NullPointerException e) {
System.err.println("Set.of() не допускает null");
}
//Map.of() с null ключом или значением
try {
Map<String, String> map = Map.of("key", null); // NullPointerException
} catch (NullPointerException e) {
System.err.println("Map.of() не допускает null-значений");
}
//Решение: использовать HashMap для поддержки null
Map<String, String> hashMap = new HashMap<>();
hashMap.put("key1", "value1");
hashMap.put("key2", null); // допустимо
hashMap.put(null, "value3"); // допустим null-ключ
System.out.println("HashMap with nulls: " + hashMap);
//Если нужна неизменяемость с null, используйте unmodifiable обертку
Map<String, String> unmodifiableWithNull = Collections.unmodifiableMap(hashMap);
// unmodifiableWithNull нельзя изменить, но null сохраняются
System.out.println("Unmodifiable with null: " + unmodifiableWithNull);
// Однако это не иммутабельная коллекция — исходный hashMap можно изменить, и view отразит
//Для безопасной работы с неизменяемыми коллекциями и null — избегайте null
// Используйте Optional или значения-заглушки
Map<String, Optional<String>> safeMap = Map.of(
"key1", Optional.of("value"),
"key2", Optional.empty() // представляет null
);
// При чтении: safeMap.get("key2").orElse("default");
//Использование checkedMap для типизированной проверки (не решает проблему null)
Map<String, String> checked = Collections.checkedMap(
new HashMap<>(), String.class, String.class);
checked.put("a", null); // допустимо, проверка типов не касается null
}
}
Объяснение:
Set.of и Map.of реализованы как специализированные внутренние классы, оптимизированные для хранения фиксированного числа элементов. Они не поддерживают
null, потому что это позволяет упростить реализацию (не нужны проверки на null при чтении) и избежать неоднозначности: в неизменяемой коллекции отсутствие элемента и null-значение — разные вещи, но при использовании null они могут смешиваться. HashMap и HashSet были спроектированы с поддержкой null (один null-ключ, неограниченное количество null-значений), и это поведение осталось для обратной совместимости. При выборе между
Map.of и HashMap учитывайте: если null может появиться в данных, используйте HashMap и управляйте неизменяемостью через обертки или явное копирование. В современных API (например, Stream API, Optional) предпочтительно полностью избегать null, заменяя его на Optional или пустые коллекции. #Java #советы
👍4
Что выведет код?
#Tasks
import java.util.Map;
public class Task050826 {
public static void main(String[] args) {
try {
Map<String, String> map = Map.of(
"key1", "value1",
"key2", null
);
System.out.println("size=" + map.size());
} catch (Exception e) {
System.out.println(e.getClass().getSimpleName());
}
}
}
#Tasks
👍3
Варианты ответа:
Anonymous Quiz
67%
size=2
0%
size=1
25%
NullPointerException
8%
IllegalArgumentException
👍3
Что такое 🤓
Ответ:
Optional.isEmpty() (Java 11) — метод, возвращающий true, если Optional пуст (т.е. не содержит значения).
Ранее использовали !optional.isPresent(). Новый метод делает код более читаемым: if (optional.isEmpty()) { ... }. Это симметрично isPresent() и улучшает понимание намерения.
Позволяет писать более естественные условия.
#собеседование
Optional.isEmpty()? Ответ:
Optional.isEmpty() (Java 11)
Ранее использовали !optional.isPresent(). Новый метод делает код более читаемым: if (optional.isEmpty()) { ... }. Это симметрично isPresent() и улучшает понимание намерения.
Позволяет писать более естественные условия.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3