Современный Java, объяснённый просто (с примерами)
Многие думают, что Java сложный или многословный язык.
Но в последних версиях (Java 17 → 21 → 25) язык сильно изменился.
4 современных фичи, которые делают жизнь разработчика проще:
1. Records (меньше повторяющегося кода)
Раньше приходилось писать конструкторы, геттеры, toString…
Достаточно одной строки — всё это генерируется автоматически.
2. Sealed classes (контролируемое наследование)
Позволяет ограничить, какие классы могут наследоваться от другого.
Никто больше не сможет реализовать Shape, кроме разрешённых. Безопасность и ясность.
3. Pattern Matching (более мощный switch)
Теперь switch понимает типы, а не только значения.
Чище, чем использовать instanceof и касты повсюду.
4. Virtual Threads (лёгкая конкуренция)
С Java 21 появились виртуальные потоки → можно создавать тысячи потоков без падения системы.
Идеально для приложений с огромным количеством соединений (APIs, микросервисы).
Java больше не тот тяжёлый язык, каким был раньше.
А с выходом Java 25 как LTS он приносит ещё больше улучшений для разработчиков.
👉 Java Portal
Многие думают, что Java сложный или многословный язык.
Но в последних версиях (Java 17 → 21 → 25) язык сильно изменился.
4 современных фичи, которые делают жизнь разработчика проще:
1. Records (меньше повторяющегося кода)
Раньше приходилось писать конструкторы, геттеры, toString…
Достаточно одной строки — всё это генерируется автоматически.
2. Sealed classes (контролируемое наследование)
Позволяет ограничить, какие классы могут наследоваться от другого.
Никто больше не сможет реализовать Shape, кроме разрешённых. Безопасность и ясность.
3. Pattern Matching (более мощный switch)
Теперь switch понимает типы, а не только значения.
Чище, чем использовать instanceof и касты повсюду.
4. Virtual Threads (лёгкая конкуренция)
С Java 21 появились виртуальные потоки → можно создавать тысячи потоков без падения системы.
Идеально для приложений с огромным количеством соединений (APIs, микросервисы).
Java больше не тот тяжёлый язык, каким был раньше.
А с выходом Java 25 как LTS он приносит ещё больше улучшений для разработчиков.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20❤5
В Java на собеседованиях могут спросить про альтернативы
Ниже три мощные альтернативы
Используется для временных кэшей, хранения слушателей, метаданных, привязанных к жизненному циклу объекта.
Используется во фреймворках, парсерах и графах зависимостей, где важна физическая идентичность объекта.
Использовать
Используется всегда, если ключи берутся из одного
Быстрый гайд по выбору:
- Нужно автоочищение кэша →
- Нужна идентичность объектов (
- Ключи из
- Всё остальное →
👉 Java Portal
HashMap
, так как он не всегда самый быстрый или экономичный по памяти и иногда приводит к скрытым проблемам с производительностью, утечкам памяти и сложным багам. Ниже три мощные альтернативы
HashMap
и ситуации, когда стоит их использовать. WeakHashMap
: Самоочищающийся кэш HashMap
часто применяют для кэширования, но он держит сильные ссылки на ключи, мешая GC освободить память даже тогда, когда объект уже больше нигде не используется. Это может привести к утечкам памяти. WeakHashMap
хранит ключи через слабые ссылки. Если на объект-ключ больше нет сильных ссылок, GC может удалить его, и запись в мапе исчезнет автоматически. Используется для временных кэшей, хранения слушателей, метаданных, привязанных к жизненному циклу объекта.
IdentityHashMap
: Когда объекты "равны", но не одинаковы HashMap
проверяет ключи через метод .equals()
. Если у вас два объекта с одинаковыми данными, но это разные экземпляры (например, два Person
с одинаковым именем, но разными записями), то HashMap
перезапишет значение. IdentityHashMap
сравнивает ключи только по ссылке (==), игнорируя .equals()
. Разные объекты всегда будут разными ключами, даже если у них одинаковые данные. Используется во фреймворках, парсерах и графах зависимостей, где важна физическая идентичность объекта.
EnumMap
: Оптимизированный вариант для enum-ключей Использовать
enum
как ключ в HashMap
неэффективно. Нужно считать хэши, обрабатывать коллизии, хотя набор ключей фиксирован на этапе компиляции. EnumMap
специально создан для enum-ключей. Внутри он работает через массив, используя ordinal() значения enum в качестве индекса. Это даёт настоящие O(1)-операции и экономит память. Используется всегда, если ключи берутся из одного
enum
. Быстрый гайд по выбору:
- Нужно автоочищение кэша →
WeakHashMap
- Нужна идентичность объектов (
==
) → IdentityHashMap
- Ключи из
enum
→ EnumMap
- Всё остальное →
HashMap
по умолчаниюPlease open Telegram to view this post
VIEW IN TELEGRAM
👍14
Google увеличил функционал Agent Development Kit для Java, внедрив поддержку LangChain4j. Теперь Java-инженеры способны подключать модели OpenAI, Anthropic, Mistral и прочие, разрабатывая многоагентные решения с более гибким контролем и усовершенствованной логикой.
Подробности: тык
👉 Java Portal
Подробности: тык
Please open Telegram to view this post
VIEW IN TELEGRAM
InfoQ
Google's Agent Development Kit for Java Adds Integration with LangChain4j
The latest release of the Agent Development Kit for Java, version 0.2.0, marks a significant expansion of its capabilities through the integration with the LangChain4j LLM framework, which opens it up to all the large language models supported by the framework.
❤5👍2
Вопрос для собеседования Java/Backend:
Современные приложения могут держать пользователя залогиненным без серверного хранения сессий благодаря JWT
Это компактный и безопасный токен, который сервер подписывает и отдает клиенту. Клиент хранит его и отправляет вместе с запросами, а сервер проверяет подпись и доверяет данным внутри токена без обращения к базе.
JWT состоит из трёх частей — заголовка с алгоритмом и типом, полезной нагрузки с пользовательскими данными (claims) и подписи, которая гарантирует подлинность.
Такой подход делает авторизацию stateless: вся необходимая информация хранится в самом токене.
Чтобы обеспечить безопасность, важно всегда использовать HTTPS, задавать короткий срок жизни токена и предусматривать механизм отзыва украденных токенов.
👉 Java Portal
Как современные приложения оставляют вас залогиненным без хранения сессии на сервере?🫖
Современные приложения могут держать пользователя залогиненным без серверного хранения сессий благодаря JWT
Это компактный и безопасный токен, который сервер подписывает и отдает клиенту. Клиент хранит его и отправляет вместе с запросами, а сервер проверяет подпись и доверяет данным внутри токена без обращения к базе.
JWT состоит из трёх частей — заголовка с алгоритмом и типом, полезной нагрузки с пользовательскими данными (claims) и подписи, которая гарантирует подлинность.
Такой подход делает авторизацию stateless: вся необходимая информация хранится в самом токене.
Чтобы обеспечить безопасность, важно всегда использовать HTTPS, задавать короткий срок жизни токена и предусматривать механизм отзыва украденных токенов.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍5
This media is not supported in your browser
VIEW IN TELEGRAM
Держите репозиторий на GitHub где собрана отличная подборка бесплатных материалов по программированию.
Здесь собраны сотни книг по самым разным направлениям: от веб-разработки и геймдева до AI, блокчейна, создания приложений и даже prompt engineering.😎
👉 Java Portal
Здесь собраны сотни книг по самым разным направлениям: от веб-разработки и геймдева до AI, блокчейна, создания приложений и даже prompt engineering.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤3
Вопрос из Java-собеседования (сценарный):
Ты используешь
Тимлид просит тебя отрефакторить это, так как field injection часто считается плохой практикой.
Подумай о минусах field injection:
→ Visibility: скрывает обязательные зависимости класса.
→ Testability: усложняет unit-тестирование, часто требует рефлексии.
→ Runtime Issues: может привести к NullPointerException, если зависимость отсутствует.
→ Design: поощряет классы с чрезмерной ответственностью (нарушение SRP).
Какой рекомендуемый вариант?
→ Constructor Injection.
Зависимости явно передаются при создании объекта, делая их обязательными.
Почему Constructor Injection лучше?
→ Explicit: явно показывает, что нужно классу для работы.
→ Guaranteed: приложение не поднимется, если зависимости нет.
→ Immutable: final-поля безопаснее и дружелюбнее к многопоточности.
→ Testable: легко замокать и прокинуть зависимости в тестах.
Это приводит к более надежному и поддерживаемому коду.
👉 Java Portal
Ты используешь
@Autowired
для field injection в Spring-проекте. Это просто и работает.@Component
public class UserService {
@Autowired
private UserRepository userRepository;
}
Тимлид просит тебя отрефакторить это, так как field injection часто считается плохой практикой.
Подумай о минусах field injection:
→ Visibility: скрывает обязательные зависимости класса.
→ Testability: усложняет unit-тестирование, часто требует рефлексии.
→ Runtime Issues: может привести к NullPointerException, если зависимость отсутствует.
→ Design: поощряет классы с чрезмерной ответственностью (нарушение SRP).
Какой рекомендуемый вариант?
→ Constructor Injection.
Зависимости явно передаются при создании объекта, делая их обязательными.
@Component
public class UserService {
private final UserRepository userRepo; // final!
public UserService(UserRepository userRepo) {
this.userRepo = userRepo;
}
}
Почему Constructor Injection лучше?
→ Explicit: явно показывает, что нужно классу для работы.
→ Guaranteed: приложение не поднимется, если зависимости нет.
→ Immutable: final-поля безопаснее и дружелюбнее к многопоточности.
→ Testable: легко замокать и прокинуть зависимости в тестах.
Это приводит к более надежному и поддерживаемому коду.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤10👍3💊1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁17❤10
Топ-53 задач на Java для подготовки к собеседованиям
В статье собраны самые популярные задания по Java, полезные курсы по DevOps, Linux и паттернам проектирования, а также список вопросов для подготовки к техническим интервью.
👉 Java Portal
В статье собраны самые популярные задания по Java, полезные курсы по DevOps, Linux и паттернам проектирования, а также список вопросов для подготовки к техническим интервью.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5❤3
Подготовка к собеседованию по Java Microservices
Без понимания ключевых концепций микросервисов сложно успешно пройти собеседование на backend-разработчика. Даже если вы не реализовывали их на практике, базовое знание даст серьёзное преимущество. Сохрани себе этот список как краткий гид или план подготовки.
👉 Java Portal
Без понимания ключевых концепций микросервисов сложно успешно пройти собеседование на backend-разработчика. Даже если вы не реализовывали их на практике, базовое знание даст серьёзное преимущество. Сохрани себе этот список как краткий гид или план подготовки.
Монолит vs Микросервисы → масштабирование отдельных функций независимо
Проектирование микросервиса → изоляция управления профилем пользователя
Паттерн API Gateway → единая точка входа для клиентов
Взаимодействие сервисов (REST vs Messaging) → асинхронная очередь обработки заказов
Паттерн Circuit Breaker → предотвращение каскадных сбоев сервисов
Spring Cloud Load Balancer → распределение трафика между инстансами
Spring Cloud Config → управление внешними конфигурационными параметрами
Service discovery (Eureka/Consul) → автоматический поиск сервисов друг другом
Feign Client vs WebClient → блокирующие и неблокирующие вызовы
Event-driven архитектура и Kafka → обработка потоков данных в реальном времени
Отдельная база для сервиса vs общая база → разделение уровня хранения данных
Паттерн Saga → согласованность распределённых транзакций
Аутентификация на основе JWT и OAuth2 → безопасные stateless API
Безопасность в API Gateway → централизованная аутентификация и авторизация запросов
Observability (логи, трассировка, метрики) → отладка проблем в продакшене
Prometheus и Grafana → мониторинг состояния системы и дашборды
Стратегии деплоя в Kubernetes → авто-масштабирование и самовосстановление приложений
Blue-Green и Canary-деплой → нулевой даунтайм и минимальные риски при релизах
Когда использовать WebFlux → высоконагруженные и низколатентные API
CQRS и Event Sourcing → разделение моделей чтения и записи при сложных сценариях
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Как тестировать Spring Boot приложения в Java?
Статья объясняет, как использовать
👉 Java Portal
Статья объясняет, как использовать
@SpringBootTest
, разницу между юнит- и интеграционными тестами, а также даёт советы по ускорению тестов. Полезно для разработчиков любого уровня, работающих со Spring Boot и микросервисами.Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Многие начинают с Java и используют
Кажется, что это «упрощает код», например при вызове методов, но на самом деле
В Java
- Статическое поле существует в памяти только один раз и шарится между всеми объектами этого класса.
- Статический метод можно вызвать без создания экземпляра.
- Жизненный цикл статических сущностей начинается при загрузке класса в память и заканчивается только при завершении JVM.
Для чего используется?🤔
- Для объявления констант (
- Для утилитарных методов (например,
Где начинаются проблемы?
- Когда используешь
- Когда превращаешь его в «глобальную зависимость», и код становится тяжело тестировать, плюс возникает сильная связность.
👉 Java Portal
static
повсюду. Кажется, что это «упрощает код», например при вызове методов, но на самом деле
static
— это довольно точное понятие, которое стоит хорошо понимать. В Java
static
означает, что что-то принадлежит классу, а не экземпляру. То есть: - Статическое поле существует в памяти только один раз и шарится между всеми объектами этого класса.
- Статический метод можно вызвать без создания экземпляра.
- Жизненный цикл статических сущностей начинается при загрузке класса в память и заканчивается только при завершении JVM.
Для чего используется?
- Для объявления констант (
public static final
), которые никогда не меняются. - Для утилитарных методов (например,
Collections.sort()
), которые не зависят от внутреннего состояния объекта. Где начинаются проблемы?
- Когда используешь
static
для переменных, которые на самом деле должны быть частью состояния объекта. - Когда превращаешь его в «глобальную зависимость», и код становится тяжело тестировать, плюс возникает сильная связность.
static
— это не шорткат. Это способ сказать: «это уникально и шарится по всему приложению».
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍3
Java Streams Cheat Sheet
Пример кода со всеми базовыми приёмами работы со Stream API:
👉 Java Portal
Пример кода со всеми базовыми приёмами работы со Stream API:
преобразование коллекций
flatMap, mapMulti, peek
сортировка, min/max, distinct
проверки (allMatch, anyMatch)
объединение (reduce, joining)
группировка и разбиение (groupingBy, partitioningBy)
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12
CQRS — один из самых популярных вопросов на собеседованиях Java/backend-разработчиков, связанных с взаимодействием микросервисов.
При этом обычно не задают вопрос в формате «Дайте определение CQRS», а формулируют его через реальный сценарий.
Сценарий:
Вопросы:
Определите проблему: Какую ключевую архитектурную проблему этот пример демонстрирует в части работы с данными и почему единая модель данных не справляется?
Предложите решение: Как вы бы переработали этот сервис, чтобы устранить проблемы с производительностью и избыточной сложностью? Назовите архитектурный паттерн и его основной принцип.
Ответ:
CQRS решает эту задачу за счёт разделения моделей и баз данных для записи и чтения.
Запись (заказы): команды обновляют выделенную нормализованную базу для записи (оптимизированную под транзакции).
Чтение (отчёты): события записи асинхронно обновляют отдельную денормализованную базу для чтения (оптимизированную под быстрые запросы и отчётность).
CQRS чаще всего реализуется с использованием брокера сообщений.
👉 Java Portal
При этом обычно не задают вопрос в формате «Дайте определение CQRS», а формулируют его через реальный сценарий.
Сценарий:
Сервис заказов на e-commerce платформе в данный момент обрабатывает все операции (массовое создание и обновление заказов, поиск заказов клиентов, формирование сложных отчётов по продажам) через одну общую реляционную базу данных.
Во время пиковых нагрузок тяжёлые отчётные запросы вызывают серьёзные замедления транзакционных операций, что ухудшает пользовательский опыт. Кроме того, сама модель данных заказов становится чрезмерно сложной, пытаясь одновременно удовлетворить разные потребности.
Вопросы:
Определите проблему: Какую ключевую архитектурную проблему этот пример демонстрирует в части работы с данными и почему единая модель данных не справляется?
Предложите решение: Как вы бы переработали этот сервис, чтобы устранить проблемы с производительностью и избыточной сложностью? Назовите архитектурный паттерн и его основной принцип.
Ответ:
CQRS решает эту задачу за счёт разделения моделей и баз данных для записи и чтения.
Запись (заказы): команды обновляют выделенную нормализованную базу для записи (оптимизированную под транзакции).
Чтение (отчёты): события записи асинхронно обновляют отдельную денормализованную базу для чтения (оптимизированную под быстрые запросы и отчётность).
CQRS чаще всего реализуется с использованием брокера сообщений.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Проект JDBG от roger1337 позволяет подключаться к JVM во время выполнения и исследовать внутреннее состояние Java-программы.
Инструмент использует JNI + JVMTI + DLL-инъекцию, поддерживает просмотр классов, байткода, стека вызовов, локальных переменных и экземпляров объектов.
Создан для исследовательских и образовательных целей, под лицензией Apache 2.0.
https://github.com/roger1337/JDBG
👉 Java Portal
Инструмент использует JNI + JVMTI + DLL-инъекцию, поддерживает просмотр классов, байткода, стека вызовов, локальных переменных и экземпляров объектов.
Создан для исследовательских и образовательных целей, под лицензией Apache 2.0.
https://github.com/roger1337/JDBG
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤3🔥3
В Spring Boot ProductController нужно обработать два разных случая:
1. Вернуть простой 404 Not Found, если продукт не найден.
2. Вернуть 201 Created с динамическим заголовком Location при успешном создании.
Какие механизмы Spring вы бы использовали для реализации каждого из этих требований и почему?
Два основных способа управлять HTTP-ответом, отправляемым клиенту:
→
- Можно навесить на исключение или метод контроллера.
- Всегда возвращает один и тот же HTTP-статус.
- Подход "fire-and-forget": быстро и лаконично в случаях, когда ответ всегда одинаковый.
- Лучше всего подходит для простой обработки ошибок. Например, ResourceNotFoundException, аннотированный
- Нельзя добавить кастомные заголовки или динамическое тело ответа.
→
- Даёт полный программный контроль над формированием HTTP-ответа во время выполнения.
- Можно выставить статус, добавить заголовки и собрать тело ответа так, как требуется по логике.
- Лучше всего подходит для сложных ответов. Например, когда нужно добавить заголовок Location после создания ресурса (201 Created) или вернуть детализированный JSON-объект с информацией об ошибке.
- Это основной инструмент, когда ответ должен зависеть от ситуации.
Комбинация подходов:
Используя
👉 Java Portal
1. Вернуть простой 404 Not Found, если продукт не найден.
2. Вернуть 201 Created с динамическим заголовком Location при успешном создании.
Какие механизмы Spring вы бы использовали для реализации каждого из этих требований и почему?
Два основных способа управлять HTTP-ответом, отправляемым клиенту:
→
@ResponseStatus
: простой статический вариант- Можно навесить на исключение или метод контроллера.
- Всегда возвращает один и тот же HTTP-статус.
- Подход "fire-and-forget": быстро и лаконично в случаях, когда ответ всегда одинаковый.
- Лучше всего подходит для простой обработки ошибок. Например, ResourceNotFoundException, аннотированный
@ResponseStatus(HttpStatus.NOT_FOUND)
, всегда будет возвращать 404.- Нельзя добавить кастомные заголовки или динамическое тело ответа.
→
ResponseEntity
: кастомный инструмент - Даёт полный программный контроль над формированием HTTP-ответа во время выполнения.
- Можно выставить статус, добавить заголовки и собрать тело ответа так, как требуется по логике.
- Лучше всего подходит для сложных ответов. Например, когда нужно добавить заголовок Location после создания ресурса (201 Created) или вернуть детализированный JSON-объект с информацией об ошибке.
- Это основной инструмент, когда ответ должен зависеть от ситуации.
Комбинация подходов:
Используя
@RestControllerAdvice
для глобальной обработки исключений, можно применять @ResponseStatus
для типовых ошибок, а ResponseEntity — для более специфичных и динамичных ответов. Такой подход даёт одновременно и эффективность, и гибкость.Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤5
Учись Git прямо в браузере
Теперь можно тренироваться с командами Git, не устанавливая ничего на свой компьютер.
Прямо в браузере запускаешь команды и сразу видишь, что делает каждая из них, идеально для обучения и практики.
Попробовать можно здесь
👉 Java Portal
Теперь можно тренироваться с командами Git, не устанавливая ничего на свой компьютер.
Прямо в браузере запускаешь команды и сразу видишь, что делает каждая из них, идеально для обучения и практики.
Попробовать можно здесь
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍6
Генерация тестовых данных
Чтобы написать хороший тест, нужны хорошие тестовые данные, приближенные к production. Плохо подготовленные данные = плохо написанный тест.
Поэтому практически все тесты должны состоять из трех основных частей:
- given (подготовка данных и стабов для mock/spy)
- when (вызов тестируемого API)
- then (проверка результата)
Сложно написать хороший тест, полагаясь на данные, которые уже существуют в базе в момент запуска теста (за исключением справочных данных или тех, что были накатаны на production с помощью миграционных фреймворков вроде liquibase и flyway). Обычно на эти данные полагаются другие тесты, а потому часто меняются, что ломает наши тесты или делает их даже flaky.
Поэтому каждый тест должен в идеале готовить данные только для себя, на которых он планирует проверить API:
А чтобы не испортить состояние базы во время проверки, то:
- открываем транзакцию ПЕРЕД выполнением теста (
- накатываем данные, вызываем API и проверяем результат (
- откатываем транзакцию в конце (
👉 Java Portal
Чтобы написать хороший тест, нужны хорошие тестовые данные, приближенные к production. Плохо подготовленные данные = плохо написанный тест.
Поэтому практически все тесты должны состоять из трех основных частей:
- given (подготовка данных и стабов для mock/spy)
- when (вызов тестируемого API)
- then (проверка результата)
Сложно написать хороший тест, полагаясь на данные, которые уже существуют в базе в момент запуска теста (за исключением справочных данных или тех, что были накатаны на production с помощью миграционных фреймворков вроде liquibase и flyway). Обычно на эти данные полагаются другие тесты, а потому часто меняются, что ломает наши тесты или делает их даже flaky.
Поэтому каждый тест должен в идеале готовить данные только для себя, на которых он планирует проверить API:
@Test
void findAll() {
// given
// Все компактно, содержит только необходимую информацию для программиста
User user1 = userDao.save(getUser("test1@gmail.com"));
User user2 = userDao.save(getUser("test2@gmail.com"));
User user3 = userDao.save(getUser("test3@gmail.com"));
// when
List<User> actualResult = userDao.findAll();
// then
// Легко получить доступ к id объектов, т.к. накатывание данных было в самом тесте
assertThat(actualResult).hasSize(3);
List<Integer> userIds = actualResult.stream()
.map(User::getId)
.toList();
assertThat(userIds).contains(user1.getId(), user2.getId(), user3.getId());
}
А чтобы не испортить состояние базы во время проверки, то:
- открываем транзакцию ПЕРЕД выполнением теста (
@BeforeEach
)- накатываем данные, вызываем API и проверяем результат (
@Test
)- откатываем транзакцию в конце (
@AfterEach
)Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍2
JEP 511 в Java добавляет возможность краткого импорта всех пакетов, экспортируемых модулем. Это облегчает повторное использование модульных библиотек без необходимости помещать импортирующий код в модуль.
Подробнее: https://openjdk.org/jeps/511
👉 Java Portal
Подробнее: https://openjdk.org/jeps/511
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3