Сверяем файлы сборки и находим расхождения!
После копирования приложения можно проверить, что файлы совпадают с исходной сборкой. Напишем небольшую проверку двух каталогов, которая найдёт отсутствующие и изменённые файлы, не загружая их целиком в память.
Обойдём файлы без загрузки всего списка в память и закроем поток после проверки. Символические ссылки отфильтруем через LinkOption.NOFOLLOW_LINKS:
try (Stream files = Files.walk(buildDir)) {
Iterator paths = files.filter(path ->
Files.isRegularFile(path, NOFOLLOW_LINKS)).iterator();
while (paths.hasNext()) compare(paths.next(), buildDir, deployDir);
}
Для каждого файла строим такой же относительный путь в каталоге развёртывания. Это сохраняет структуру вложенных папок:
Path relative = buildDir.relativize(source);
Path deployed = deployDir.resolve(relative);
Отсутствующий файл отмечаем отдельно, иначе проверка совпадения не сможет отличить его от пустого файла:
if (!Files.isRegularFile(deployed)) {
reportMissing(relative);
return;
}
Для существующих файлов используем Files.mismatch. Метод читает содержимое по мере необходимости и возвращает позицию первого различия, а -1 означает полное совпадение:
long offset = Files.mismatch(source, deployed);
if (offset == -1) reportMatch(relative);
else reportDifference(relative, offset);
Можно добавить обратный проход по каталогу развёртывания, если нужно также находить лишние файлы.
Java Библиотека | Мы в Телеграм
Java Records — больше, чем сокращённая запись класса
record User(String name, String email) {}
Вы получаете:
→ Поля компонентов с модификатором final.
→ Автоматические equals(), hashCode() и toString().
→ Явный сигнал: «этот тип хранит данные».
Используйте records для DTO — меньше шаблонного кода, проще ревью.
Java Библиотека | Мы в Телеграм
Java Records, Lombok и POJO: в чём разница?
Все три подхода помогают описывать данные, но отвечают на разные потребности: краткость, генерация шаблонного кода и контроль над поведением класса.
• Record — компактный носитель данных. Records стали стандартной возможностью языка в Java 16:
public record User(
Long id,
String name,
String email
) {}
Компилятор создаёт конструктор для всех компонентов, методы доступа id(), name(), email(), а также equals(), hashCode() и toString(). Подходит для DTO, моделей запросов и ответов API, данных событий.
Неизменяемость поверхностная: поля компонентов — final, но содержимое переданного списка или другого изменяемого объекта всё ещё может меняться.
• Lombok — меньше шаблонного кода. Аннотации позволяют генерировать методы и конструкторы при компиляции:
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Long id;
private String name;
private String email;
}
Lombok умеет создавать getters/setters, конструкторы, equals(), hashCode(), toString() и builder через @Builder.
Удобен для существующих проектов и классов с большим количеством повторяющегося кода. При этом добавляет зависимость при сборке и требует понимания того, что именно генерируется.
С JPA-сущностями аннотации стоит выбирать аккуратно: автоматически созданные equals(), hashCode() и toString() могут некорректно работать со связями и ленивой загрузкой.
• POJO — обычный Java-объект. Класс без обязательной привязки к специальному фреймворку или модели программирования. Вы сами определяете конструкторы, валидацию, изменяемость, бизнес-логику и правила сравнения. Подходит для доменных моделей и классов с нестандартным поведением.
Это не три взаимоисключающих варианта: record — возможность языка, Lombok — инструмент генерации кода, POJO — характеристика класса. Класс с аннотациями Lombok вполне может оставаться POJO. Выбирайте подход по назначению класса, а не только по количеству сэкономленных строк.
Java Библиотека | Мы в Телеграм
Как кешировать данные о классах и не удерживать ClassLoader?
Фреймворки часто читают аннотации и методы через reflection. Сохранять такие данные в обычной статической map не всегда безопасно, если приложение выгружает плагины или модули.
Например, типичный кеш хранит ссылку на класс в ключе:
Map, Metadata> cache = new ConcurrentHashMap<>();
Заполнять такой кеш можно через computeIfAbsent:
cache.computeIfAbsent(type, MetadataCache::inspect);
Но долгоживущий кеш удерживает ключи-Class, а вместе с ними может задержать выгрузку ClassLoader. Для данных, привязанных к Class, в Java есть ClassValue.
Опиши вычисление один раз в computeValue:
ClassValue cache = new ClassValue<>() {
protected Metadata computeValue(Class type) {
return inspect(type);
}
};
Значение вычисляется по запросу, отдельно для каждого класса. Оставляй inspect без побочных эффектов, поскольку конкурентные вызовы могут привести к повторному вычислению.
Читай метаданные через get:
Metadata metadata = cache.get(Order.class);
metadata.invoke(order);
Такой доступ не требует вручную синхронизировать создание значения. ClassValue подходит для reflection-кеша, который индексируется объектами Class.
Если значение нужно пересчитать, удали его:
cache.remove(Order.class);
Metadata refreshed = cache.get(Order.class);
Следующий get снова вызовет computeValue. Для обычных кешей с произвольными ключами ClassValue не подходит.
Java Библиотека | Мы в Телеграм
Что такое тернарный оператор выбора?
Тернарный условный оператор ?: - оператор, которым можно заменить некоторые конструкции операторов if-then-else.
Выражение записывается в следующей форме:
условие ? выражение1 : выражение2
Если условие выполняется, то вычисляется выражение1 и его результат становится результатом выполнения всего оператора. Если же условие равно false, то вычисляется выражение2 и его значение становится результатом работы оператора. Оба операнда выражение1 и выражение2 должны возвращать значение одинакового (или совместимого) типа.
Java Библиотека | Мы в Телеграм
Проверяем пересечение бронирований на Java!
В календаре нужно отклонить новую бронь, если выбранное время уже занято. Для проверки достаточно сравнить начало и конец двух интервалов, не перебирая каждую минуту внутри них.
Сделаем модель с полуоткрытым интервалом, где начало включается, а конец уже свободен:
record Booking(LocalDateTime start, LocalDateTime end) {
Booking {
if (!start.isBefore(end)) {
throw new IllegalArgumentException("End must be after start");
}
}
boolean overlaps(Booking other) {
return start.isBefore(other.end())
&& other.start().isBefore(end);
}
}
Проверка не даст создать бронь нулевой или отрицательной длины. Условие пересечения учитывает обе границы и не считает соседние интервалы конфликтом.
Подготовим уже занятые промежутки и новый запрос:
List existing = List.of(
new Booking(start1, end1),
new Booking(start2, end2)
);
Booking requested = new Booking(requestStart, requestEnd);
Здесь предполагается, что все значения уже приведены к одной временной зоне. Для расписания в нескольких регионах лучше сравнивать Instant, а исходный ZoneId сохранять отдельно.
Проверим весь список и получим понятный результат:
boolean conflict = existing.stream()
.anyMatch(booking -> booking.overlaps(requested));
anyMatch завершает проверку, как только найдёт первое пересечение. Если conflict равен false, новую бронь можно добавить, а интервалы, которые соприкасаются ровно по границе, останутся допустимыми.
Java Библиотека | Мы в Телеграм
☕️ Скользящие окна в Stream без ручного буфера
Нужно сравнить соседние измерения или обработать последовательность небольшими перекрывающимися группами? В Java 24+ есть готовый gatherer.
var windows = Stream.of(1, 2, 3, 4, 5)
.gather(Gatherers.windowSliding(3))
.toList();
// [[1, 2, 3], [2, 3, 4], [3, 4, 5]]
Каждое следующее окно теряет самый старый элемент и получает новый. Если вход короче размера окна, получится одно неполное окно; пустой Stream не выдаст ни одного.
🟡 Окна нельзя изменять. Большой размер окна может потреблять лишнюю память — это не бесплатная замена любого буфера.
Gatherers стали стабильным API в Java 24. В докладе автора API есть примеры собственных преобразований и правила работы с параллельными потоками.
🔗 Источник • Разбор и примеры
Java Библиотека | Мы в Телеграм
Шпаргалка по выбору типа даты и времени в Java!
Для календарного интервала вроде срока подписки используют Period, а для точной длительности в часах и секундах подходит Duration. Когда важен конкретный момент, выбирают Instant или тип с часовым поясом.
На картинке собрана схема выбора между LocalDate, LocalTime, LocalDateTime, Instant и ZonedDateTime. Она помогает не потерять часовой пояс там, где он влияет на расписание и переходы летнего времени.
Сохрани, чтобы не потерять!
Java Библиотека | Мы в Телеграм
final, finally и finalize: разные задачи
final запрещает повторное присваивание переменной, переопределение метода или наследование класса. final-ссылка не делает объект неизменяемым:
final var names = new ArrayList();
names.add("Java"); // допустимо
finally выполняется при выходе из try, в том числе после return или исключения. Это не гарантия на случай аварийного завершения JVM. Для AutoCloseable обычно удобнее try-with-resources.
finalize() — устаревший механизм финализации. В Java 18 его пометили для удаления, а не удалили: метод ещё присутствует в API Java 25. Момент вызова не гарантирован, поэтому закрывать файлы и соединения через него нельзя.
#Java
Java Библиотека | Мы в Телеграм
Подборка Spring от 13 октября: что открыть
В выпуске This Week in Spring от 13 октября собраны материалы по Spring Boot, Spring Modulith, Spring AI и инструментам разработчика.
Такую подборку удобнее читать выборочно: выберите технологию из своего проекта, откройте первоисточник и сопоставьте версию API со своей. Одна ссылка из обзора не заменяет проверку совместимости зависимостей.
Полный выпуск с исходными ссылками.
#Java
Java Библиотека | Мы в Телеграм
Spring: контейнер собирает зависимости
В обычном Java-коде объект можно создать через new и передать зависимости в конструктор. В Spring ту же сборку берёт на себя IoC-контейнер: создаёт бины по конфигурации и связывает их.
Dependency Injection означает, что объект получает зависимости извне. Он не должен сам искать их через глобальный доступ к контейнеру.
Constructor injection удобно использовать для обязательных зависимостей: состав объекта виден из сигнатуры конструктора, а поля могут быть final.
Spring Boot добавляет автоконфигурацию и удобный запуск, но не отменяет необходимость понимать, какие бины созданы и почему выбран конкретный кандидат.
#Java
Java Библиотека | Мы в Телеграм
Webhook: подписывайте исходные байты запроса
Для HMAC-SHA256 сервер вычисляет MAC по исходному телу и общему секрету, затем сравнивает результат с присланной подписью.
В Java используются Mac.getInstance("HmacSHA256") и SecretKeySpec. Для сравнения байтовых массивов подходит MessageDigest.isEqual(expected, provided).
Важны детали протокола: секрет может быть строкой или Base64-данными, а подпись — hex либо Base64. Декодируйте именно тот формат, который задаёт отправитель.
Не пересобирайте JSON перед проверкой: пробелы и порядок полей меняют байты. Некорректный формат подписи должен приводить к отказу до обработки события.
HMAC не предотвращает повторную доставку. Для этого отдельно нужны правила проверки времени или учёт идентификаторов событий.
#Java
Java Библиотека | Мы в Телеграм
unmodifiableList: представление, а не снимок
var source = new ArrayList<>(List.of("A"));
var view = Collections.unmodifiableList(source);
var snapshot = List.copyOf(source);
source.add("B");
System.out.println(view); // [A, B]
System.out.println(snapshot); // [A]
Обёртка запрещает изменение списка через view, но показывает изменения исходного списка.
List.copyOf(), доступный с Java 10, создаёт независимый по составу неизменяемый список и не принимает null-элементы. Копия поверхностная: изменяемые объекты внутри неё остаются теми же объектами.
При возврате данных из сервиса решите, нужен читателю текущий вид коллекции или снимок на момент вызова.
#Java
Java Библиотека | Мы в Телеграм
Загрузчик классов — часть идентичности типа
Для JVM класс определяется не только именем, но и загрузчиком, который его определил. Два одноимённых класса из разных загрузчиков могут оказаться несовместимыми типами.
В типичной современной JVM есть bootstrap, platform и application class loader. Пользовательский загрузчик может добавлять свой способ поиска классов.
При стандартной делегации родителю дочерний загрузчик видит классы родителей; обратная видимость автоматически не появляется. Это важно для плагинов: общий интерфейс должен загружаться так, чтобы обе стороны действительно использовали один тип.
Конкретная схема может отличаться от стандартной, например в контейнерах и системах плагинов.
#Java
Java Библиотека | Мы в Телеграм
Безопасность Java: десять проверок перед релизом
1. Проверяйте входные данные и отдельно права на действие. Валидация не заменяет авторизацию.
2. Передавайте SQL-значения параметрами PreparedStatement. Имена таблиц и колонок выбирайте из разрешённого набора.
3. Не отдавайте клиенту stack trace и внутреннюю конфигурацию.
4. Храните секреты вне репозитория, определите способ их ротации.
5. Проверяйте доступ к конкретному объекту, а не только роль пользователя.
6. Ограничивайте десериализуемые типы. JSON сам по себе не гарантирует безопасность.
7. Следите за уязвимостями и обновлениями зависимостей.
8. Не записывайте пароли и токены в логи.
9. Настройте Secure, HttpOnly и подходящий SameSite для сессионных cookie.
10. Проверьте защитные заголовки и CSP под конкретный интерфейс.
Настройки нужно проверять вместе с поведением приложения, а не только наличием аннотаций.
#Java
Java Библиотека | Мы в Телеграм
Работаете с СУБД? Присоединяйтесь к сообществу Pangolin для разработчиков и администраторов баз данных!
Pangolin DB — это PostgreSQL с 100+ доработками, и команда СберТеха открыто рассказывает о его разработке.
В канале «СУБД Pangolin» найдете:
🔹 Глубокие разборы архитектуры и кода
🔹 Кейсы оптимизации и доработки PostgreSQL
🔹 Советы и опыт инженеров
🔹 Вебинары и встречи с экспертами
🔹 Вакансии и жизнь команды от первого лица
Присоединяйтесь к сообществу, где говорят на языке баз данных!
📚 10 ловушек Java: проверь себя
Почему add() выбрасывает исключение?
Почему remove(1) удаляет число 2?
Откуда NullPointerException в обычном сравнении?
Собрали 10 коротких разборов. В каждом — пример кода, результат, объяснение и исправление.
Сначала попробуй угадать ответ, затем проверь себя. PDF прикреплён к этому посту — сохраняй для работы и подготовки к собеседованиям.
«Java библиотека» на удобной тебе площадке:
🔹 ВКонтакте
🔹 Telegram
🔹 MAX
Подписывайся — продолжим разбирать Java на конкретных примерах.
Почему GC не устраняет все утечки памяти
GC освобождает память объектов, которые больше недостижимы. Если приложение продолжает хранить ненужную ссылку, сборщик не может угадать, что объект больше не нужен бизнес-логике.
Проверьте:
• статическую коллекцию, в которую только добавляют элементы;
• кеш без ограничений или удаления записей;
• ThreadLocal в долгоживущем потоке;
• слушателя, который остаётся зарегистрированным после закрытия экрана или сессии.
Для поиска причины полезны heap dump и пути удержания объектов от GC roots. Сам рост занятой памяти ещё не доказывает утечку: смотрите, что удерживается после сборок и почему.
#Java
Java Библиотека | Мы в Телеграм
Критическая уязвимость в Java: атака по сети без пароля и участия пользователя
Oracle опубликовала предупреждение CVE-2026-91403 с оценкой CVSS 9.1. Проблема находится в JSSE — компоненте Java, который обеспечивает защищённые соединения TLS.
По описанию Oracle, успешная атака может позволить читать, изменять и удалять данные, доступные уязвимому приложению. Для эксплуатации не нужны учётные данные, а сложность атаки оценена как низкая.
В списке затронутых версий:
- Java SE 8u511 / 8u511-perf, 11.0.33, 17.0.21, 21.0.13, 25.0.5 и 27.0.1.
- Oracle GraalVM for JDK 17.0.21 и 21.0.13.
- Oracle GraalVM Enterprise Edition 21.3.20.
Условия зависят от приложения: Oracle указывает на сценарии, где данные атакующего попадают в API уязвимого компонента, например через веб-сервис. Само наличие Java ещё не означает, что любой сервис можно атаковать.
Администраторам стоит проверить используемые сборки Java, включая runtime внутри контейнеров, и установить исправления по инструкции поставщика.
Предупреждение опубликовано 21 октября. Более ранние версии тоже могут быть затронуты — отсутствие в списке не подтверждает их безопасность.
https://www.oracle.com/security-alerts/alert-cve-2026-91403.html
Java Библиотека | Мы в Телеграм
Надёжность сделки
Время ответа админа
Обычно отвечает быстро
Размещений через Помогач
Первое размещение — за вами
Публикация канала «Java библиотека» от 30 октября 2026, 20:56