TGViewer
Channel Public Channel
Библиотека джависта | Java, Spring, Maven, Hibernate

Библиотека джависта | Java, Spring, Maven, Hibernate

@javaproglib

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

Учиться у нас: clc.to/AATM8w

Для обратной связи: @proglibrary_feeedback_bot

По рекламе: @tproger_sales_bot

РКН: https://gosuslugi.ru/snet/67a5bbda1b17b35b6c1a55c4
Subscribers
22K
Photos
2.5K
Videos
57
Links
3.7K

Showing posts older than #7622 · Back to latest

Older Posts 20 shown
Post #7621 2.42K
🎤 Ваши знания по ИИ-агентам + наша аудитория в 1 млн человек = профит

Мы в Proglib активно качаем тему ИИ-агентов. Если вы в теме, то у нас есть предложение 👇

Что с нас?

- Огромный охват: пропиарим ваши соцсети и продукты на 1 000 000+ айтишников.
- Личный бренд: станете узнаваемым экспертом в самой горячей нише 2026 года.
- Никакой рутины: наши редакторы сами упакуют ваши мысли в крутые посты.

Что с вас?

Любой экспертный контент по ИИ-агентам: кейсы из прода, шпаргалки, статьи, наработки по стеку (LangGraph, CrewAI, AutoGen и др.) или просто мысли по архитектуре.

👉 Стать экспертом и заявить о себе
Post #7620 2.29K
❓ Как правильно определять границы сервисов в микросервисной архитектуре?

Один из недооценённых скиллов в разработке — это умение провести правильную границу между сервисами. Большинство «распределённых монолитов», которые мы встречаем в продакшене, рождаются именно здесь.

Разобрали тему — держи шпаргалку 👇

🔹 Что такое Service Boundary

Это контракт на три вещи:

— за что сервис отвечает;
— какими данными он владеет;
— как он общается с соседями.

Представь компанию: HR не лезет в финансы, а склад не занимается зарплатами. Так же должны работать твои сервисы.

🔹 4 принципа, которые работают

1. Business Capability First

Режь по бизнес-функциям, а не по техническим слоям. OrderService, PaymentService, UserService, потому что именно так бизнес думает о системе.

2. Single Responsibility

Один сервис — одна ответственность. Если в описании сервиса есть союз и, это уже тревожный звоночек 🚨

3. Data Ownership

У каждого сервиса своя БД. Без исключений. Shared database = shared pain.

4. Loose Coupling

Только API, никакого прямого доступа к чужим таблицам.

🔹 Классический антипаттерн

// ❌ Бизнес-логика смешана в одном сервисе
@Service
public class BadOrderService {
public String processOrderAndPayment(int id) {
String order = orderRepository.findById(id)
.orElse("Order not found");
String paymentStatus = "Payment Successful"; // 🚨 чужая ответственность
return order + " | " + paymentStatus;
}
}


Выглядит безобидно, пока не нужно масштабировать платежи отдельно, сменить платёжного провайдера или добавить retry-логику только для оплаты. Тут и начнутся реальные проблемы.

🔹 Советы из практики

→ Начни с монолита. Не дроби систему заранее. Сначала пойми домен, потом режь по швам.
→ Следи за chatty communication. Если сервис делает 10 вызовов к соседям на каждый запрос, граница явно проведена не там.
→ Изучи DDD. Bounded Context из Domain-Driven Design это лучший инструмент для поиска правильных границ. Инвестиция окупается быстро

💬 Делимся в комментах страшными историями god-сервисов.

══════ Навигация ══════
Вакансии • Задачи • Собесы

🐸 Библиотека джависта

#CoreJava
  • ❤ 6
  • 👍 6
  • 🔥 1
  • 👏 1
Post #7616 2.61K
🦾 Почему ваши AI-продукты на базе LLM ломаются (и как это чинить)?

Выкатили ИИ-фичу в прод, а она галлюцинирует, падает или выдает мусор? Приглашаем на открытый вебинар, где разберем реальную боль внедрения LLM-агентов и научимся делать так, чтобы «всё работало».

🗓️ Когда: 14 мая в 19:00 МСК
⏱️ Формат: 60 минут мяса + 30 минут ответов на ваши вопросы

🧑🏻‍💻 Кто вещает: Эмиль Сатаев — Backend Platform Developer (8+ лет в разработке). Человек, который своими руками внедряет LLM и агентные системы в реальные коммерческие сервисы.

🎁 Главный бонус для онлайна:
Только участникам прямого эфира подарим уникальный промокод на скидку 10.000 ₽ на большой курс AgentOps.

👉 Занять место на вебинаре
  • ❤ 1
Post #7614 2.37K
☕️ Магия jcmd

Запустите jcmd <pid> Thread.print, и вы получите полный thread dump живого JVM-процесса — без kill -3, без рестарта, без агентов.

🔹 Зачем это нужно

— Полный дамп всех потоков с трассировками прямо на живом проде;
— Работает с любым JDK-процессом: Spring Boot, Quarkus, Kafka Streams;
— Один бинарник закрывает heap dump, GC-статистику, профилирование и диагностику;
— Не требует JMX, агентов или открытых портов — только PID.

🔹 Как использовать

— Список всех JVM-процессов и их PID:
jcmd

— Все доступные команды для конкретного процесса:
jcmd <pid> help

— Thread dump (дедлоки, зависшие потоки):
jcmd <pid> Thread.print

— Heap dump на диск:
jcmd <pid> GC.heap_dump /tmp/heap.hprof

— Статистика GC в реальном времени:
jcmd <pid> GC.heap_info

— Запустить GC вручную (осторожно на проде):
jcmd <pid> GC.run

— Статистика классов по памяти:
jcmd <pid> GC.class_histogram


jcmd <pid> GC.class_histogram — первое, что стоит запустить при подозрении на утечку памяти: сразу видно, каких объектов неожиданно много и сколько они весят.

⚠️ Некоторые команды требуют флага -XX:+UnlockDiagnosticVMOptions при запуске JVM — иначе получите Exception: No such command. Если команда недоступна, проверьте jcmd <pid> help — там только то, что реально работает для вашего процесса прямо сейчас.

══════ Навигация ══════
Вакансии • Задачи • Собесы

🐸 Библиотека джависта

#Enterprise
  • 👍 10
  • ❤ 5
  • 🔥 1
Post #7613 2.64K
📦 Java медленно превращается в Haskell

Records, Sealed Classes, Pattern Matching — это уже не просто фичи. Это Data-Oriented Programming: иммутабельные данные отдельно, логика отдельно.

Для одних это долгожданная эволюция. Для других тихое убийство ООП, которому в Java 30 лет.

💬 Используешь DOP в продакшне? И что в целом думаешь об изменениях в языке?

══════ Навигация ══════
Вакансии • Задачи • Собесы

🐸 Библиотека джависта

#DevLife
  • 👍 10
  • 🤔 5
  • 🔥 1
Post #7612 2.48K

Forwarded from Библиотека собеса по Java | вопросы с собеседований

✔️ Java-тест: кэш, который врёт

Метод возвращает устаревшие данные. Иногда и только на нескольких потоках. Воспроизвести локально — нереально 👇

📦 Задание — code review

Команда добавила простой in-memory кэш для тяжёлых вычислений. На одном потоке работает идеально. На проде с нагрузкой — иногда возвращает старый результат или null.

@Component
public class PricingCache {

private final Map<String, BigDecimal> cache = new HashMap<>();
private final PricingEngine pricingEngine;

public PricingCache(PricingEngine pricingEngine) {
this.pricingEngine = pricingEngine;
}

public BigDecimal getPrice(String productId) {
if (cache.containsKey(productId)) {
return cache.get(productId);
}
BigDecimal price = pricingEngine.calculate(productId);
cache.put(productId, price);
return price;
}

public void invalidate(String productId) {
cache.remove(productId);
}

public void invalidateAll() {
cache.clear();
}
}


▪️ Объясни

— В чём проблема в коде
— Как переписать getPrice верно

Ставьте → 🔥, если нравится формат. Если нет → 🌚

💬 Решения под спойлер. Сравним, какое будет лучше.

🐸 Библиотека собеса по Java

#practise
  • 🔥 13
  • 👍 4
  • 🤔 2
Post #7611 2.55K
🕯 TimSort в Java

Arrays.sort(Object[]) и Collections.sort() используют TimSort — алгоритм, разработанный Тимом Петерсом для Python в 2002 году и портированный в Java 7. Для примитивов используется dual-pivot quicksort, но для объектов — только TimSort, и причина этого выбора нетривиальна.

🔹 Почему не quicksort для объектов

Quicksort не стабилен — одинаковые элементы могут поменяться местами. Для примитивов это безразлично: два одинаковых int неразличимы. Для объектов же критично: Comparator может считать два объекта равными по одному критерию, но они остаются разными объектами. Нестабильная сортировка ломает составные компараторы и пользовательские ожидания.

Merge sort стабилен, но требует O(n) дополнительной памяти и не использует частичную упорядоченность входных данных.

🔹 Как работает TimSort

TimSort строится на наблюдении: реальные данные редко полностью случайны. Массивы часто содержат уже упорядоченные подпоследовательности — runs.

Алгоритм:

1. Проходит по массиву, находя естественные runs — уже отсортированные (возрастающие или убывающие) подпоследовательности. Убывающие разворачиваются на месте.

2. Если run короче минимального порога (minRun, вычисляется от размера массива, обычно 32-64 элемента) — расширяется insertion sort'ом. Insertion sort эффективен на почти отсортированных коротких последовательностях.

3. Runs помещаются в стек и сливаются попарно через merge sort. Merge происходит не сразу — алгоритм поддерживает инвариант на стеке runs для гарантии O(n log n) в худшем случае.

🔹 Galloping mode

При слиянии двух runs TimSort переключается в режим gallopping если обнаруживает что элементы из одного run идут длинными сериями подряд. Вместо поэлементного сравнения — бинарный поиск: ищет где именно заканчивается серия из первого run. Это даёт O(n) на уже отсортированных данных вместо O(n log n).

Порог переключения в gallopping — MIN_GALLOP = 7. Если 7 раз подряд «выиграл» один run — переключаемся. Порог динамически адаптируется: если gallopping оказывается неэффективным, порог растёт.

🔹 Сложность

→ Лучший случай (уже отсортированный массив): O(n) — один run, ничего сливать не нужно.
→ Средний и худший: O(n log n).
→ Память: O(n) в худшем случае, но на практике меньше — временный буфер для merge не всегда равен половине массива.

🔹 Практическое следствие

Если данные поступают уже частично отсортированными — TimSort это эксплуатирует автоматически. Повторная сортировка почти отсортированного массива значительно дешевле первичной сортировки случайных данных. Это важно для пайплайнов где данные сортируются инкрементально или приходят из источника с естественным порядком.

══════ Навигация ══════
Вакансии • Задачи • Собесы

🐸 Библиотека джависта

#CoreJava
  • 👍 9
  • ❤ 1
  • 🔥 1
Post #7609 2.48K
🗓 Выброси Date и забудь Calendar

Если ты работал с java.util.Date или Calendar, то сталкивался с этими проблемами. Мутабельные объекты, месяцы с нуля, запутанный API. В Java 8 появился java.time (JSR-310), и это то, что должно было быть с самого начала.

🔹 Instant — source of truth

Instant now = Instant.now(); // 2024-01-15T19:00:00Z

// Из Unix timestamp
Instant fromSeconds = Instant.ofEpochSecond(1705341600L);

// Получить timestamp
long epochMilli = now.toEpochMilli();

// Арифметика
Instant later = now.plusSeconds(3600); // +1 час

// Наносекундная точность (не то что Date с миллисекундами)
long nanos = now.getNano();


Храни в БД именно Instant. Никакой TZ-зависимости и никаких сюрпризов.

🔹 LocalDateTime, когда TZ не нужна

LocalDateTime dt = LocalDateTime.of(2024, 1, 15, 19, 0, 0);
LocalDateTime parsed = LocalDateTime.parse("2024-01-15T19:00:00");

// ✅ Юзер ввёл дату без TZ
// ✅ Бизнес-логика без мультирегиональности
// ❌ Хранение в БД — используй Instant
// ❌ API-ответы — неоднозначно без TZ


🔹 ZonedDateTime для пользователей

ZonedDateTime ny = ZonedDateTime.now(ZoneId.of("America/New_York"));
ZonedDateTime tokyo = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));

// Конвертация между TZ — один и тот же момент времени
ZonedDateTime london = ny.withZoneSameInstant(ZoneId.of("Europe/London"));


DST обрабатывается автоматически:
// 10 марта 2:30 AM не существует (переход на летнее время)
LocalDateTime nonExistent = LocalDateTime.of(2024, 3, 10, 2, 30);
ZonedDateTime adjusted = nonExistent.atZone(ZoneId.of("America/New_York"));
// → автоматически станет 3:30 AM EDT


🔹 ZonedDateTime vs OffsetDateTime

// ZonedDateTime — знает правила DST, для будущих дат
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("America/New_York"));

// OffsetDateTime — просто смещение, без DST. Для прошлых событий и API
OffsetDateTime odt = OffsetDateTime.now(ZoneOffset.ofHours(-5));


🔹 DateTimeFormatter для форматирования и парсинга

LocalDateTime dt = LocalDateTime.of(2024, 1, 15, 19, 0, 0);

// Predefined
dt.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); // "2024-01-15T19:00:00"
dt.format(DateTimeFormatter.BASIC_ISO_DATE); // "20240115"

// Custom
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
dt.format(fmt); // "2024-01-15 19:00:00"

// Парсинг с обработкой ошибок
public static Optional<LocalDateTime> parse(String s) {
try {
return Optional.of(LocalDateTime.parse(s, fmt));
} catch (DateTimeParseException e) {
return Optional.empty();
}
}


🔹 Шпаргалка по токенам

yyyy → 2024      MM → 01      dd → 15
HH → 19 (24h) hh → 07 (12h) mm → 00
ss → 00 SSS → 123 a → PM
z → EST Z → -0500 VV → America/New_York


🔹 Duration vs Period


// Duration — точный временной интервал
Duration duration = Duration.ofHours(24); // ровно 86400 секунд

// Period — календарный интервал
Period period = Period.ofDays(1); // 1 день (может быть 23 или 25 ч. при DST!)

// Оба работают с LocalDateTime, но семантика разная:
dt.plus(Duration.ofHours(24)); // +86400 сек
dt.plus(Period.ofDays(1)); // +1 календарный день


🔹 Миграция с легаси

// Date → Instant
Instant instant = oldDate.toInstant();

// Instant → Date
Date date = Date.from(instant);

// Date → LocalDateTime
LocalDateTime ldt = oldDate.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime();


══════ Навигация ══════
Вакансии • Задачи • Собесы

🐸 Библиотека джависта

#Enterprise
  • ❤ 7
  • 👍 6
  • 🔥 4
Post #7608 2.24K
🔥 4 привычки кодеров

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

но, я собрал 4 привычки адептов «чистого кода», (которые обычно все практикуют) 🤡

• Бесконечный рефакторинг рабочего кода.
Кажется, что так ты делаешь продукт лучше. Итог: жестко падаешь в перфекционизм. Переписываешь функцию по три раза, а бизнес ждет релиз. Закрываешь вкладку и в голове абсолютная пустота, время потрачено, а новых фичей ноль.

• Упарывание в сложную архитектуру

Сеньоры на ютубе обещают золотые горы, если внедрить микросервисы куда угодно. Итог: получаешь красивый overengineering-проект для мамы и 0 запущенных продуктов в срок, пока конкуренты клепают MVP на коленке.

• Душные споры на ревью
Неплохо, но как итог: ты пишешь полотна текста и тратишь часы на поиск глупой придирки к стилю, потому что банально фокус сместился с реальной задачи на эго.

• Ручная микро-оптимизация
Классика для тех, кто любит алгоритмы из универа. Итог: убиваешь дни жизни и выжимаешь миллисекунды, хотя бизнесу нужен был просто грязный, но рабочий скрипт еще вчера.

Проблема в том, что ни один из этих путей не дает самого главного - скорости и проверки гипотез. Реальному рынку плевать на твой идеальный код за 3 дня. Бизнес предпочтет код от ИИ-агента за 5 минут, который уже завтра начнет приносить деньги.

Хочешь обкатанный на нас лично и 100х учениках метод, как перестать кодить руками и начать делегировать задачи автономным системам?

👉 Заходи сюда, но у нас осталось всего 4 места, набор идет до завтрашнего дня.

P. S. Если интересно еще что-нибудь почитать от меня, то заходите в «Азбуку Айтишника», там я рассказываю об айти-базе, также у меня там есть бесплатный гайд на 15 глав по ии-агентам
  • 👏 2
  • ❤ 1
Post #7606 2.67K
🧵 Как починить мертвый ThreadLocal в пуле потоков

Если положить RequestId / userId / traceId в ThreadLocal и передать задачу в ExecutorService в итоге значение пропадёт. InheritableThreadLocal помогает только при явном создании потока, но не при переиспользовании из пула.

Alibaba решили это ещё в 2013 году, а библиотека до сих пор активно поддерживается → TransmittableThreadLocal (TTL).

🔹 Подключается:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.14.5</version>
</dependency>


🔹 Используется как обычный ThreadLocal, только умнее:
TransmittableThreadLocal<String> traceId = new TransmittableThreadLocal<>();
traceId.set("req-123");

ExecutorService pool = TtlExecutors.getTtlExecutorService(
Executors.newFixedThreadPool(4)
);

pool.submit(() -> {
// "req-123" — доступен здесь, в потоке из пула
System.out.println(traceId.get());
});


🔹 Три способа интеграции

→ Обернуть Runnable/Callable — TtlRunnable.get(task)
→ Обернуть пул — TtlExecutors.getTtlExecutorService(pool)
→ Java Agent — вообще без изменений в коде: -javaagent:transmittable-thread-local.jar

Агентовый режим особенно полезен, когда нужно прозрачно встроить TTL в легаси-проект или сторонний фреймворк — он патчит JDK-классы пулов на уровне байткода.

0 зависимостей. Работает с виртуальными потоками (Project Loom). Поддерживает кастомный TtlCopier для глубокого копирования значений при передаче в дочерний поток.

Актуально везде, где есть distributed tracing, MDC, tenant isolation или любой per-request контекст в многопоточке.

⚠️ README встретит иероглифами, не пугайся, английская версия лежит в README-EN.md.

🔗 Репозиторий на GitHub

══════ Навигация ══════
Вакансии • Задачи • Собесы

🐸 Библиотека джависта

#Enterprise
  • ❤ 6
  • 👍 4
  • 🔥 1
Post #7605 2.24K
🗓️ Уже через пару часов стартует вебинар!

Тема:
Как эффективно управлять контекстным окном LLM в мультиагентных системах и не сливать бюджет на токены


Ждем вас сегодня в 19:00 по московскому времени. Не пропустите начало, будет много практики!

👉 Успей занять место
Post #7603 2.4K
📋 Паттерн Command (Команда)

Command — поведенческий паттерн, который превращает запрос в самостоятельный объект. Этот объект содержит всю информацию о запросе: что делать, с какими параметрами и как это отменить.

Использование

🔹 Когда нужно откладывать выполнение операции или ставить её в очередь.
🔹 Когда требуется undo/redo — история операций.
🔹 Когда нужен аудит: кто, что и когда изменил.
🔹 Когда операции должны быть идемпотентными и безопасными для повтора при сбое.

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


1️⃣ Undo/Redo из коробки

Каждая команда знает, как себя отменить. Стек команд — готовая история изменений. Так работают все текстовые редакторы и графические инструменты.

2️⃣ Очереди и отложенное выполнение

Команды сериализуются и отправляются в Kafka или RabbitMQ. Воркеры их обрабатывают независимо. Если команда идемпотентна — безопасно повторить при сбое.

3️⃣ Полный audit log

Сохраняете команды в БД — получаете историю всех действий с параметрами. Это основа Event Sourcing: состояние системы восстанавливается воспроизведением команд.

4️⃣ Декомпозиция сложных операций

Макрокоманда объединяет несколько команд. Транзакционное выполнение, откат при ошибке — всё строится поверх простых команд.

🤖 Осталось 4 места на курс по ИИ-агентам. Набор закрывается 30 апреля.
🔗 Успеть на обучение

══════ Навигация ══════
Вакансии • Задачи • Собесы

🐸 Библиотека джависта

#CoreJava
  • ❤ 4
  • 👍 4
  • 🔥 1
Older posts →
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →