Знали, почему Pattern.compile лучше не вызывать в горячем цикле?
В Java регулярные выражения часто используют для валидации, поиска и очистки строк. Рабочий код выглядит так:
Проблема в том, что Pattern.compile создаёт объект шаблона. Если делать это на каждой итерации, программа снова и снова разбирает одно и то же выражение.
Для короткого списка разницы почти не видно. Но в обработке логов, CSV, API-ответов или очередей это превращается в лишнюю нагрузку.
Лучше скомпилировать шаблон один раз:
А внутри цикла только создавать matcher:
Так код показывает, что регулярка постоянная, а не строится заново для каждой строки.
Если шаблон зависит от входных данных, его всё равно можно кешировать по ключу:
Но кешировать стоит только ограниченный набор шаблонов, чтобы не получить бесконечно растущую Map.
👉 Java Ready | #совет
В Java регулярные выражения часто используют для валидации, поиска и очистки строк. Рабочий код выглядит так:
for (String email : emails) {
if (Pattern.compile(".+@.+\\..+").matcher(email).matches()) {
valid.add(email);
}
}Проблема в том, что Pattern.compile создаёт объект шаблона. Если делать это на каждой итерации, программа снова и снова разбирает одно и то же выражение.
Для короткого списка разницы почти не видно. Но в обработке логов, CSV, API-ответов или очередей это превращается в лишнюю нагрузку.
Лучше скомпилировать шаблон один раз:
private static final Pattern EMAIL =
Pattern.compile(".+@.+\\..+");
А внутри цикла только создавать matcher:
for (String email : emails) {
if (EMAIL.matcher(email).matches()) {
valid.add(email);
}
}Так код показывает, что регулярка постоянная, а не строится заново для каждой строки.
Если шаблон зависит от входных данных, его всё равно можно кешировать по ключу:
Pattern pattern = cache.computeIfAbsent(mask, Pattern::compile);
Но кешировать стоит только ограниченный набор шаблонов, чтобы не получить бесконечно растущую Map.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤4🔥4🤝1
Java 25 становится проще!
Автор разбирает JEP-512 и изменения, которые позволяют писать небольшие программы с меньшим количеством обязательной обвязки. Вместо класса, static main и ручных импортов можно сосредоточиться на самой задаче, а не на стартовом шаблоне.
В статье разбирают:
• как устроены упрощённые исходники Java 25
• зачем появились неявные импорты и класс IO
• как запускать короткие Java-скрипты из командной строки
👉 Java Ready | #статья
Автор разбирает JEP-512 и изменения, которые позволяют писать небольшие программы с меньшим количеством обязательной обвязки. Вместо класса, static main и ручных импортов можно сосредоточиться на самой задаче, а не на стартовом шаблоне.
В статье разбирают:
• как устроены упрощённые исходники Java 25
• зачем появились неявные импорты и класс IO
• как запускать короткие Java-скрипты из командной строки
Продолжай читать на Habr
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍5🔥3
Почему Files.lines() нельзя оставлять без try-with-resources?
Files.lines() выглядит как удобный способ быстро получить Stream строк из файла. Но за этим Stream остаётся открытый файловый ресурс.
После count поток может быть исчерпан, но файл не обязан закрыться сразу. В долгоживущем сервисе или цикле обработки это приводит к накоплению открытых дескрипторов.
Правильнее ограничить жизнь Stream блоком try-with-resources.
Java закроет поток даже при исключении внутри обработки. Это особенно полезно для больших логов, CSV-файлов и пакетных задач, где не хочется загружать всё содержимое в память.
Если нужен небольшой файл целиком, можно взять готовый список строк.
readAllLines проще, но читает файл полностью. Files.lines подходит для потоковой обработки, если не забывать закрывать ресурс.
👉 Java Ready | #совет
Files.lines() выглядит как удобный способ быстро получить Stream строк из файла. Но за этим Stream остаётся открытый файловый ресурс.
Stream<String> lines = Files.lines(path);
long count = lines.count();
После count поток может быть исчерпан, но файл не обязан закрыться сразу. В долгоживущем сервисе или цикле обработки это приводит к накоплению открытых дескрипторов.
Правильнее ограничить жизнь Stream блоком try-with-resources.
try (Stream<String> lines = Files.lines(path)) {
long count = lines.count();
}Java закроет поток даже при исключении внутри обработки. Это особенно полезно для больших логов, CSV-файлов и пакетных задач, где не хочется загружать всё содержимое в память.
Если нужен небольшой файл целиком, можно взять готовый список строк.
List<String> lines = Files.readAllLines(path);
readAllLines проще, но читает файл полностью. Files.lines подходит для потоковой обработки, если не забывать закрывать ресурс.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍5🔥4
Напоминалка по устройству Java records!
На картинке показано, из каких частей состоит record и что генерирует компилятор.
Например, запись public record Person(String name, int age) создаёт final-поля, канонический конструктор, методы name(), age(), equals() и hashCode() без ручного шаблонного кода.
Сохрани, чтобы не потерять!
👉 Java Ready | #совет
На картинке показано, из каких частей состоит record и что генерирует компилятор.
Например, запись public record Person(String name, int age) создаёт final-поля, канонический конструктор, методы name(), age(), equals() и hashCode() без ручного шаблонного кода.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10❤6🔥6
Запускаем внешнюю команду через ProcessBuilder!
Иногда Java-приложению нужно вызвать системную утилиту, например git, ffmpeg или собственный скрипт деплоя. Склеивать такую команду в одну строку опасно, особенно если параметры приходят извне.
ProcessBuilder принимает аргументы отдельно. Так пробелы и специальные символы не превращаются в случайный shell-код.
redirectErrorStream(true) объединяет обычный вывод и ошибки. Это не даёт процессу зависнуть, когда буфер stderr заполняется, пока приложение читает только stdout.
После чтения обязательно дождитесь завершения и проверьте код возврата. Нулевой код обычно означает успех.
Для долгих команд добавьте waitFor с таймаутом и уничтожайте процесс при превышении лимита. Так интеграция с внешним инструментом не сможет навсегда заблокировать поток приложения.
👉 Java Ready | #практика
Иногда Java-приложению нужно вызвать системную утилиту, например git, ffmpeg или собственный скрипт деплоя. Склеивать такую команду в одну строку опасно, особенно если параметры приходят извне.
ProcessBuilder принимает аргументы отдельно. Так пробелы и специальные символы не превращаются в случайный shell-код.
var process = new ProcessBuilder(
"git", "status", "--short")
.redirectErrorStream(true)
.start();
redirectErrorStream(true) объединяет обычный вывод и ошибки. Это не даёт процессу зависнуть, когда буфер stderr заполняется, пока приложение читает только stdout.
try (var reader = process.inputReader()) {
var lines = reader.lines().toList();
lines.forEach(System.out::println);
}После чтения обязательно дождитесь завершения и проверьте код возврата. Нулевой код обычно означает успех.
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new IllegalStateException("Command failed");
}
Для долгих команд добавьте waitFor с таймаутом и уничтожайте процесс при превышении лимита. Так интеграция с внешним инструментом не сможет навсегда заблокировать поток приложения.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍4🔥3
Ищем одинаковые файлы на Java!
В папке могут лежать копии одного файла под разными именами. Сделаем небольшую утилиту, которая сравнивает содержимое, а не названия.
В этой задаче:
Результат поможет разобрать архивы, папки и копии.
👉 Java Ready | #задача
В папке могут лежать копии одного файла под разными именами. Сделаем небольшую утилиту, которая сравнивает содержимое, а не названия.
В этой задаче:
• обходим вложенные папки
• считаем SHA-256 потоково
• группируем пути по хешу
• показываем кандидатов на дубликаты
Результат поможет разобрать архивы, папки и копии.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤9👍5🔥4
Почему trim() может не убрать пробелы по краям строки?
В Java часто очищают пользовательский ввод так:
Но trim() ориентируется на символы с кодом не выше U+0020. Некоторые пробельные символы Unicode под это правило не попадают.
Например, строка может начинаться и заканчиваться широким пробелом U+2003:
Видимые на экране отступы останутся. Это может сломать сравнение логина, поиск ключа или проверку поля формы.
Начиная с Java 11 есть strip(), который опирается на определение пробельного символа в Character.isWhitespace:
Если нужна очистка только с одной стороны, есть отдельные методы:
Для проверки строки, состоящей только из пробелов, пригодится isBlank():
strip() не удаляет все символы, которые выглядят как пробелы. Для специальных форматов ввода полезно отдельно определить допустимые символы.
👉 Java Ready | #совет
В Java часто очищают пользовательский ввод так:
String name = input.trim();
Но trim() ориентируется на символы с кодом не выше U+0020. Некоторые пробельные символы Unicode под это правило не попадают.
Например, строка может начинаться и заканчиваться широким пробелом U+2003:
String input = "\u2003admin\u2003";
System.out.println(input.trim().length());
Видимые на экране отступы останутся. Это может сломать сравнение логина, поиск ключа или проверку поля формы.
Начиная с Java 11 есть strip(), который опирается на определение пробельного символа в Character.isWhitespace:
String name = input.strip();
System.out.println(name.equals("admin"));
Если нужна очистка только с одной стороны, есть отдельные методы:
String left = input.stripLeading();
String right = input.stripTrailing();
Для проверки строки, состоящей только из пробелов, пригодится isBlank():
if (input.isBlank()) {
throw new IllegalArgumentException("Empty name");
}strip() не удаляет все символы, которые выглядят как пробелы. Для специальных форматов ввода полезно отдельно определить допустимые символы.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍4🔥4
Собираем Tower Defense с JavaFX и FXGL!
Автор решил попробовать FXGL на проекте и начал с игры, в которой враги идут по маршруту, а игрок расставляет башни. Получился не только экран с графикой, но и небольшой игровой цикл с ресурсами, волнами и улучшениями.
В статье показывают:
• как разложены игровые сущности и компоненты
• что происходит при размещении башни на поле
• как игра проверяет стоимость и доступность покупки
👉 Java Ready | #статья
Автор решил попробовать FXGL на проекте и начал с игры, в которой враги идут по маршруту, а игрок расставляет башни. Получился не только экран с графикой, но и небольшой игровой цикл с ресурсами, волнами и улучшениями.
В статье показывают:
• как разложены игровые сущности и компоненты
• что происходит при размещении башни на поле
• как игра проверяет стоимость и доступность покупки
Продолжай читать на Habr
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6❤2🔥2
Почему kubectl apply ещё не означает, что приложение заработало?
Во время деплоя часто запускают одну команду и считают её успешное завершение концом работы:
Но apply сообщает, что Kubernetes принял описание ресурса. Новые Pod могут ещё создаваться, скачивать образ, ждать readiness probe или падать при запуске.
После apply проверьте именно завершение обновления Deployment:
Команда ждёт завершения rollout и возвращает ошибку, если не дождалась его за указанное время. Название app здесь должно совпадать с именем вашего Deployment.
В скрипте команды удобно поставить рядом:
Теперь пайплайн не продолжит работу после неуспешного ожидания. Само по себе это всё ещё не заменяет проверку приложения снаружи кластера. Сервис, ingress и внешние зависимости могут ломаться отдельно.
Если обновление застряло, сначала посмотрите состояние ресурсов:
Затем откройте события Deployment и причину проблемы у конкретного Pod:
Проблемой может оказаться неверный образ, недоступный секрет, ошибка readiness probe или нехватка ресурсов.
Предыдущую ревизию можно вернуть отдельно:
После отката тоже проверьте rollout status.
➡️ DevOps Ready | #совет
Во время деплоя часто запускают одну команду и считают её успешное завершение концом работы:
kubectl apply -f deployment.yaml
Но apply сообщает, что Kubernetes принял описание ресурса. Новые Pod могут ещё создаваться, скачивать образ, ждать readiness probe или падать при запуске.
После apply проверьте именно завершение обновления Deployment:
kubectl rollout status deployment/app --timeout=120s
Команда ждёт завершения rollout и возвращает ошибку, если не дождалась его за указанное время. Название app здесь должно совпадать с именем вашего Deployment.
В скрипте команды удобно поставить рядом:
set -e
kubectl apply -f deployment.yaml
kubectl rollout status deployment/app --timeout=120s
Теперь пайплайн не продолжит работу после неуспешного ожидания. Само по себе это всё ещё не заменяет проверку приложения снаружи кластера. Сервис, ingress и внешние зависимости могут ломаться отдельно.
Если обновление застряло, сначала посмотрите состояние ресурсов:
kubectl get deployment app
kubectl get pods -l app=app
Затем откройте события Deployment и причину проблемы у конкретного Pod:
kubectl describe deployment app
kubectl describe pod POD_NAME
Проблемой может оказаться неверный образ, недоступный секрет, ошибка readiness probe или нехватка ресурсов.
Предыдущую ревизию можно вернуть отдельно:
kubectl rollout undo deployment/app
После отката тоже проверьте rollout status.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍2🔥2
Шпаргалка по sealed-иерархиям в Java!
На картинке показано, как sealed-класс ограничивает прямых наследников. Одни ветки закрываются через final, другая остаётся контролируемой через sealed, а non-sealed снова разрешает свободное наследование.
Например, для фиксированного набора фигур можно явно перечислить допустимые реализации Shape. Это помогает выразить границы модели прямо в типах и облегчает проверку вариантов при работе с pattern matching.
Сохрани, чтобы не потерять!
👉 Java Ready | #ресурс
На картинке показано, как sealed-класс ограничивает прямых наследников. Одни ветки закрываются через final, другая остаётся контролируемой через sealed, а non-sealed снова разрешает свободное наследование.
Например, для фиксированного набора фигур можно явно перечислить допустимые реализации Shape. Это помогает выразить границы модели прямо в типах и облегчает проверку вариантов при работе с pattern matching.
Сохрани, чтобы не потерять!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍2🔥2
Следим за появлением файлов в папке через WatchService!
Создадим наблюдатель и зарегистрируем каталог. Папка должна существовать заранее:
Константы ENTRY_CREATE и ENTRY_MODIFY берутся из StandardWatchEventKinds. try-with-resources закроет наблюдатель при выходе из блока.
Дальше ждём сигнал. Метод take блокирует поток, пока событие не появится:
Контекст события содержит имя относительно наблюдаемой папки, а не готовый абсолютный путь. Не подставляй его отдельно от dir:
После обработки обязательно сбросим ключ. Если каталог удалён или больше недоступен, reset вернёт false:
События могут повторяться, а при перегрузке наблюдатель сообщит OVERFLOW. Поэтому важную обработку лучше делать идемпотентной и предусмотреть повторное сканирование каталога после переполнения.
👉 Java Ready | #практика
Создадим наблюдатель и зарегистрируем каталог. Папка должна существовать заранее:
Path dir = Path.of("incoming");
try (WatchService watcher = FileSystems.getDefault().newWatchService()) {
dir.register(watcher, ENTRY_CREATE, ENTRY_MODIFY);Константы ENTRY_CREATE и ENTRY_MODIFY берутся из StandardWatchEventKinds. try-with-resources закроет наблюдатель при выходе из блока.
Дальше ждём сигнал. Метод take блокирует поток, пока событие не появится:
while (true) {
WatchKey key = watcher.take();
for (WatchEvent<?> event : key.pollEvents()) {Контекст события содержит имя относительно наблюдаемой папки, а не готовый абсолютный путь. Не подставляй его отдельно от dir:
if (event.kind() == OVERFLOW) continue;
Path file = dir.resolve((Path) event.context());
System.out.println(event.kind() + " " + file);
}
После обработки обязательно сбросим ключ. Если каталог удалён или больше недоступен, reset вернёт false:
if (!key.reset()) break;
}
}
События могут повторяться, а при перегрузке наблюдатель сообщит OVERFLOW. Поэтому важную обработку лучше делать идемпотентной и предусмотреть повторное сканирование каталога после переполнения.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤8👍4🔥2
Находим три самых популярных товара!
Есть поток покупок с повторяющимися названиями. Построим небольшую сводку, которая считает частоты и показывает лидеров.
В этой задаче:
Когда данных станет очень много, вместо полной сортировки можно оставить только три записи в маленькой куче.
👉 Java Ready | #задача
Есть поток покупок с повторяющимися названиями. Построим небольшую сводку, которая считает частоты и показывает лидеров.
В этой задаче:
• собираем счётчики через Map.merge
• сортируем товары по частоте
• оставляем топ-3 и печатаем результат
Когда данных станет очень много, вместо полной сортировки можно оставить только три записи в маленькой куче.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2🔥2👍1