Guard-методы и параметризация
До появления широкого использования SLF4J распространенным паттерном был явной guard:
Этот подход решает проблему конкатенации, но загромождает код и нарушает единообразие. Параметризованные сообщения устраняют необходимость в guard для простых случаев, так как внутренняя проверка уровня выполняется автоматически до форматирования.
Guard остается оправдан только при дорогостоящем вычислении аргумента:
Здесь даже параметризация не спасет, потому что
Исключения и параметризация
Особый случай — логирование исключений. SLF4J распознает последний аргумент типа
В параметризованном вызове последний
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
До появления широкого использования SLF4J распространенным паттерном был явной guard:
if (logger.isDebugEnabled()) {
logger.debug("User " + userId + " not found");
}Этот подход решает проблему конкатенации, но загромождает код и нарушает единообразие. Параметризованные сообщения устраняют необходимость в guard для простых случаев, так как внутренняя проверка уровня выполняется автоматически до форматирования.
Guard остается оправдан только при дорогостоящем вычислении аргумента:
// Аргумент требует сериализации — guard необходим
if (logger.isDebugEnabled()) {
logger.debug("Full state: {}", objectMapper.writeValueAsString(complexObject));
}
Здесь даже параметризация не спасет, потому что
writeValueAsString выполняется до вызова логгера как частичное вычисление аргумента. SLF4J не может отложить выполнение произвольного выражения.Исключения и параметризация
Особый случай — логирование исключений. SLF4J распознает последний аргумент типа
Throwable и обрабатывает его отдельно от параметров:// Правильно: throwable логируется со стектрейсом
logger.error("Payment {} failed for user {}", paymentId, userId, exception);
// Неправильно: исключение превращается в toString(), стектрейс потерян
logger.error("Payment " + paymentId + " failed: " + exception.getMessage());
В параметризованном вызове последний
Throwable не подставляется в шаблон, а передается в appender для вывода полного стектрейса. При конкатенации разработчик часто ограничивается exception.getMessage(), теряя критически важную информацию о месте возникновения и цепочке вызовов.#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍5
Напоминаю, что набираю на обучение желающих погрузиться в мир Java! 🤓
Пишите в лс @Oleborn, все обсудим.😉
Пишите в лс @Oleborn, все обсудим.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
Что выведет код?
#Tasks
public class Task180526 {
public static void main(String[] args) {
String a = "hello";
String b = "world";
String c = a + b;
String d = "hello" + "world";
System.out.println(c == d);
System.out.println(c.intern() == d);
System.out.println((a + b).intern() == d);
}
}#Tasks
👍3
Варианты ответа:
Anonymous Quiz
26%
true true true
17%
false true true
22%
false false true
35%
true false true
👍4
Java for Beginner
Keycloak с нуля: от первого токена до современной auth-архитектуры Осваиваем Keycloak на практике: запуск, все способы аутентификации, роли, федерация, безопасность и кластеризация. Строим два Spring Boot сервиса и разбираемся, как устроена современная auth…
Ребят дайте обратную связь, как вам видео?🤨
Что такое System.arraycopy()? Чем отличается от Arrays.copyOf() 🤓
Ответ:
System.arraycopy() — это нативный метод, выполняющий быстрое копирование элементов из одного массива в другой.
Параметры: исходный массив, начальная позиция в нем, целевой массив, начальная позиция в нем, количество копируемых элементов.
Важно: целевой массив должен существовать и иметь достаточный размер.
Arrays.copyOf() — более высокоуровневый метод, который создает новый массив внутри себя, используя System.arraycopy(). Также позволяет изменить длину копии (обрезать или дополнить значениями по умолчанию).
#собеседование
Ответ:
System.arraycopy() — это нативный метод, выполняющий быстрое копирование элементов из одного массива в другой.
Параметры: исходный массив, начальная позиция в нем, целевой массив, начальная позиция в нем, количество копируемых элементов.
Важно: целевой массив должен существовать и иметь достаточный размер.
Arrays.copyOf() — более высокоуровневый метод, который создает новый массив внутри себя, используя System.arraycopy(). Также позволяет изменить длину копии (обрезать или дополнить значениями по умолчанию).
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
Готовлю новую статью))
Как считаете не слишком пафосно и кликбейтно? 😂😂😂
Но я все равно поржал от генераторов картинок😂 😂 😂
Как считаете не слишком пафосно и кликбейтно? 😂😂😂
Но я все равно поржал от генераторов картинок
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥2
История технологии сегодня — 19 мая
ℹ️ Кто родился в этот день
Гэри Арлен Килдалл (19 мая 1942, Сиэтл, Вашингтон — 11 июля 1994, Монтерей, Калифорния) — программист и предприниматель, создавший операционную систему CP/M и основавший Digital Research, Inc. (DRI). Килдалл был одним из первых, кто увидел потенциал микропроцессоров не только в качестве контроллеров оборудования, но и как часть мощного персонального компьютера.
🌐 Знаковые события
1910 — возвращение кометы Галлея: Земля пересекла хвост кометы.
1980 - в Анахайме, Калифорния, Apple представил публике свою новую разработку — компьютер «Apple III». Это стало первой неудачей известной фирмы.
#Biography #Birth_Date #Events #19мая
Гэри Арлен Килдалл (19 мая 1942, Сиэтл, Вашингтон — 11 июля 1994, Монтерей, Калифорния) — программист и предприниматель, создавший операционную систему CP/M и основавший Digital Research, Inc. (DRI). Килдалл был одним из первых, кто увидел потенциал микропроцессоров не только в качестве контроллеров оборудования, но и как часть мощного персонального компьютера.
1910 — возвращение кометы Галлея: Земля пересекла хвост кометы.
1980 - в Анахайме, Калифорния, Apple представил публике свою новую разработку — компьютер «Apple III». Это стало первой неудачей известной фирмы.
#Biography #Birth_Date #Events #19мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
[Совет по Java #039]
Тема:
Проблема: Метод
Разработчики, незнакомые с этой особенностью, ожидают простого разделения по литералу и получают неожиданные или пустые результаты.
Решение: Используйте
Альтернативно, используйте
Объяснение: Регулярные выражения используют множество метасимволов.
Точка (
#Java #советы
Тема:
String.split() принимает регулярное выражение.Проблема: Метод
String.split(String regex) интерпретирует аргумент как регулярное выражение (regex), а не как литеральную строку. Символ точки (.) в regex означает "любой символ". Поэтому вызов "a.b.c".split(".") разделит строку по каждому символу, а не по точкам, вернув пустой массив. Аналогичные проблемы возникают с другими спецсимволами: $, |, *, +, ?, ^, (, ), [, {. Разработчики, незнакомые с этой особенностью, ожидают простого разделения по литералу и получают неожиданные или пустые результаты.
Решение: Используйте
Pattern.quote() для экранирования всей строки или экранируйте отдельные символы двойным обратным слешем (\\., \\|). Для простых односимвольных разделителей можно использовать split(Pattern.quote(".")). Если разделитель не является regex-спецсимволом (например, запятая или пробел), экранирование не требуется. Альтернативно, используйте
StringUtils.split() из Apache Commons Lang, который работает с литералами.public class StringSplitRegex {
public static void main(String[] args) {
String ip = "192.168.1.1";
String csv = "a|b|c";
String math = "10*20*30";
//Антипаттерн: без экранирования
String[] badSplit = ip.split(".");
System.out.println("split(\".\") length: " + badSplit.length); // 0
// Регулярка '.' совпала с каждым символом, результат пустой
String[] badPipe = csv.split("|");
System.out.println("split(\"|\") length: " + badPipe.length); // 7
// '|' в regex означает "или" — результат каждый символ
//Решение 1: экранирование двойным слешем
String[] goodDot = ip.split("\\.");
System.out.println("split(\"\\\\.\") : " + String.join(", ", goodDot));
String[] goodPipe = csv.split("\\|");
System.out.println("split(\"\\\\|\") : " + String.join(", ", goodPipe));
//Решение 2: Pattern.quote() — экранирует всё
String[] quoted = ip.split(Pattern.quote("."));
System.out.println("Pattern.quote(\".\") : " + String.join(", ", quoted));
//Решение 3: для сложных случаев — ограничение на количество частей
String[] limited = "one:two:three:four".split(":", 3);
System.out.println("split with limit: " + String.join(", ", limited)); // [one, two, three:four]
// Альтернатива: ручная работа без regex
String[] manual = "one,two,three".split(",", -1); // -1 сохраняет пустые хвосты
System.out.println("Manual: " + String.join(", ", manual));
// Внимание: обратный слеш требует четыре слеша в Java
String path = "C:\\Users\\Name\\file.txt";
String[] pathParts = path.split("\\\\"); // \\\\ экранирует один \
System.out.println("Path parts: " + String.join(" | ", pathParts));
}
}Объяснение: Регулярные выражения используют множество метасимволов.
Точка (
.) — самый частый подвох. Двойной обратный слеш (\\.) нужен потому, что Java требует экранирования обратного слеша в строковом литерале: первый слеш экранирует второй, и в regex передается \., что означает "буквальная точка".
Pattern.quote() автоматически добавляет \Q и \E вокруг строки, что указывает regex-движку интерпретировать содержимое буквально. Это наиболее безопасный способ при динамических разделителях. Параметр limit в split() управляет количеством частей: отрицательное значение сохраняет пустые строки в конце, ноль (по умолчанию) — удаляет.#Java #советы
👍3
Что выведет код?
#Tasks
import java.util.Arrays;
public class Task190526 {
public static void main(String[] args) {
String str = "1.2.3.";
String[] parts = str.split(".");
System.out.println(parts.length);
System.out.println(Arrays.toString(parts));
}
}
#Tasks
👍2
👍4
Что такое CAS (Compare-And-Swap) операции? 🤓
Ответ:
CAS — это атомарная инструкция процессора, которая сравнивает значение в памяти с ожидаемым значением, и если они равны, заменяет его на новое.
Выполняется атомарно (одна инструкция).
В Java CAS реализован через sun.misc.Unsafe и используется в атомарных классах (AtomicInteger, AtomicLong, AtomicReference) и в ConcurrentHashMap.
CAS — основа неблокирующих (lock-free) алгоритмов, которые работают быстрее synchronized при низкой конкуренции, так как не переводят поток в режим ожидания.
#собеседование
Ответ:
CAS — это атомарная инструкция процессора, которая сравнивает значение в памяти с ожидаемым значением, и если они равны, заменяет его на новое.
Выполняется атомарно (одна инструкция).
В Java CAS реализован через sun.misc.Unsafe и используется в атомарных классах (AtomicInteger, AtomicLong, AtomicReference) и в ConcurrentHashMap.
CAS — основа неблокирующих (lock-free) алгоритмов, которые работают быстрее synchronized при низкой конкуренции, так как не переводят поток в режим ожидания.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
Java for Beginner
Напоминаю, что набираю на обучение желающих погрузиться в мир Java! 🤓 Пишите в лс @Oleborn, все обсудим. 😉
Напоминаю, что продолжаю набор! Пишите в лс @oleborn!
История технологии сегодня — 20 мая
ℹ️ Кто родился в этот день
Исаа́к (Ю́зик) Я́ковлевич Померанчу́к (7 (20) мая 1913, Варшава — 14 декабря 1966, Москва) — советский физик-теоретик, академик АН СССР (1964; член-корреспондент 1953).
Уильям Реддингтон Хьюлетт (англ. William Reddington Hewlett, 20 мая 1913 — 12 января 2001) — американский инженер, соучредитель компании «Hewlett-Packard» (HP, вместе с Дэвидом Паккардом).
Эмиль Берлинер (англ. Emile Berliner; 20 мая 1851, Ганновер — 3 августа 1931, Вашингтон) — американский изобретатель граммофона и микрофона, конструктор летательных аппаратов и общественный деятель.
🌐 Знаковые события
1891 — изобретатель Томас Эдисон показал общественности кинетоскоп, машину движущегося изображения.
1977 — первый полёт советского истребителя четвёртого поколения Су-27.
#Biography #Birth_Date #Events #20мая
Исаа́к (Ю́зик) Я́ковлевич Померанчу́к (7 (20) мая 1913, Варшава — 14 декабря 1966, Москва) — советский физик-теоретик, академик АН СССР (1964; член-корреспондент 1953).
Уильям Реддингтон Хьюлетт (англ. William Reddington Hewlett, 20 мая 1913 — 12 января 2001) — американский инженер, соучредитель компании «Hewlett-Packard» (HP, вместе с Дэвидом Паккардом).
Эмиль Берлинер (англ. Emile Berliner; 20 мая 1851, Ганновер — 3 августа 1931, Вашингтон) — американский изобретатель граммофона и микрофона, конструктор летательных аппаратов и общественный деятель.
1891 — изобретатель Томас Эдисон показал общественности кинетоскоп, машину движущегося изображения.
1977 — первый полёт советского истребителя четвёртого поколения Су-27.
#Biography #Birth_Date #Events #20мая
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Раздел 9. Исключения, логирование, отладка
Глава 2. Логирование (Logging)
Логирование исключений — правильная передача throwable последним параметром
SLF4J анализирует последний аргумент метода логирования. Если он является экземпляром
Здесь
Механизм работает для любого количества параметров.
При одном аргументе-исключении и отсутствии placeholder-ов SLF4J использует сообщение исключения как текст лога и дополняет его стектрейсом:
Проблема logger.error(e.getMessage(), e)
Этот паттерн встречается в коде, где разработчик хочет, чтобы текст лога совпадал с сообщением исключения.
Однако он порождает несколько проблем:
Дублирование сообщения. Если layout настроен на вывод
Первая строка повторяет содержимое второй, увеличивая объем лога без добавления информации.
Потеря контекста.
Риск null-сообщения. Не все исключения имеют непустое сообщение.
Невозможность параметризации. Форма
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
Глава 2. Логирование (Logging)
Логирование исключений — правильная передача throwable последним параметром
SLF4J анализирует последний аргумент метода логирования. Если он является экземпляром
java.lang.Throwable, фреймворк обрабатывает его отдельно от параметров подстановки: исключение передается в appender для вывода полного стектрейса, а не встраивается в текст сообщения через {}.// Правильно: throwable — последний параметр, SLF4J выведет стектрейс
logger.error("Payment processing failed for order {}", orderId, exception);
Здесь
orderId подставляется в {}, а exception передается как объект Throwable. Logback или Log4j2 извлекают из него класс, сообщение и полный стектрейс, форматируя их согласно layout-конфигурации.Механизм работает для любого количества параметров.
При одном аргументе-исключении и отсутствии placeholder-ов SLF4J использует сообщение исключения как текст лога и дополняет его стектрейсом:
// SLF4J интерпретирует exception как Throwable, а не как параметр подстановки
logger.error("Database connection lost", exception);
Проблема logger.error(e.getMessage(), e)
Этот паттерн встречается в коде, где разработчик хочет, чтобы текст лога совпадал с сообщением исключения.
Однако он порождает несколько проблем:
Дублирование сообщения. Если layout настроен на вывод
%ex или %exception, стектрейс начинается с имени класса исключения и его getMessage(). Таким образом, сообщение исключения появляется дважды: в заголовке лога и в начале стектрейса.// Вывод при logger.error(e.getMessage(), e)
2024-01-15 10:23:14 ERROR Connection timeout after 30000ms
java.net.SocketTimeoutException: Connection timeout after 30000ms
at java.net.SocketInputStream.socketRead0(Native Method)
...
Первая строка повторяет содержимое второй, увеличивая объем лога без добавления информации.
Потеря контекста.
e.getMessage() часто содержит только техническое описание, лишенное бизнес-контекста. Сравните:// Антипаттерн: что за заказ? какой шлюз?
logger.error(e.getMessage(), e);
// Правильно: контекст в сообщении, детали в стектрейсе
logger.error("Payment failed for order {} via gateway {}", orderId, gatewayId, e);
Риск null-сообщения. Не все исключения имеют непустое сообщение.
NullPointerException без кастомного сообщения вернет null, и logger.error(null, e) приведет к неинформативной строке null в заголовке лога.Невозможность параметризации. Форма
logger.error(e.getMessage(), e) не позволяет добавить параметры контекста, так как место для {} занято самим сообщением исключения.#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍4
Правильный паттерн: контекст + throwable
Рекомендуемый подход — формировать описательное сообщение с бизнес-контекстом, передавая исключение последним параметром:
В этом примере заголовок лога содержит все параметры операции, позволяя оператору понять, какой именно перевод не удался, не разворачивая стектрейс. Стектрейс доступен для детального анализа, но не загромождает основное сообщение.
Особый случай: логирование без дополнительного контекста
Если метод перехватывает исключение только для логирования перед повторным выбросом, и дополнительного контекста не требуется, достаточно передать само исключение:
Здесь
Логирование исключений в Stream API и лямбдах
При обработке коллекций часто требуется логировать ошибку для конкретного элемента, но продолжить обработку остальных. Исключение передается в логгер стандартным образом:
Важно: при логировании внутри catch-блока исключение должно оставаться доступным для дальнейшей обработки. Если метод глотает исключение без логирования или повторного выброса, информация о сбое теряется безвозвратно.
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
Рекомендуемый подход — формировать описательное сообщение с бизнес-контекстом, передавая исключение последним параметром:
public void transferFunds(String fromAccount, String toAccount, BigDecimal amount) {
try {
bankingGateway.transfer(fromAccount, toAccount, amount);
logger.info("Transfer completed: {} -> {}, amount {}", fromAccount, toAccount, amount);
} catch (BankingException e) {
logger.error("Transfer failed: {} -> {}, amount {}, reason: {}",
fromAccount, toAccount, amount, e.getMessage(), e);
}
}В этом примере заголовок лога содержит все параметры операции, позволяя оператору понять, какой именно перевод не удался, не разворачивая стектрейс. Стектрейс доступен для детального анализа, но не загромождает основное сообщение.
Особый случай: логирование без дополнительного контекста
Если метод перехватывает исключение только для логирования перед повторным выбросом, и дополнительного контекста не требуется, достаточно передать само исключение:
try {
executeOperation();
} catch (IOException e) {
logger.error("Operation failed", e);
throw new ServiceException("Execution error", e);
}Здесь
"Operation failed" — это статический префикс, а вся диагностическая информация содержится в стектрейсе исключения. Это допустимо, когда исключение само по себе достаточно информативно и уже содержит все необходимые детали.Логирование исключений в Stream API и лямбдах
При обработке коллекций часто требуется логировать ошибку для конкретного элемента, но продолжить обработку остальных. Исключение передается в логгер стандартным образом:
List<String> processed = items.stream()
.map(item -> {
try {
return processor.process(item);
} catch (ProcessingException e) {
logger.warn("Skipping item {}: {}", item.getId(), e.getMessage(), e);
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
Важно: при логировании внутри catch-блока исключение должно оставаться доступным для дальнейшей обработки. Если метод глотает исключение без логирования или повторного выброса, информация о сбое теряется безвозвратно.
#Java #для_новичков #beginner #logging #Log4j2 #Logback #SLF4J
👍4
Что выведет код?
#Tasks
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Task200526 {
private static final Logger log = LoggerFactory.getLogger(Task200526.class);
public static void main(String[] args) {
try {
throw new RuntimeException("BOOM");
} catch (Exception e) {
log.error("Error occurred: {}", e);
}
}
}
#Tasks
👍4
Что такое ForkJoinPool и RecursiveTask? 🤓
Ответ:
ForkJoinPool — это специальный пул потоков, реализующий алгоритм work-stealing (воровства задач).
Каждый поток имеет свою очередь задач. Когда поток завершает свои задачи, он может "украсть" задачу из очереди другого потока.
RecursiveTask<V> — это абстрактный класс для задач, которые возвращают результат и могут разделяться (fork) на подзадачи и объединяться (join).
Классический пример — рекурсивные алгоритмы, такие как быстрая сортировка, слияние массивов, вычисление чисел Фибоначчи. Используется в parallelStream().
#собеседование
Ответ:
ForkJoinPool — это специальный пул потоков, реализующий алгоритм work-stealing (воровства задач).
Каждый поток имеет свою очередь задач. Когда поток завершает свои задачи, он может "украсть" задачу из очереди другого потока.
RecursiveTask<V> — это абстрактный класс для задач, которые возвращают результат и могут разделяться (fork) на подзадачи и объединяться (join).
Классический пример — рекурсивные алгоритмы, такие как быстрая сортировка, слияние массивов, вычисление чисел Фибоначчи. Используется в parallelStream().
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4