Please open Telegram to view this post
VIEW IN TELEGRAM
😁22💯7❤🔥1🔥1
Представь, что есть цикл на 10 000 элементов, и баг воспроизводится только на одном конкретном объекте. Без Conditional Breakpoints придется жать F8 вручную сотни раз. А с ними дебаггер сам остановится в нужный момент.
🔹 Как включить
Кликни правой кнопкой на кружок брейкпоинта → появится поле Condition. Введите любое булево Java-выражение. Всё, дебаггер будет останавливаться только когда оно true.
🔹 Примеры из реальной жизни
▪️ Фильтрация по ID
user.getId() == 42
Останавливаемся только на конкретном пользователе — удобно при обработке списка сущностей из БД.
▪️ Фильтрация по содержимому строки
request.getUrl().contains("/admin")Отлавливаем только определённые HTTP-запросы в фильтре или интерцепторе.
▪️ Ловим NPE до того, как он случился
order.getItems() == null
Останавливаемся именно тогда, когда данные уже сломаны, а не после падения.
▪️ Условие по индексу в цикле
i == 999
Прыгаем сразу к последней итерации, не прокручивая весь цикл.
🔹 Продвинутые трюки
— Log message вместо остановки. Если не хотите прерывать выполнение, а просто логировать — в том же окне брейкпоинта включите "Evaluate and log" и введите выражение.
— Pass count. Чуть ниже в настройках брейкпоинта есть поле "Pass count" — брейкпоинт сработает только на N-м попадании.
— Disable until hit. Можно настроить цепочку: один брейкпоинт активирует другой. В настройках есть "Disable until breakpoint is hit" — указываете другой брейкпоинт, и текущий начнёт работать только после срабатывания того.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14❤3🔥1👏1
Forwarded from Библиотека задач по Java | тесты, код, задания
Какие принципы нарушены в коде?
Anonymous Quiz
9%
DRY и S из SOLID
12%
O и I из SOLID
50%
D и S из SOLID
9%
KISS и S из SOLID
21%
Посмотреть ответ
👍7
Please open Telegram to view this post
VIEW IN TELEGRAM
😁24😢5🌚3
🧵 StampedLock: когда ReentrantReadWriteLock уже не справляется
Если знаком с ReentrantReadWriteLock, то знаешь идею: много читателей одновременно, но запись эксклюзивна. Звучит разумно, но у этой модели есть фундаментальная проблема: читатели блокируют писателей.
Поток, который хочет писать, ждёт пока все читатели закончат. При высокой read-нагрузке писатель может ждать очень долго. StampedLock решает именно это.
🔵 Три режима, не два
ReentrantReadWriteLock даёт два режима — read и write. StampedLock добавляет третий — optimistic read.
Это знакомо. Но вот где начинается интересное:
tryOptimisticRead() не захватывает никакого лока, а просто возвращает штамп. validate() проверяет — была ли запись с момента получения штампа. Если нет, то данные консистентны, идём дальше, если да, то фолбэк на обычный read lock.
🔵 Что такое stamp
Это long, который кодирует состояние лока. Каждая успешная запись инвалидирует все оптимистичные штампы. Поэтому validate() — это просто битовая проверка, без CAS, без синхронизации, так что она очень дешёвая.
🔵 Где это реально даёт профит
Сценарий: данные читаются в 95% случаев, пишутся редко. Классический пример — кеш, конфигурация, счётчики с инкрементом.
С ReentrantReadWriteLock все читатели всё равно захватывают shared lock — это операция на AQS, есть накладные расходы. С StampedLock + optimistic read при отсутствии конкурентных записей блокировки нет вообще.
🔵 Подводные камни
— StampedLock не реентерабельный. Если поток захватил write lock и попытается захватить его снова — дедлок. Это принципиальное отличие от ReentrantReadWriteLock.
— Нет поддержки Condition. Если тебе нужен await/signal — StampedLock не подойдёт.
— Нет поддержки прерывания в обычных методах readLock()/writeLock(). Есть отдельные readLockInterruptibly() — но это уже осознанный выбор.
StampedLock — инструмент для конкретного профиля нагрузки: много чтений, редкие записи, нет реентерабельности. Не замена всем локам подряд. Но в правильном месте даёт ощутимый прирост без усложнения архитектуры.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
Если знаком с ReentrantReadWriteLock, то знаешь идею: много читателей одновременно, но запись эксклюзивна. Звучит разумно, но у этой модели есть фундаментальная проблема: читатели блокируют писателей.
Поток, который хочет писать, ждёт пока все читатели закончат. При высокой read-нагрузке писатель может ждать очень долго. StampedLock решает именно это.
ReentrantReadWriteLock даёт два режима — read и write. StampedLock добавляет третий — optimistic read.
StampedLock lock = new StampedLock();
// обычный read lock
long stamp = lock.readLock();
try {
// читаем
} finally {
lock.unlockRead(stamp);
}
// write lock
long stamp = lock.writeLock();
try {
// пишем
} finally {
lock.unlockWrite(stamp);
}
Это знакомо. Но вот где начинается интересное:
long stamp = lock.tryOptimisticRead();
// читаем данные без блокировки вообще
int value = this.value;
if (!lock.validate(stamp)) {
// кто-то писал пока мы читали — перечитываем под реальным локом
stamp = lock.readLock();
try {
value = this.value;
} finally {
lock.unlockRead(stamp);
}
}
tryOptimisticRead() не захватывает никакого лока, а просто возвращает штамп. validate() проверяет — была ли запись с момента получения штампа. Если нет, то данные консистентны, идём дальше, если да, то фолбэк на обычный read lock.
Это long, который кодирует состояние лока. Каждая успешная запись инвалидирует все оптимистичные штампы. Поэтому validate() — это просто битовая проверка, без CAS, без синхронизации, так что она очень дешёвая.
Сценарий: данные читаются в 95% случаев, пишутся редко. Классический пример — кеш, конфигурация, счётчики с инкрементом.
С ReentrantReadWriteLock все читатели всё равно захватывают shared lock — это операция на AQS, есть накладные расходы. С StampedLock + optimistic read при отсутствии конкурентных записей блокировки нет вообще.
— StampedLock не реентерабельный. Если поток захватил write lock и попытается захватить его снова — дедлок. Это принципиальное отличие от ReentrantReadWriteLock.
— Нет поддержки Condition. Если тебе нужен await/signal — StampedLock не подойдёт.
— Нет поддержки прерывания в обычных методах readLock()/writeLock(). Есть отдельные readLockInterruptibly() — но это уже осознанный выбор.
StampedLock — инструмент для конкретного профиля нагрузки: много чтений, редкие записи, нет реентерабельности. Не замена всем локам подряд. Но в правильном месте даёт ощутимый прирост без усложнения архитектуры.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥5👏1
😁 Развернем холиварчик
К статье на Хабре «Я два месяца платил 300к человеку, который тихо скармливал мои задачи в ChatGPT» уже почти 900 комментов.
Прочитайте, давайте тоже обсудим💬
🐸 Библиотека джависта
#DevLife
К статье на Хабре «Я два месяца платил 300к человеку, который тихо скармливал мои задачи в ChatGPT» уже почти 900 комментов.
Прочитайте, давайте тоже обсудим
🐸 Библиотека джависта
#DevLife
Please open Telegram to view this post
VIEW IN TELEGRAM
😁8👍1🔥1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁17👍3❤1
🔨 Паттерн Builder
Builder — порождающий паттерн, который разделяет конструирование сложного объекта и его представление. Позволяет создавать объекты пошагово и получать разные результаты, используя одинаковый процесс построения.
Использование
🔹 Когда конструктор принимает много параметров — особенно если часть из них опциональна.
🔹 Когда порядок шагов построения важен или требует валидации перед созданием.
🔹 Когда нужно создавать разные представления одного и того же объекта.
Преимущества
1️⃣ Читаемость и явное намерение
Конструктор с 7 параметрами — это загадка. Builder с именованными шагами — спецификация. Читая вызов, вы сразу понимаете, что создаётся и почему.
2️⃣ Безопасная валидация
Вся проверка параметров сосредоточена в методе build(). Объект либо создаётся корректным, либо не создаётся вообще. Нет промежуточных невалидных состояний.
3️⃣ Иммутабельность
Builder накапливает параметры, build() создаёт финальный неизменяемый объект. Это удобно в многопоточном коде и делает объекты предсказуемыми.
4️⃣ Поддержка опциональных параметров без перегрузок
Вместо пяти перегруженных конструкторов — один Builder. Указываете только то, что нужно, остальное берёт дефолт.
⚠️ Lombok даёт @Builder за одну аннотацию — но понимать механику всё равно стоит.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
Builder — порождающий паттерн, который разделяет конструирование сложного объекта и его представление. Позволяет создавать объекты пошагово и получать разные результаты, используя одинаковый процесс построения.
Использование
🔹 Когда конструктор принимает много параметров — особенно если часть из них опциональна.
🔹 Когда порядок шагов построения важен или требует валидации перед созданием.
🔹 Когда нужно создавать разные представления одного и того же объекта.
Преимущества
Конструктор с 7 параметрами — это загадка. Builder с именованными шагами — спецификация. Читая вызов, вы сразу понимаете, что создаётся и почему.
Вся проверка параметров сосредоточена в методе build(). Объект либо создаётся корректным, либо не создаётся вообще. Нет промежуточных невалидных состояний.
Builder накапливает параметры, build() создаёт финальный неизменяемый объект. Это удобно в многопоточном коде и делает объекты предсказуемыми.
Вместо пяти перегруженных конструкторов — один Builder. Указываете только то, что нужно, остальное берёт дефолт.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9👍3❤2🤔1
Java Developer - офис (Санкт-Петербург)
Middle (Middle+) Backend Developer - офис (Санкт-Петербург)
Middle/Senior Java Developer - офис (Москва)
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱2❤1
Forwarded from Библиотека собеса по Java | вопросы с собеседований
— Statement используется для
— PreparedStatement
Поэтому в реальных проектах почти всегда используют PreparedStatement.
#core
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤3🔥1
♻️ Redis-кеш с AI
@Cacheable над методом поставить несложно. Сложнее объяснить тимлиду почему прод лежит, когда Redis недоступен — а CacheErrorHandler никто не написал.
Промпт, который закрывает этот пробел сразу:
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#Enterprise
@Cacheable над методом поставить несложно. Сложнее объяснить тимлиду почему прод лежит, когда Redis недоступен — а CacheErrorHandler никто не написал.
Промпт, который закрывает этот пробел сразу:
Ты Senior Java-разработчик. Сгенерируй модуль кеширования для Spring Boot 3.x с Redis.
Требования:
- RedisCacheConfiguration с GenericJackson2JsonRedisSerializer
- CacheManager с раздельными TTL для разных кешей (RedisCacheManagerBuilder)
- 2 сервиса с @Cacheable, @CachePut, @CacheEvict — с комментарием когда что применять
- Кастомный CacheErrorHandler (деградация без исключения при недоступном Redis)
- application.yml конфиг
- Тест: @SpringBootTest + Testcontainers Redis
Стек: Java 21, Spring Boot 3.2, Spring Data Redis, Testcontainers 1.19
@EnableCaching — только в отдельном @Configuration, не в Application-классе.
Верни код классов, yml, тест.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤3😁3🔥1
😱 Если ваш продукт не умеет отдавать данные в формате, понятном AI-агенту, то вас просто не существует
Скрипт не будет кликать по красивым кнопкам в браузере, он уйдёт к конкуренту с нормальным API. Перестроить архитектуру под машинных клиентов — это уже не хайп, а необходимое условие сохранения конкурентоспособности.
Как адаптировать продукт и не исчезнуть из выдачи:
— интегрировать
— научиться контролировать стоимость (лимиты, кэш, роутинг между моделями);
— настроить AgentOps: трейсинг, логирование и отлов регрессий.
Всё это ждёт вас на обновлённом курсе «Разработка AI-агентов». Мы специально сделали фокус на утилитарном инжиниринге и production-ready решениях.
Кстати, до 29 марта можно забрать курс с большой скидкой, и стоит поторопиться — мест на потоке всё меньше.
Зафиксировать цену и начать деплоить агентов без слива бюджета 👈
Скрипт не будет кликать по красивым кнопкам в браузере, он уйдёт к конкуренту с нормальным API. Перестроить архитектуру под машинных клиентов — это уже не хайп, а необходимое условие сохранения конкурентоспособности.
Как адаптировать продукт и не исчезнуть из выдачи:
— интегрировать
MCP и A2A-взаимодействие, чтобы агенты могли вас читать;— научиться контролировать стоимость (лимиты, кэш, роутинг между моделями);
— настроить AgentOps: трейсинг, логирование и отлов регрессий.
Всё это ждёт вас на обновлённом курсе «Разработка AI-агентов». Мы специально сделали фокус на утилитарном инжиниринге и production-ready решениях.
Кстати, до 29 марта можно забрать курс с большой скидкой, и стоит поторопиться — мест на потоке всё меньше.
Зафиксировать цену и начать деплоить агентов без слива бюджета 👈
🥱2
Please open Telegram to view this post
VIEW IN TELEGRAM
😢19💯8❤2😁1
Открывается через Run → Evaluate Expression или Alt + F8 (Option + F8 на macOS).
🔹 Что это вообще такое
Небольшое окно с полем ввода, в котором можно написать любое Java-выражение и мгновенно получить результат. Код выполняется в контексте текущего фрейма — видны все локальные переменные, this, поля класса.
🔹 Примеры из реальной жизни
▪️ Вызов метода на живом объекте
userService.findById(42L)
Не нужно писать тест — просто вызываете метод и смотрите, что он реально вернёт с текущими данными в БД.
▪️ Проверка сложного условия
order.getItems().stream()
.anyMatch(i -> i.getPrice().compareTo(BigDecimal.ZERO) < 0)
Подозреваете, что в заказе есть товары с отрицательной ценой? Проверяете прямо сейчас, не добавляя логов.
▪️ Изменение переменной на лету
user.setRole(Role.ADMIN)
Хотите проверить, как поведёт себя код с другим значением — меняете стейт прямо в памяти и продолжаете выполнение. Приложение не перезапускается.
▪️ Десериализация или парсинг
objectMapper.writeValueAsString(response)
Получаете красивый JSON из объекта прямо в дебаггере — удобно проверить, что именно уйдёт клиенту.
🔹 Продвинутые трюки
— В окне Evaluate есть переключатель с однострочного режима на Code Fragment — там можно писать многострочный код с переменными, условиями и циклами.
— Результат вычисления отображается как обычная переменная в дереве дебаггера. Можно раскрыть, посмотреть вложенные поля, скопировать значение.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11❤4👏1
Forwarded from Библиотека собеса по Java | вопросы с собеседований
Memory leak, который живёт неделями и не воспроизводится локально 👇
📦 Задание — code review
Написали фильтр для аудита запросов. В продакшне через несколько дней — OutOfMemoryError.
@Component
public class AuditFilter implements Filter {
private static final ThreadLocal<AuditContext> CONTEXT =
new ThreadLocal<>();
@Override
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain
) throws IOException, ServletException {
AuditContext ctx = new AuditContext(
((HttpServletRequest) request).getRequestURI(),
System.currentTimeMillis()
);
CONTEXT.set(ctx);
try {
chain.doFilter(request, response);
} finally {
auditLog(CONTEXT.get());
}
}
public static AuditContext current() {
return CONTEXT.get();
}
private void auditLog(AuditContext ctx) {
// пишем в БД...
}
}
▪️ Объясни
— Почему объекты в ThreadLocal не собираются GC, даже если запрос завершён.
— Какая одна строчка кода здесь отсутствует, и где именно она должна быть.
* Есть ли риски при использовании ThreadLocal в virtual threads (Project Loom)?
Ставьте → 🔥, если нравится формат. Если нет → 🌚
#practise
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12👍2❤1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁20💯2😢1👾1
🧵 GC: как выбрать сборщик мусора и не пожалеть
Выбирал ли ты GC хоть раз осознанно? Часто запустил приложение — работает, и ладно. Но когда начинаются проблемы с латентностью или throughput, первый вопрос от SRE: «А какой у вас GC?».
🔹 Разберём что выбрать и почему.
Все GC балансируют между двумя вещами:
▪️ Throughput — сколько полезной работы делает приложение за единицу времени
▪️ Latency — насколько долго приложение паузится на GC
Идеального нет. Выбор всегда зависит от профиля нагрузки.
🔹 Serial и Parallel — если латентность не важна
Serial GC однопоточный. И Minor, и Major GC выполняет один поток, всё приложение стоит. Звучит как антиквариат, но на маленьком heap (< 256MB) и однопоточной среде накладные расходы на координацию потоков не нужны, Serial реально быстрее.
Parallel GC — то же самое, но сборку делают несколько потоков одновременно. STW никуда не девается, просто сама пауза короче за счёт параллелизма. На Major GC всё равно можешь получить сотни миллисекунд.
Где уместно: batch-обработка, утилиты, CLI-инструменты. Там где важен максимальный throughput и никто не ждёт response time.
🔹 G1 — дефолт с Java 9
G1 делит heap на регионы фиксированного размера (~1-32MB) и собирает их инкрементально. Не нужно собирать весь heap за раз — выбираются регионы с наибольшим количеством мусора (отсюда "Garbage First").
Главная настройка:
Это не гарантия, это цель. G1 будет подстраивать размер собираемых регионов, чтобы уложиться.
Где уместно: большинство серверных приложений с heap от 4GB. Хороший баланс throughput/latency без тюнинга.
🔹 ZGC и Shenandoah — когда паузы недопустимы
Оба делают большую часть работы конкурентно — параллельно с работой приложения. STW-паузы измеряются единицами миллисекунд вне зависимости от размера heap.
Где уместно: real-time системы, trading, API с жёсткими SLA по p99 латентности. Платишь немного throughput — получаешь предсказуемые паузы.
🔹 Как выбирать на практике
Не угадывать, а мерить. Включаешь GC логи и смотришь что происходит:
Дальше либо GCEasy, либо руками смотришь на паузы и частоту сборок.
🔹 Три вопроса которые определяют выбор
1. Какой размер heap?
До 4GB — G1 справится. Больше 16GB — смотри на ZGC, у G1 начинаются долгие Mixed GC.
2. Какие требования к латентности?
Есть SLA на p99 < 50ms — только ZGC или Shenandoah. Нет жёстких требований — G1.
3. Какой профиль аллокаций?
Много short-lived объектов — генерационный GC справится хорошо. Много long-lived крупных объектов — G1 может давать длинные паузы на evacuation, ZGC справится лучше.
══════ Навигация ══════
Вакансии • Задачи • Собесы
🐸 Библиотека джависта
#CoreJava
Выбирал ли ты GC хоть раз осознанно? Часто запустил приложение — работает, и ладно. Но когда начинаются проблемы с латентностью или throughput, первый вопрос от SRE: «А какой у вас GC?».
🔹 Разберём что выбрать и почему.
Все GC балансируют между двумя вещами:
▪️ Throughput — сколько полезной работы делает приложение за единицу времени
▪️ Latency — насколько долго приложение паузится на GC
Идеального нет. Выбор всегда зависит от профиля нагрузки.
🔹 Serial и Parallel — если латентность не важна
-XX:+UseSerialGC / -XX:+UseParallelGC
Serial GC однопоточный. И Minor, и Major GC выполняет один поток, всё приложение стоит. Звучит как антиквариат, но на маленьком heap (< 256MB) и однопоточной среде накладные расходы на координацию потоков не нужны, Serial реально быстрее.
Parallel GC — то же самое, но сборку делают несколько потоков одновременно. STW никуда не девается, просто сама пауза короче за счёт параллелизма. На Major GC всё равно можешь получить сотни миллисекунд.
Где уместно: batch-обработка, утилиты, CLI-инструменты. Там где важен максимальный throughput и никто не ждёт response time.
🔹 G1 — дефолт с Java 9
-XX:+UseG1GC
G1 делит heap на регионы фиксированного размера (~1-32MB) и собирает их инкрементально. Не нужно собирать весь heap за раз — выбираются регионы с наибольшим количеством мусора (отсюда "Garbage First").
Главная настройка:
bash-XX:MaxGCPauseMillis=200 # целевое время паузы
Это не гарантия, это цель. G1 будет подстраивать размер собираемых регионов, чтобы уложиться.
Где уместно: большинство серверных приложений с heap от 4GB. Хороший баланс throughput/latency без тюнинга.
🔹 ZGC и Shenandoah — когда паузы недопустимы
-XX:+UseZGC / -XX:+UseShenandoahGC
Оба делают большую часть работы конкурентно — параллельно с работой приложения. STW-паузы измеряются единицами миллисекунд вне зависимости от размера heap.
Где уместно: real-time системы, trading, API с жёсткими SLA по p99 латентности. Платишь немного throughput — получаешь предсказуемые паузы.
🔹 Как выбирать на практике
Не угадывать, а мерить. Включаешь GC логи и смотришь что происходит:
bash-Xlog:gc*:file=gc.log:time,uptime:filecount=5,filesize=20m
Дальше либо GCEasy, либо руками смотришь на паузы и частоту сборок.
🔹 Три вопроса которые определяют выбор
1. Какой размер heap?
До 4GB — G1 справится. Больше 16GB — смотри на ZGC, у G1 начинаются долгие Mixed GC.
2. Какие требования к латентности?
Есть SLA на p99 < 50ms — только ZGC или Shenandoah. Нет жёстких требований — G1.
3. Какой профиль аллокаций?
Много short-lived объектов — генерационный GC справится хорошо. Много long-lived крупных объектов — G1 может давать длинные паузы на evacuation, ZGC справится лучше.
══════ Навигация ══════
Вакансии • Задачи • Собесы
#CoreJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤3🔥1
Вышла Java 25, которую все хотят попробовать. Но ставить ли её или взять проверенную Java 21 LTS?
В этом гайде — пошаговая установка Java на Windows с картинками, разбор различий между версиями, настройка JAVA_HOME и PATH.
Ориентирован для начинающих разработчиков, изучающих Java
══════ Навигация ══════
Вакансии • Задачи • Собесы
#Enterprise
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1👍1
Please open Telegram to view this post
VIEW IN TELEGRAM
😁28💯2🔥1