Собираем маскировщик секретов для логов!
В логах не должны оставаться токены, пароли и API-ключи. Сделаем небольшой sanitizer, который находит опасные поля и заменяет значение на маску.
В этой задаче:
👉 Java Ready | #задача
В логах не должны оставаться токены, пароли и API-ключи. Сделаем небольшой sanitizer, который находит опасные поля и заменяет значение на маску.
В этой задаче:
• описываем шаблон секретного поля
• используем Matcher для замены
• сохраняем имя ключа
• прячем только значение после знака равенства
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤4🔥3🤝2😁1
Интересный разбор WebFlux и Virtual Threads под нагрузкой!
Автор сравнивает реактивный WebFlux и Spring MVC с виртуальными потоками на микросервисной системе под нагрузкой 2000 RPS.
В статье автор показывает:
• чем event loop отличается от thread-per-request модели
• как WebFlux и Virtual Threads ведут себя при I/O
• какие параметры JVM и Spring влияют на результат
👉 Java Ready | #статья
Автор сравнивает реактивный WebFlux и Spring MVC с виртуальными потоками на микросервисной системе под нагрузкой 2000 RPS.
В статье автор показывает:
• чем event loop отличается от thread-per-request модели
• как WebFlux и Virtual Threads ведут себя при I/O
• какие параметры JVM и Spring влияют на результат
Продолжай читать на Habr
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍2🔥2
Шпаргалка по generics в Java!
Например, ? extends T удобно использовать для чтения данных из producer-коллекции, а ? super T подходит для коллекции, в которую нужно безопасно добавлять значения.
На картинке собраны generics, wildcards, PECS, method overloading, recursive generics, covariance и важный нюанс type erasure. Особенно полезно держать под рукой правило Producer Extends Consumer Super.
Сохрани, чтобы не потерять!
👉 Java Ready | #ресурс
Например, ? extends T удобно использовать для чтения данных из producer-коллекции, а ? super T подходит для коллекции, в которую нужно безопасно добавлять значения.
На картинке собраны generics, wildcards, PECS, method overloading, recursive generics, covariance и важный нюанс type erasure. Особенно полезно держать под рукой правило Producer Extends Consumer Super.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤3🔥3🤝2
Разбиваем список на батчи в Java!
Когда нужно отправить много записей в API или базу, их часто удобнее обрабатывать пачками. Так проще контролировать нагрузку и размер одного запроса.
Пусть есть список событий:
Размер пачки лучше держать отдельной переменной:
Идём по списку шагом batchSize:
Теперь получаем часть списка:
Эту пачку можно отправить дальше:
Важно что subList возвращает view на исходный список. Если исходный список будут менять параллельно, лучше сделать независимую копию.
Для копии достаточно одной строки:
Такой приём подходит для bulk insert, отправки сообщений, экспорта данных, обработки файлов и любых задач, где один большой список нужно безопасно разложить на управляемые части.
👉 Java Ready | #практика
Когда нужно отправить много записей в API или базу, их часто удобнее обрабатывать пачками. Так проще контролировать нагрузку и размер одного запроса.
Пусть есть список событий:
List events = List.of("a", "b", "c", "d", "e");Размер пачки лучше держать отдельной переменной:
int batchSize = 2;
Идём по списку шагом batchSize:
for (int start = 0; start < events.size(); start += batchSize) {
int end = Math.min(start + batchSize, events.size());
}Теперь получаем часть списка:
List batch = events.subList(start, end);
Эту пачку можно отправить дальше:
sendBatch(batch);
Важно что subList возвращает view на исходный список. Если исходный список будут менять параллельно, лучше сделать независимую копию.
Для копии достаточно одной строки:
List batch = List.copyOf(events.subList(start, end));
Такой приём подходит для bulk insert, отправки сообщений, экспорта данных, обработки файлов и любых задач, где один большой список нужно безопасно разложить на управляемые части.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍3🔥2
Media is too big
VIEW IN TELEGRAM
Java Programming MOOC - большой курс Java от University of Helsinki!
На сайте собран большой открытый курс по Java от University of Helsinki. Есть две части, отдельные уроки, упражнения, основы синтаксиса, объекты, коллекции, обработка ошибок, файлы и более продвинутые темы.
Материал удобно проходить по главам. В боковой навигации есть части курса, внутри разделов много объяснений и примеров, поэтому ресурс хорошо подходит как маршрут от базы к уверенной практике.
👉 Java Ready | #ресурс
На сайте собран большой открытый курс по Java от University of Helsinki. Есть две части, отдельные уроки, упражнения, основы синтаксиса, объекты, коллекции, обработка ошибок, файлы и более продвинутые темы.
Материал удобно проходить по главам. В боковой навигации есть части курса, внутри разделов много объяснений и примеров, поэтому ресурс хорошо подходит как маршрут от базы к уверенной практике.
Оставляю ссылочку на Java Programming MOOC
Please open Telegram to view this post
VIEW IN TELEGRAM
❤11👍5🔥4🤝1
Делаем простой registry обработчиков команд на Java!
Когда команд становится больше, длинная цепочка if/else быстро начинает мешать. Вместо этого можно хранить обработчики в Map.
Опишем интерфейс команды:
Создадим registry:
Добавим пару команд:
Теперь входную строку можно разделить:
Первый элемент — имя команды:
Достаём обработчик:
И запускаем, если команда существует:
Ожидаемый вывод для
Такой подход удобно расширять, новая команда добавляется одной строкой в registry, без переписывания большого switch.
👉 Java Ready | #практика
Когда команд становится больше, длинная цепочка if/else быстро начинает мешать. Вместо этого можно хранить обработчики в Map.
Опишем интерфейс команды:
@FunctionalInterface
interface Command {
void run(String[] args);
}
Создадим registry:
Map<String, Command> commands = new HashMap<>();
Добавим пару команд:
commands.put("hello", args ->
System.out.println("Hello, " + args[0]));
commands.put("sum", args ->
System.out.println(Integer.parseInt(args[0])
+ Integer.parseInt(args[1])));Теперь входную строку можно разделить:
String input = "sum 10 25";
String[] parts = input.split(" ");
Первый элемент — имя команды:
String name = parts[0];
String[] args = Arrays.copyOfRange(parts, 1, parts.length);
Достаём обработчик:
Command command = commands.get(name);
И запускаем, если команда существует:
if (command != null) {
command.run(args);
} else {
System.out.println("Unknown command");
}Ожидаемый вывод для
sum 10 25:35
Такой подход удобно расширять, новая команда добавляется одной строкой в registry, без переписывания большого switch.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤6🔥2😁1
Собираем diff двух списков по id!
Нужно сравнить старый и новый список объектов и понять, что добавилось, что изменилось и что исчезло. Сделаем небольшой diff по идентификатору.
В этой задаче:
Такой подход полезен для синхронизации справочников, импорта данных, обновления кеша и подготовки изменений перед записью в базу.
👉 Java Ready | #задача
Нужно сравнить старый и новый список объектов и понять, что добавилось, что изменилось и что исчезло. Сделаем небольшой diff по идентификатору.
В этой задаче:
• индексируем старые элементы по id
• ищем новые и изменённые записи
• отдельно находим удалённые id
• возвращаем понятный результат
Такой подход полезен для синхронизации справочников, импорта данных, обновления кеша и подготовки изменений перед записью в базу.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍4🔥4🤝1
Например,
/bin содержит системные бинарные файлы, а /etc — конфигурации, управляющие поведением системы.На картинке — директории Linux, их назначение и место в иерархии.
Сохрани, чтобы не забыть!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍5🔥4🤝2
Почему Stream.peek не стоит использовать для бизнес-логики?
peek выглядит удобным способом вставить действие внутрь stream pipeline. Часто туда кладут логирование, метрики или даже изменение объекта.
Например, такой код кажется коротким:
Проблема в том, что peek задуман как инструмент для отладки и наблюдения за элементами, а не как основной шаг бизнес-логики.
Пока нет terminal operation, ничего не выполняется:
В этом примере activate вообще не вызовется, потому что pipeline только описан, но не запущен.
Ещё хуже, когда поведение зависит от terminal operation. Например, count может быть оптимизирован так, что часть промежуточных действий не выполняется ожидаемым способом.
Если нужно изменить объекты явно, лучше использовать обычный цикл:
Если нужно получить новые значения, лучше использовать map:
А peek оставить для временной диагностики:
👉 Java Ready | #совет
peek выглядит удобным способом вставить действие внутрь stream pipeline. Часто туда кладут логирование, метрики или даже изменение объекта.
Например, такой код кажется коротким:
users.stream()
.peek(User::activate)
.toList();
Проблема в том, что peek задуман как инструмент для отладки и наблюдения за элементами, а не как основной шаг бизнес-логики.
Пока нет terminal operation, ничего не выполняется:
users.stream()
.peek(User::activate);
В этом примере activate вообще не вызовется, потому что pipeline только описан, но не запущен.
Ещё хуже, когда поведение зависит от terminal operation. Например, count может быть оптимизирован так, что часть промежуточных действий не выполняется ожидаемым способом.
Если нужно изменить объекты явно, лучше использовать обычный цикл:
for (User user : users) {
user.activate();
}Если нужно получить новые значения, лучше использовать map:
List result = users.stream()
.map(UserDto::from)
.toList();
А peek оставить для временной диагностики:
users.stream()
.peek(user -> log.debug("user {}", user.id()))
.toList();
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7❤4🔥2🤝1
Хорошая статья про обработку ошибок в Kafka!
Автор разбирает ситуацию, когда консьюмер не может обработать сообщение и снова упирается в тот же offset. Дальше показывает, как использовать Dead Letter Queue, retryable и non-retryable ошибки.
В статье автор показывает:
• почему ошибка десериализации может остановить консьюмера
• как настроить DeadLetterPublishingRecoverer в Spring Kafka
• зачем выносить проблемные сообщения в отдельный DLT процессор
👉 Java Ready | #статья
Автор разбирает ситуацию, когда консьюмер не может обработать сообщение и снова упирается в тот же offset. Дальше показывает, как использовать Dead Letter Queue, retryable и non-retryable ошибки.
В статье автор показывает:
• почему ошибка десериализации может остановить консьюмера
• как настроить DeadLetterPublishingRecoverer в Spring Kafka
• зачем выносить проблемные сообщения в отдельный DLT процессор
Продолжай читать на Habr
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍3🔥2🤝2
Шпаргалка по контейнеризации Java-приложений!
Например, multi-stage build помогает не тащить инструменты сборки в production-образ, а .dockerignore убирает лишние файлы из build context.
На картинке собраны практики для Docker-образов с Java. Есть фиксированные base image теги, минимальный runtime, запуск не от root, обработка сигналов, graceful shutdown, .dockerignore и проверка уязвимостей.
Сохрани, чтобы не потерять!
👉 Java Ready | #ресурс
Например, multi-stage build помогает не тащить инструменты сборки в production-образ, а .dockerignore убирает лишние файлы из build context.
На картинке собраны практики для Docker-образов с Java. Есть фиксированные base image теги, минимальный runtime, запуск не от root, обработка сигналов, graceful shutdown, .dockerignore и проверка уязвимостей.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍4🔥3🤝1
Собираем поиск по словам на Java!
Нужно быстро находить документы, где встречается слово. Сделаем небольшой inverted index, который хранит для каждого слова набор id документов.
Начнём с хранилища индекса:
Документ можно представить обычной строкой:
Разобьём текст на слова в нижнем регистре:
Теперь добавим каждое слово в индекс:
Поиск становится простым обращением к map:
Такой индекс не заменяет полноценный search engine, но хорошо показывает идею. Мы заранее строим структуру, чтобы потом быстро получать список документов по слову.
👉 Java Ready | #практика
Нужно быстро находить документы, где встречается слово. Сделаем небольшой inverted index, который хранит для каждого слова набор id документов.
Начнём с хранилища индекса:
Map<String, Set<Integer>> index = new HashMap<>();
Документ можно представить обычной строкой:
int id = 7;
String text = "Java streams and maps";
Разобьём текст на слова в нижнем регистре:
String[] words = text
.toLowerCase()
.split("\\W+");
Теперь добавим каждое слово в индекс:
for (String word : words) {
index.computeIfAbsent(word, k -> new HashSet<>())
.add(id);
}Поиск становится простым обращением к map:
Set<Integer> result = index.getOrDefault(
"java",
Set.of()
);
Такой индекс не заменяет полноценный search engine, но хорошо показывает идею. Мы заранее строим структуру, чтобы потом быстро получать список документов по слову.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5❤2🔥2🤝1
Шпаргалка по контейнеризации Java-приложений!
Например, multi-stage build помогает не тащить инструменты сборки в production-образ, а .dockerignore убирает лишние файлы из build context.
На картинке собраны практики для Docker-образов с Java. Есть фиксированные base image теги, минимальный runtime, запуск не от root, обработка сигналов, graceful shutdown, .dockerignore и проверка уязвимостей.
Сохрани, чтобы не потерять!
👉 Java Ready | #совет
Например, multi-stage build помогает не тащить инструменты сборки в production-образ, а .dockerignore убирает лишние файлы из build context.
На картинке собраны практики для Docker-образов с Java. Есть фиксированные base image теги, минимальный runtime, запуск не от root, обработка сигналов, graceful shutdown, .dockerignore и проверка уязвимостей.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍2🔥2
Почему BigDecimal.equals может странно работать даже при одинаковом числе?
BigDecimal часто используют для денег, процентов и точных расчётов. Но сравнивать такие значения через equals не всегда то, что ожидается.
Посмотри на пример:
Математически это одно и то же значение. Но equals вернёт false, потому что BigDecimal сравнивает не только число, но и scale.
У этих объектов разный scale:
Для денежных расчётов это может быть неожиданно. Например, значение из базы пришло как 1.00, а значение из расчёта получилось как 1.0.
Если нужно сравнить именно числовое значение, используй compareTo:
compareTo смотрит на математическое значение и не считает scale причиной различия.
А вот в коллекциях equals всё равно важен:
В таком Set будет два элемента, потому что HashSet опирается на equals и hashCode.
Если тебе нужен единый формат, значение можно нормализовать:
Но для денег нормализацию лучше делать осознанно, чтобы не потерять важный формат отображения.
Для числового сравнения BigDecimal используй compareTo, а equals оставляй для случаев, где важен ещё и scale.
👉 Java Ready | #совет
BigDecimal часто используют для денег, процентов и точных расчётов. Но сравнивать такие значения через equals не всегда то, что ожидается.
Посмотри на пример:
var a = new BigDecimal("1.0");
var b = new BigDecimal("1.00");
System.out.println(a.equals(b));Математически это одно и то же значение. Но equals вернёт false, потому что BigDecimal сравнивает не только число, но и scale.
У этих объектов разный scale:
System.out.println(a.scale()); // 1
System.out.println(b.scale()); // 2
Для денежных расчётов это может быть неожиданно. Например, значение из базы пришло как 1.00, а значение из расчёта получилось как 1.0.
Если нужно сравнить именно числовое значение, используй compareTo:
if (a.compareTo(b) == 0) {
System.out.println("same value");
}compareTo смотрит на математическое значение и не считает scale причиной различия.
А вот в коллекциях equals всё равно важен:
Set<BigDecimal> values = new HashSet<>();
values.add(new BigDecimal("1.0"));
values.add(new BigDecimal("1.00"));
В таком Set будет два элемента, потому что HashSet опирается на equals и hashCode.
Если тебе нужен единый формат, значение можно нормализовать:
var normalized = amount.stripTrailingZeros();
Но для денег нормализацию лучше делать осознанно, чтобы не потерять важный формат отображения.
Для числового сравнения BigDecimal используй compareTo, а equals оставляй для случаев, где важен ещё и scale.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤5🔥5