Что выведет код?
#Tasks
public class Task200426 {
public static void main(String[] args) {
try {
method();
} catch (Exception e) {
System.out.println("Caught: " + e.getMessage());
}
}
static void method() throws Exception {
try {
throw new RuntimeException("Inner");
} catch (RuntimeException e) {
System.out.println("Inside catch");
throw new Exception("Outer");
}
}
}#Tasks
👍1
Как работает JIT-компилятор (Just-In-Time)? 🤓
Ответ:
JIT-компилятор — это часть JVM, которая переводит байт-код в машинный код во время выполнения для повышения производительности.
Когда метод выполняется часто (становится "горячим"), JIT компилирует его в нативный код, который выполняется напрямую процессором, а не интерпретируется.
В HotSpot JVM есть два JIT-компилятора: C1 (Client) для быстрого старта и C2 (Server) для агрессивной оптимизации в долгоиграющих приложениях. Tiered Compilation (уровневая компиляция) использует оба.
#собеседование
Ответ:
Когда метод выполняется часто (становится "горячим"), JIT компилирует его в нативный код, который выполняется напрямую процессором, а не интерпретируется.
В HotSpot JVM есть два JIT-компилятора: C1 (Client) для быстрого старта и C2 (Server) для агрессивной оптимизации в долгоиграющих приложениях. Tiered Compilation (уровневая компиляция) использует оба.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологии сегодня — 21 апреля
ℹ️ Кто родился в этот день
Пе́рси Уи́льямс Бри́джмен (Бри́джман) (англ. Percy Williams Bridgman; 21 апреля 1882, Кембридж, Массачусетс — 20 августа 1961, Рэндольф[англ.], Нью-Гемпшир) — американский физик, лауреат Нобелевской премии по физике в 1946 году «за изобретение прибора, позволяющего создавать сверхвысокие давления, и за открытия, сделанные в связи с этим в физике высоких давлений».
В 1905 году он начал исследования некоторых явлений при высоких давлениях. Из-за поломки установки ему пришлось изменить её, в результате чего он изобрёл новый блок (систему двойного сжатия — компрессор, действующий внутри сосуда высокого давления), позволявший получать давления до 100 тысяч атмосфер (10 ГПа), рекордным стало достижение рубежа 400 000 атм[6]. Такие давления стали огромным достижением по сравнению с теми, которые достигались до того — 3000 атмосфер (0.3 ГПа). Также его имя известно в связи с прокладкой Бриджмена (выполненная из резины или мягкого металла, сжатая под давлением, большим, чем в перекрытом ею сосуде с газом, она автоматически уплотнялась при возрастании давления и не давала течи) и термодинамическим уравнением Бриджмена.
🌐 Знаковые события
1964 — при неудачной попытке запуска американского навигационного спутника «Транзит-5В» с ядерной энергетической установкой SNAP-9A на борту, находившиеся в ней 950 граммов плутония-238 рассеялись в земной атмосфере, вызвав существенное повышение естественного радиационного фона.
2005 — Компания AMD начала поставки двухъядерных процессоров Opteron.
#Biography #Birth_Date #Events #21апреля
Пе́рси Уи́льямс Бри́джмен (Бри́джман) (англ. Percy Williams Bridgman; 21 апреля 1882, Кембридж, Массачусетс — 20 августа 1961, Рэндольф[англ.], Нью-Гемпшир) — американский физик, лауреат Нобелевской премии по физике в 1946 году «за изобретение прибора, позволяющего создавать сверхвысокие давления, и за открытия, сделанные в связи с этим в физике высоких давлений».
В 1905 году он начал исследования некоторых явлений при высоких давлениях. Из-за поломки установки ему пришлось изменить её, в результате чего он изобрёл новый блок (систему двойного сжатия — компрессор, действующий внутри сосуда высокого давления), позволявший получать давления до 100 тысяч атмосфер (10 ГПа), рекордным стало достижение рубежа 400 000 атм[6]. Такие давления стали огромным достижением по сравнению с теми, которые достигались до того — 3000 атмосфер (0.3 ГПа). Также его имя известно в связи с прокладкой Бриджмена (выполненная из резины или мягкого металла, сжатая под давлением, большим, чем в перекрытом ею сосуде с газом, она автоматически уплотнялась при возрастании давления и не давала течи) и термодинамическим уравнением Бриджмена.
1964 — при неудачной попытке запуска американского навигационного спутника «Транзит-5В» с ядерной энергетической установкой SNAP-9A на борту, находившиеся в ней 950 граммов плутония-238 рассеялись в земной атмосфере, вызвав существенное повышение естественного радиационного фона.
2005 — Компания AMD начала поставки двухъядерных процессоров Opteron.
#Biography #Birth_Date #Events #21апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
[Совет по Java #028]
Тема: static-методы не переопределяются.
Проблема: Статические методы принадлежат классу, а не экземпляру. Они не участвуют в полиморфизме времени выполнения (динамическом связывании).
Выбор вызываемого статического метода определяется на этапе компиляции по типу ссылки, а не по фактическому типу объекта. Это приводит к неожиданному поведению: при вызове статического метода через ссылку на родительский класс, который указывает на объект дочернего класса, будет выполнен метод родителя, даже если в дочернем классе объявлен метод с такой же сигнатурой.
Такая ситуация называется сокрытие (hiding), а не переопределение (overriding). Разработчики, привыкшие к полиморфизму экземплярных методов, часто делают ошибку, полагая, что статические методы ведут себя аналогично.
Решение: Никогда не вызывайте статические методы через объекты или ссылки. Всегда вызывайте их через имя класса: Parent.staticMethod(). Если вам нужно разное поведение в иерархии, используйте экземплярные методы или паттерн Стратегия.
Предупреждайте коллег в команде о том, что статические методы не переопределяются. Для ясности кода помечайте статические методы как static и избегайте вызова через переменные.
Объяснение: При компиляции вызова p.print() компилятор заменяет его на Parent.print(), так как тип переменной p — Parent.
Информация о фактическом типе объекта (Child) не используется для разрешения статического метода. Сокрытие (hiding) означает, что в классе-наследнике объявлен свой статический метод, но он никак не связан с методом родителя. Более того, статический метод можно вызвать даже на null-ссылке, если тип известен компилятору.
Это еще раз подчеркивает, что статические методы связаны с классом, а не с объектом.
#Java #советы
Тема: static-методы не переопределяются.
Проблема: Статические методы принадлежат классу, а не экземпляру. Они не участвуют в полиморфизме времени выполнения (динамическом связывании).
Выбор вызываемого статического метода определяется на этапе компиляции по типу ссылки, а не по фактическому типу объекта. Это приводит к неожиданному поведению: при вызове статического метода через ссылку на родительский класс, который указывает на объект дочернего класса, будет выполнен метод родителя, даже если в дочернем классе объявлен метод с такой же сигнатурой.
Такая ситуация называется сокрытие (hiding), а не переопределение (overriding). Разработчики, привыкшие к полиморфизму экземплярных методов, часто делают ошибку, полагая, что статические методы ведут себя аналогично.
Решение: Никогда не вызывайте статические методы через объекты или ссылки. Всегда вызывайте их через имя класса: Parent.staticMethod(). Если вам нужно разное поведение в иерархии, используйте экземплярные методы или паттерн Стратегия.
Предупреждайте коллег в команде о том, что статические методы не переопределяются. Для ясности кода помечайте статические методы как static и избегайте вызова через переменные.
public class StaticOverrideExample {
static class Parent {
public static void print() {
System.out.println("Parent static method");
}
public void instanceMethod() {
System.out.println("Parent instance method");
}
}
static class Child extends Parent {
// Это не переопределение, а сокрытие (hiding)
public static void print() {
System.out.println("Child static method");
}
@Override // А это корректное переопределение
public void instanceMethod() {
System.out.println("Child instance method");
}
}
public static void main(String[] args) {
Parent p = new Child();
//Антипаттерн: вызов статического метода через переменную
p.print(); // Вывод: "Parent static method" — неожиданно!
// Компилятор смотрит на тип переменной Parent, а не на объект Child
//Правильно: вызов через класс
Parent.print(); // Parent static method
Child.print(); // Child static method
// Для сравнения: экземплярный метод ведет себя полиморфно
p.instanceMethod(); // Вывод: "Child instance method" — ожидаемо
// Демонстрация опасности
Parent nullRef = null;
nullRef.print(); // Работает! (тип известен на этапе компиляции)
// nullRef.instanceMethod(); // NullPointerException
}
}Объяснение: При компиляции вызова p.print() компилятор заменяет его на Parent.print(), так как тип переменной p — Parent.
Информация о фактическом типе объекта (Child) не используется для разрешения статического метода. Сокрытие (hiding) означает, что в классе-наследнике объявлен свой статический метод, но он никак не связан с методом родителя. Более того, статический метод можно вызвать даже на null-ссылке, если тип известен компилятору.
Это еще раз подчеркивает, что статические методы связаны с классом, а не с объектом.
#Java #советы
👍4
Что выведет код?
#Tasks
class Parent210426 {
static String get() { return "Parent"; }
String nonStatic() { return "ParentNS"; }
}
class Child210426 extends Parent210426 {
static String get() { return "Child"; }
String nonStatic() { return "ChildNS"; }
}
public class Task210426 {
public static void main(String[] args) {
Parent210426 p = new Child210426();
System.out.println(p.get());
System.out.println(((Child210426) p).get());
System.out.println(p.nonStatic());
}
}#Tasks
👍2
Варианты ответа:
Anonymous Quiz
57%
Parent Child ChildNS
7%
Child Child ChildNS
14%
Parent Parent ParentNS
21%
Child Parent ChildNS
👍2
Уффф... 🥵
Я накидал неплохое такое обновление чата в devforge.ru🧑💻
Теперь в чате можно и позависать)
Жду всех там!✈️
Я накидал неплохое такое обновление чата в devforge.ru
Теперь в чате можно и позависать)
Жду всех там!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Что такое OSGi? 🤓
Ответ:
OSGi (Open Service Gateway initiative) — это модульная система и сервисная платформа для Java.
Она позволяет разбивать приложение на связанные (bundles) — динамически загружаемые модули. Каждый bundle — это JAR-файл с особой структурой MANIFEST.MF, где явно описано, какие пакеты он экспортирует (делает публичными) и какие импортирует.
OSGi обеспечивает динамическое управление жизненным циклом модулей (можно устанавливать, обновлять, останавливать модули на ходу) и строгую инкапсуляцию на уровне JAR-файлов.
#собеседование
Ответ:
Она позволяет разбивать приложение на связанные (bundles) — динамически загружаемые модули. Каждый bundle — это JAR-файл с особой структурой MANIFEST.MF, где явно описано, какие пакеты он экспортирует (делает публичными) и какие импортирует.
OSGi обеспечивает динамическое управление жизненным циклом модулей (можно устанавливать, обновлять, останавливать модули на ходу) и строгую инкапсуляцию на уровне JAR-файлов.
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История технологии сегодня — 22 апреля
ℹ️ Кто родился в этот день
И́горь Анато́льевич Дани́лов (род. 22 апреля 1964, Ленинград) — российский программист, автор популярного антивируса Dr. Web, технический директор и основатель компании «Доктор Веб». Свой первый вирусный анализатор Игорь Данилов написал из энтузиазма в желании избавить свой НИИ от вирусных угроз. В 1992 начал разработку антивируса Dr.Web, а в 1993 году Dr.Web стал первой антивирусной программой, распознавшей и уничтожившей полиморфный вирус, что принесло ему известность в среде мировых разработчиков антивирусных средств и специалистов по борьбе с вирусами. В 2003 основал компанию «Доктор Веб».
Джу́лиус Ро́берт О́ппенге́ймер (англ. Julius Robert Oppenheimer; 22 апреля 1904, Нью-Йорк, США — 18 февраля 1967, Принстон, штат Нью-Джерси, США) — американский физик-теоретик и физик-ядерщик, широко известен как научный руководитель Манхэттенского проекта, в рамках которого в годы Второй мировой войны разрабатывались первые образцы ядерного оружия; из-за этого Оппенгеймера, наряду со Станиславом Уламом и Эдвардом Теллером часто называют «отцом атомной бомбы».
Сэмюэл Харрис Альтман (также Олтмен; англ. Samuel Harris Altman, МФА: /ˈɔːltmən/; род. 22 апреля 1985, Чикаго, Иллинойс) — американский предприниматель, инвестор, программист и блогер. С 2014 года и до увольнения в 2019-м был президентом Y Combinator, после чего стал генеральным директором OpenAI. В декабре 2025 года американский журнал Time назвал его человеком года, как одного из создателей систем искусственного интеллекта.
🌐 Знаковые события
1993 — вышла первая версия веб-браузера Mosaic.
#Biography #Birth_Date #Events #22апреля
И́горь Анато́льевич Дани́лов (род. 22 апреля 1964, Ленинград) — российский программист, автор популярного антивируса Dr. Web, технический директор и основатель компании «Доктор Веб». Свой первый вирусный анализатор Игорь Данилов написал из энтузиазма в желании избавить свой НИИ от вирусных угроз. В 1992 начал разработку антивируса Dr.Web, а в 1993 году Dr.Web стал первой антивирусной программой, распознавшей и уничтожившей полиморфный вирус, что принесло ему известность в среде мировых разработчиков антивирусных средств и специалистов по борьбе с вирусами. В 2003 основал компанию «Доктор Веб».
Джу́лиус Ро́берт О́ппенге́ймер (англ. Julius Robert Oppenheimer; 22 апреля 1904, Нью-Йорк, США — 18 февраля 1967, Принстон, штат Нью-Джерси, США) — американский физик-теоретик и физик-ядерщик, широко известен как научный руководитель Манхэттенского проекта, в рамках которого в годы Второй мировой войны разрабатывались первые образцы ядерного оружия; из-за этого Оппенгеймера, наряду со Станиславом Уламом и Эдвардом Теллером часто называют «отцом атомной бомбы».
Сэмюэл Харрис Альтман (также Олтмен; англ. Samuel Harris Altman, МФА: /ˈɔːltmən/; род. 22 апреля 1985, Чикаго, Иллинойс) — американский предприниматель, инвестор, программист и блогер. С 2014 года и до увольнения в 2019-м был президентом Y Combinator, после чего стал генеральным директором OpenAI. В декабре 2025 года американский журнал Time назвал его человеком года, как одного из создателей систем искусственного интеллекта.
1993 — вышла первая версия веб-браузера Mosaic.
#Biography #Birth_Date #Events #22апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
This media is not supported in your browser
VIEW IN TELEGRAM
Хорошая новость! 💃
Devforge.ru переехал на новый более мощный сервер!✈️
RAM 4 ГБ
vCPU 2
Так что есть где развернуться...
А самое главное минимум расходов🤫
Devforge.ru переехал на новый более мощный сервер!
RAM 4 ГБ
vCPU 2
Так что есть где развернуться...
А самое главное минимум расходов
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3🔥1
Раздел 9. Исключения, логирование, отладка
Глава 1. Иерархия исключений (Exceptions)
Создание своих исключений: наследование от Exception или RuntimeException. Когда кастомное исключение оправдано
Стандартные исключения Java — IOException, IllegalArgumentException, NullPointerException — описывают универсальные классы ошибок. Однако когда приложение вырастает за пределы учебных примеров, универсальные типы перестают адекватно передавать семантику сбоев. IOException не объясняет, что именно пошло не так в бизнес-процессе обработки платежа. IllegalArgumentException не указывает, какое поле запроса нарушило правило валидации.
Кастомное исключение — это класс, расширяющий Exception или RuntimeException, который несет доменную семантику ошибки. Его название становится частью языка предметной области (ubiquitous language в терминологии Domain-Driven Design), позволяя коду самодокументироваться и облегчая обработку ошибок через специфичные catch-блоки.
Однако создание кастомных исключений — это не бесплатная операция. Каждый новый класс исключения увеличивает сложность системы, требует поддержки и тестирования. Поэтому первый вопрос, который должен задать разработчик: действительно ли стандартное исключение не передает нужную семантику?
Когда кастомное исключение оправдано
Создание собственного класса исключения оправдано в следующих сценариях:
— Доменная специфика ошибки. Когда ошибка является неотъемлемой частью бизнес-логики и требует специфической обработки. InsufficientFundsException в банковской системе или SeatUnavailableException в системе бронирования — это не технические сбои, а валидные бизнес-сценарии, которые код должен обрабатыать осмысленно.
— Необходимость дополнительного контекста. Когда стандартное исключение не позволяет передать структурированную информацию об ошибке. Кастомный класс может содержать поля для error code, идентификатора сущности, деталей валидации, которые необходимы для формирования корректного ответа API или сообщения пользователю.
— Разделение обработки в catch-блоках. Когда разные типы ошибок требуют разной логики восстановления. Иерархия кастомных исключений позволяет использовать полиморфизм в обработке: перехватить общий тип для единообразной обработки, или специфичный для особой логики.
— API для внешнего использования. Когда код предназначен для использования как библиотека или сервис, и нужно предоставить четкий контракт возможных сбоев без экспонирования внутренних деталей реализации.
Обратные сценарии, когда кастомное исключение не нужно:
— Ошибка является стандартной программной ошибкой (null-аргумент, выход за границы) — используйте IllegalArgumentException, IndexOutOfBoundsException
— Ошибка не требует специфической обработки и обрабатывается единообразно с другими сбоями
— Сценарий покрывается существующим стандартным исключением с информативным сообщением
#Java #для_новичков #beginner #exception #custom_exception
Глава 1. Иерархия исключений (Exceptions)
Создание своих исключений: наследование от Exception или RuntimeException. Когда кастомное исключение оправдано
Стандартные исключения Java — IOException, IllegalArgumentException, NullPointerException — описывают универсальные классы ошибок. Однако когда приложение вырастает за пределы учебных примеров, универсальные типы перестают адекватно передавать семантику сбоев. IOException не объясняет, что именно пошло не так в бизнес-процессе обработки платежа. IllegalArgumentException не указывает, какое поле запроса нарушило правило валидации.
Кастомное исключение — это класс, расширяющий Exception или RuntimeException, который несет доменную семантику ошибки. Его название становится частью языка предметной области (ubiquitous language в терминологии Domain-Driven Design), позволяя коду самодокументироваться и облегчая обработку ошибок через специфичные catch-блоки.
Однако создание кастомных исключений — это не бесплатная операция. Каждый новый класс исключения увеличивает сложность системы, требует поддержки и тестирования. Поэтому первый вопрос, который должен задать разработчик: действительно ли стандартное исключение не передает нужную семантику?
Когда кастомное исключение оправдано
Создание собственного класса исключения оправдано в следующих сценариях:
— Доменная специфика ошибки. Когда ошибка является неотъемлемой частью бизнес-логики и требует специфической обработки. InsufficientFundsException в банковской системе или SeatUnavailableException в системе бронирования — это не технические сбои, а валидные бизнес-сценарии, которые код должен обрабатыать осмысленно.
— Необходимость дополнительного контекста. Когда стандартное исключение не позволяет передать структурированную информацию об ошибке. Кастомный класс может содержать поля для error code, идентификатора сущности, деталей валидации, которые необходимы для формирования корректного ответа API или сообщения пользователю.
— Разделение обработки в catch-блоках. Когда разные типы ошибок требуют разной логики восстановления. Иерархия кастомных исключений позволяет использовать полиморфизм в обработке: перехватить общий тип для единообразной обработки, или специфичный для особой логики.
— API для внешнего использования. Когда код предназначен для использования как библиотека или сервис, и нужно предоставить четкий контракт возможных сбоев без экспонирования внутренних деталей реализации.
Обратные сценарии, когда кастомное исключение не нужно:
— Ошибка является стандартной программной ошибкой (null-аргумент, выход за границы) — используйте IllegalArgumentException, IndexOutOfBoundsException
— Ошибка не требует специфической обработки и обрабатывается единообразно с другими сбоями
— Сценарий покрывается существующим стандартным исключением с информативным сообщением
#Java #для_новичков #beginner #exception #custom_exception
👍4
Выбор между Exception и RuntimeException
Это архитектурное решение, определяющее контракт метода и обязательства вызывающего кода. Современная практика существенно сдвинулась в сторону RuntimeException, но понимание обоих подходов необходимо.
Checked-исключения: наследование от Exception
Checked-исключения форсируют явную обработку на уровне вызывающего кода. Компилятор гарантирует, что каждый potential failure path либо перехвачен, либо проброшен дальше. Это делает checked-исключения подходящими для сценариев, где восстановление не просто возможно, но и требуется по бизнес-логике.
Пример корректного использования checked-исключения:
Это checked-исключение оправдано, потому что:
— Восстановление требует специфических действий от вызывающего кода (инициация MFA)
— Исключение является частью доменной модели и бизнес-процесса
— Пропуск обработки приведет к некорректному поведению системы
Unchecked-исключения: наследование от RuntimeException
Unchecked-исключения предпочтительны для подавляющего большинства сценариев в современной Java-разработке. Они не загромождают сигнатуры методов, совместимы с функциональным стилем (Stream API, лямбды), и соответствуют философии Spring, Kotlin и других современных фреймворков.
Пример доменного unchecked-исключения:
Использование в доменном коде:
#Java #для_новичков #beginner #exception #custom_exception
Это архитектурное решение, определяющее контракт метода и обязательства вызывающего кода. Современная практика существенно сдвинулась в сторону RuntimeException, но понимание обоих подходов необходимо.
Checked-исключения: наследование от Exception
Checked-исключения форсируют явную обработку на уровне вызывающего кода. Компилятор гарантирует, что каждый potential failure path либо перехвачен, либо проброшен дальше. Это делает checked-исключения подходящими для сценариев, где восстановление не просто возможно, но и требуется по бизнес-логике.
Пример корректного использования checked-исключения:
/**
* Исключение, сигнализирующее о необходимости ручного подтверждения
* платежа из-за превышения лимита. Вызывающий код должен инициировать
* процедуру двухфакторной аутентификации.
*/
public class ManualApprovalRequiredException extends Exception {
private final String transactionId;
private final BigDecimal amount;
private final String requiredApprovalLevel;
public ManualApprovalRequiredException(String transactionId, BigDecimal amount,
String requiredApprovalLevel) {
super(String.format("Transaction %s requires %s approval for amount %s",
transactionId, requiredApprovalLevel, amount));
this.transactionId = transactionId;
this.amount = amount;
this.requiredApprovalLevel = requiredApprovalLevel;
}
public String getTransactionId() { return transactionId; }
public BigDecimal getAmount() { return amount; }
public String getRequiredApprovalLevel() { return requiredApprovalLevel; }
}
Это checked-исключение оправдано, потому что:
— Восстановление требует специфических действий от вызывающего кода (инициация MFA)
— Исключение является частью доменной модели и бизнес-процесса
— Пропуск обработки приведет к некорректному поведению системы
Unchecked-исключения: наследование от RuntimeException
Unchecked-исключения предпочтительны для подавляющего большинства сценариев в современной Java-разработке. Они не загромождают сигнатуры методов, совместимы с функциональным стилем (Stream API, лямбды), и соответствуют философии Spring, Kotlin и других современных фреймворков.
Пример доменного unchecked-исключения:
/**
* Исключение, сигнализирующее о нарушении бизнес-правила.
* Восстановление невозможно без изменения входных данных.
*/
public class BusinessRuleViolationException extends RuntimeException {
private final String ruleCode;
private final String entityType;
private final String entityId;
public BusinessRuleViolationException(String ruleCode, String entityType,
String entityId, String message) {
super(message);
this.ruleCode = ruleCode;
this.entityType = entityType;
this.entityId = entityId;
}
public String getRuleCode() { return ruleCode; }
public String getEntityType() { return entityType; }
public String getEntityId() { return entityId; }
}
Использование в доменном коде:
public class Order {
private OrderStatus status;
private List<OrderItem> items;
public void cancel() {
if (status == OrderStatus.SHIPPED) {
throw new BusinessRuleViolationException(
"ORDER_ALREADY_SHIPPED",
"Order",
this.id,
"Cannot cancel order that has already been shipped"
);
}
if (status == OrderStatus.CANCELLED) {
throw new BusinessRuleViolationException(
"ORDER_ALREADY_CANCELLED",
"Order",
this.id,
"Order is already cancelled"
);
}
this.status = OrderStatus.CANCELLED;
}
}#Java #для_новичков #beginner #exception #custom_exception
👍4
Антипаттерны при проектировании исключений
Антипаттерн "God Exception"
Создание единого кастомного исключения с enum-кодами ошибок вместо иерархии классов — распространенный, но вредный подход. Разработчик создает один класс ApplicationException с полем ErrorCode, и использует enum для различения сценариев:
Проблемы этого подхода:
— Клиентский код вынужден использовать if-else или switch по error code вместо полиморфизма catch-блоков
— Каждое добавление нового сценария требует модификации enum, нарушая Open/Closed Principle
— Невозможно использовать специфичные catch-блоки для разных типов ошибок
— Type safety теряется — компилятор не может проверить корректность обработки
Правильный подход — использовать иерархию классов для сценариев, требующих разной обработки :
Теперь клиентский код может использовать полиморфизм:
#Java #для_новичков #beginner #exception #custom_exception
Антипаттерн "God Exception"
Создание единого кастомного исключения с enum-кодами ошибок вместо иерархии классов — распространенный, но вредный подход. Разработчик создает один класс ApplicationException с полем ErrorCode, и использует enum для различения сценариев:
// Антипаттерн: God Exception с enum
public class ApplicationException extends RuntimeException {
private final ErrorCode errorCode;
public ApplicationException(ErrorCode errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
}
// Использование
throw new ApplicationException(ErrorCode.INVALID_DATA_FORMAT, "...");
throw new ApplicationException(ErrorCode.MISSING_REQUIRED_FIELD, "...");
Проблемы этого подхода:
— Клиентский код вынужден использовать if-else или switch по error code вместо полиморфизма catch-блоков
— Каждое добавление нового сценария требует модификации enum, нарушая Open/Closed Principle
— Невозможно использовать специфичные catch-блоки для разных типов ошибок
— Type safety теряется — компилятор не может проверить корректность обработки
Правильный подход — использовать иерархию классов для сценариев, требующих разной обработки :
public abstract class PaymentException extends RuntimeException {
protected PaymentException(String message, Throwable cause) {
super(message, cause);
}
}
public class InsufficientFundsException extends PaymentException {
private final BigDecimal available;
private final BigDecimal requested;
public InsufficientFundsException(BigDecimal available, BigDecimal requested) {
super(String.format("Insufficient funds: available %s, requested %s",
available, requested), null);
this.available = available;
this.requested = requested;
}
}
public class PaymentGatewayTimeoutException extends PaymentException {
private final String gatewayId;
private final int timeoutMillis;
public PaymentGatewayTimeoutException(String gatewayId, int timeoutMillis) {
super(String.format("Gateway %s timed out after %dms", gatewayId, timeoutMillis), null);
this.gatewayId = gatewayId;
this.timeoutMillis = timeoutMillis;
}
}Теперь клиентский код может использовать полиморфизм:
try {
paymentService.process(payment);
} catch (InsufficientFundsException e) {
// Специфическая логика: предложить пополнение счета
return ResponseEntity.status(402)
.body(new PaymentErrorResponse("INSUFFICIENT_FUNDS", e.getAvailable()));
} catch (PaymentGatewayTimeoutException e) {
// Специфическая логика: retry с другим шлюзом
return retryWithAlternativeGateway(payment);
} catch (PaymentException e) {
// Общая обработка для всех платежных ошибок
return ResponseEntity.status(500)
.body(new PaymentErrorResponse("PAYMENT_FAILED", e.getMessage()));
}#Java #для_новичков #beginner #exception #custom_exception
👍4
Антипаттерн "Destructive Wrapping"
Потеря стектрейса при оборачивании исключений — критическая ошибка, делающая отладку невозможной:
Проектирование иерархии исключений
Хорошо спроектированная иерархия исключений отражает структуру предметной области и уровни абстракции. Рекомендуется создавать базовые классы для каждого домена или слоя приложения, от которых наследуются конкретные исключения.
Эта иерархия позволяет:
— Перехватывать все ошибки каталога через catch (CatalogException e)
— Перехватывать все ошибки приложения через catch (LibraryException e)
— Обрабатывать специфичные сценарии через конкретные типы
— Добавлять новые исключения без модификации существующего кода
#Java #для_новичков #beginner #exception #custom_exception
Потеря стектрейса при оборачивании исключений — критическая ошибка, делающая отладку невозможной:
// Антипаттерн: потеря cause
try {
processFile(file);
} catch (IOException e) {
throw new FileProcessingException("Failed to process file"); // Cause потерян!
}
Правильный подход — всегда передавать оригинальное исключение в конструктор:
java
Copy
// Правильно: сохранение цепочки причин
try {
processFile(file);
} catch (IOException e) {
throw new FileProcessingException("Failed to process file: " + file.getName(), e);
}
Проектирование иерархии исключений
Хорошо спроектированная иерархия исключений отражает структуру предметной области и уровни абстракции. Рекомендуется создавать базовые классы для каждого домена или слоя приложения, от которых наследуются конкретные исключения.
// Базовое исключение для всего приложения
public abstract class LibraryException extends RuntimeException {
protected LibraryException(String message, Throwable cause) {
super(message, cause);
}
}
// Домен: каталог книг
public abstract class CatalogException extends LibraryException {
protected CatalogException(String message, Throwable cause) {
super(message, cause);
}
}
public class BookNotFoundException extends CatalogException {
private final String isbn;
public BookNotFoundException(String isbn) {
super("Book not found: " + isbn, null);
this.isbn = isbn;
}
public String getIsbn() { return isbn; }
}
public class DuplicateIsbnException extends CatalogException {
private final String isbn;
private final Long existingBookId;
public DuplicateIsbnException(String isbn, Long existingBookId) {
super(String.format("ISBN %s already exists for book %d", isbn, existingBookId), null);
this.isbn = isbn;
this.existingBookId = existingBookId;
}
}
// Домен: пользователи
public abstract class UserException extends LibraryException {
protected UserException(String message, Throwable cause) {
super(message, cause);
}
}
public class UserNotActiveException extends UserException {
private final String userId;
private final UserStatus currentStatus;
public UserNotActiveException(String userId, UserStatus currentStatus) {
super(String.format("User %s is not active, current status: %s", userId, currentStatus), null);
this.userId = userId;
this.currentStatus = currentStatus;
}
}
Эта иерархия позволяет:
— Перехватывать все ошибки каталога через catch (CatalogException e)
— Перехватывать все ошибки приложения через catch (LibraryException e)
— Обрабатывать специфичные сценарии через конкретные типы
— Добавлять новые исключения без модификации существующего кода
#Java #для_новичков #beginner #exception #custom_exception
👍4
Конструкторы и структурированные данные
Каждый кастомный класс исключения должен предоставлять набор конструкторов, соответствующий стандартным паттернам Java:
Наличие конструктора с Throwable cause критично для поддержки exception chaining — механизма, позволяющего сохранять полный контекст ошибки при трансляции через слои приложения.
Интеграция с Spring и глобальной обработкой
В современных Spring-приложениях кастомные исключения интегрируются с глобальной обработкой ошибок через @ControllerAdvice, что устраняет необходимость в checked-исключениях и распределенных try-catch блоках:
#Java #для_новичков #beginner #exception #custom_exception
Каждый кастомный класс исключения должен предоставлять набор конструкторов, соответствующий стандартным паттернам Java:
public class LibraryProcessingException extends RuntimeException {
private final String operation;
private final String entityId;
private final Instant timestamp;
// Базовый конструктор
public LibraryProcessingException(String operation, String entityId, String message) {
this(operation, entityId, message, null);
}
// Конструктор с cause для цепочки исключений
public LibraryProcessingException(String operation, String entityId,
String message, Throwable cause) {
super(message, cause);
this.operation = operation;
this.entityId = entityId;
this.timestamp = Instant.now();
}
// Геттеры для структурированного доступа к данным
public String getOperation() { return operation; }
public String getEntityId() { return entityId; }
public Instant getTimestamp() { return timestamp; }
}Наличие конструктора с Throwable cause критично для поддержки exception chaining — механизма, позволяющего сохранять полный контекст ошибки при трансляции через слои приложения.
Интеграция с Spring и глобальной обработкой
В современных Spring-приложениях кастомные исключения интегрируются с глобальной обработкой ошибок через @ControllerAdvice, что устраняет необходимость в checked-исключениях и распределенных try-catch блоках:
@ControllerAdvice
public class LibraryExceptionHandler {
@ExceptionHandler(BookNotFoundException.class)
public ResponseEntity<ErrorResponse> handleBookNotFound(BookNotFoundException e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ErrorResponse(
"BOOK_NOT_FOUND",
e.getMessage(),
Map.of("isbn", e.getIsbn())
));
}
@ExceptionHandler(DuplicateIsbnException.class)
public ResponseEntity<ErrorResponse> handleDuplicateIsbn(DuplicateIsbnException e) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(new ErrorResponse(
"DUPLICATE_ISBN",
e.getMessage(),
Map.of("isbn", e.getIsbn(), "existingBookId", e.getExistingBookId())
));
}
@ExceptionHandler(LibraryException.class)
public ResponseEntity<ErrorResponse> handleGenericLibrary(LibraryException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ErrorResponse(
"LIBRARY_ERROR",
"An unexpected library error occurred",
Map.of()
));
}
}
#Java #для_новичков #beginner #exception #custom_exception
👍5
Что выведет код?
#Tasks
class MyCheckedException extends Exception {
public MyCheckedException() { super(); }
}
class MyUncheckedException extends RuntimeException {
public MyUncheckedException() { super(); }
}
public class Task220426 {
public static void main(String[] args) {
try {
throw new MyUncheckedException();
} catch (Exception e) {
System.out.print("1");
}
try {
throw new MyCheckedException();
} catch (RuntimeException e) {
System.out.print("2");
} catch (Exception e) {
System.out.print("3");
}
try {
throw new MyUncheckedException();
} finally {
System.out.print("4");
}
}
}#Tasks
🔥2👍1
Варианты ответа:
Anonymous Quiz
7%
13 + Exception
7%
14 + Exception
20%
124 + Exception
67%
134 + Exception
👍2
Что такое CDI (Contexts and Dependency Injection)? 🤓
Ответ:
CDI — это стандарт внедрения зависимостей для Java EE / Jakarta EE (спецификация JSR-365).
Он предоставляет мощный механизм для управления зависимостями с учетом контекста (например, запрос, сессия, приложение).
CDI поддерживает типовую безопасность, события, декораторы, перехватчики и продвинутые возможности жизненного цикла.
В мире Spring аналогичный функционал реализован в Spring Framework, но CDI — это именно спецификация, которую можно реализовать (например, Weld — реализация CDI).
#собеседование
Ответ:
Он предоставляет мощный механизм для управления зависимостями с учетом контекста (например, запрос, сессия, приложение).
CDI поддерживает типовую безопасность, события, декораторы, перехватчики и продвинутые возможности жизненного цикла.
В мире Spring аналогичный функционал реализован в Spring Framework, но CDI — это именно спецификация, которую можно реализовать (например, Weld — реализация CDI).
#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
История технологии сегодня — 23 апреля
ℹ️ Кто родился в этот день
Макс Карл Эрнст Людвиг Планк (нем. Max Karl Ernst Ludwig Planck; 23 апреля 1858, Киль, королевство Пруссия — 4 октября 1947, Гёттинген, американская зона оккупации Германии) — немецкий физик-теоретик, основоположник квантовой физики. Лауреат Нобелевской премии по физике (1918) и других наград, член Прусской академии наук (1894), ряда иностранных научных обществ и академий наук. На протяжении многих лет один из руководителей немецкой науки.
Научные труды Планка посвящены термодинамике, теории теплового излучения, квантовой теории, специальной теории относительности, оптике. Он сформулировал второе начало термодинамики в виде принципа возрастания энтропии и использовал его для решения различных задач физической химии. Применив к проблеме равновесного теплового излучения методы электродинамики и термодинамики, Планк получил закон распределения энергии в спектре абсолютно чёрного тела (формула Планка) и обосновал этот закон, введя представление о квантах энергии и кванте действия. Это достижение положило начало развитию квантовой физики, разработкой различных аспектов которой он занимался в последующие годы («вторая теория» Планка, проблема структуры фазового пространства, статистическая механика квантовых систем и так далее). Планк впервые вывел уравнения динамики релятивистской частицы и заложил основы релятивистской термодинамики.
🌐 Знаковые события
1965 — в космос запущен первый советский спутник связи «Молния-1».
1982 — выход компьютера ZX Spectrum.
#Biography #Birth_Date #Events #23апреля
Макс Карл Эрнст Людвиг Планк (нем. Max Karl Ernst Ludwig Planck; 23 апреля 1858, Киль, королевство Пруссия — 4 октября 1947, Гёттинген, американская зона оккупации Германии) — немецкий физик-теоретик, основоположник квантовой физики. Лауреат Нобелевской премии по физике (1918) и других наград, член Прусской академии наук (1894), ряда иностранных научных обществ и академий наук. На протяжении многих лет один из руководителей немецкой науки.
Научные труды Планка посвящены термодинамике, теории теплового излучения, квантовой теории, специальной теории относительности, оптике. Он сформулировал второе начало термодинамики в виде принципа возрастания энтропии и использовал его для решения различных задач физической химии. Применив к проблеме равновесного теплового излучения методы электродинамики и термодинамики, Планк получил закон распределения энергии в спектре абсолютно чёрного тела (формула Планка) и обосновал этот закон, введя представление о квантах энергии и кванте действия. Это достижение положило начало развитию квантовой физики, разработкой различных аспектов которой он занимался в последующие годы («вторая теория» Планка, проблема структуры фазового пространства, статистическая механика квантовых систем и так далее). Планк впервые вывел уравнения динамики релятивистской частицы и заложил основы релятивистской термодинамики.
1965 — в космос запущен первый советский спутник связи «Молния-1».
1982 — выход компьютера ZX Spectrum.
#Biography #Birth_Date #Events #23апреля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
[Совет по Java #029]
Тема: Class.forName() загружает класс и инициализирует статические блоки.
Проблема: Метод Class.forName(String className) по умолчанию выполняет полную инициализацию загружаемого класса.
Это означает, что все статические поля инициализируются, а статические блоки (static initializers) выполняются. Такое поведение может быть опасным: инициализация может быть тяжелой (подключение к БД, чтение конфигураций, запуск потоков) или даже нежелательной (например, при загрузке вредоносного кода или классов, вызывающих системные вызовы).
Кроме того, статическая инициализация может выбрасывать исключения, которые не планировалось обрабатывать. Во многих сценариях (проверка наличия класса, загрузка класса для рефлексии без выполнения побочных эффектов) требуется только загрузка и связывание (linking), но не инициализация.
Решение: Для загрузки класса без инициализации используйте ClassLoader.loadClass(String name).
Этот метод загружает класс и выполняет связывание, но не инициализирует его (статические блоки не выполняются).
Объяснение: Процесс загрузки класса в Java состоит из трех фаз: загрузка (loading) — поиск и чтение байт-кода, связывание (linking) — верификация, подготовка статических полей с значениями по умолчанию, и инициализация (initialization) — выполнение статических блоков и инициализаторов.
Class.forName() по умолчанию выполняет все три фазы. ClassLoader.loadClass() останавливается после связывания. Разница критична для классов с тяжелой статической инициализацией (регистрация драйверов, создание пулов соединений, загрузка native-библиотек). Кроме того, статическая инициализация может выбросить ExceptionInInitializerError, что трудно предсказать при динамической загрузке.
#Java #советы
Тема: Class.forName() загружает класс и инициализирует статические блоки.
Проблема: Метод Class.forName(String className) по умолчанию выполняет полную инициализацию загружаемого класса.
Это означает, что все статические поля инициализируются, а статические блоки (static initializers) выполняются. Такое поведение может быть опасным: инициализация может быть тяжелой (подключение к БД, чтение конфигураций, запуск потоков) или даже нежелательной (например, при загрузке вредоносного кода или классов, вызывающих системные вызовы).
Кроме того, статическая инициализация может выбрасывать исключения, которые не планировалось обрабатывать. Во многих сценариях (проверка наличия класса, загрузка класса для рефлексии без выполнения побочных эффектов) требуется только загрузка и связывание (linking), но не инициализация.
Решение: Для загрузки класса без инициализации используйте ClassLoader.loadClass(String name).
Этот метод загружает класс и выполняет связывание, но не инициализирует его (статические блоки не выполняются).
public class ClassLoadingExample {
private static final String HEAVY_CLASS = "com.example.DatabaseDriver";
//Антипаттерн: Class.forName() с нежелательной инициализацией
public static void dangerousLoad() throws ClassNotFoundException {
// Выполнит статические блоки класса DatabaseDriver
// Может открыть соединение, зарегистрировать драйвер и т.д.
Class<?> clazz = Class.forName(HEAVY_CLASS);
System.out.println("Класс загружен и инициализирован: " + clazz.getName());
}
//Решение 1: загрузка без инициализации через ClassLoader
public static Class<?> safeLoadWithoutInit(String className) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
try {
// loadClass() загружает и связывает, но не инициализирует
return classLoader.loadClass(className);
} catch (ClassNotFoundException e) {
System.err.println("Класс не найден: " + className);
return null;
}
}
//Решение 2: Class.forName() с отключенной инициализацией
public static Class<?> safeForName(String className) throws ClassNotFoundException {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
// initialize = false — статические блоки НЕ выполняются
return Class.forName(className, false, loader);
}
//Демонстрация разницы
static class DemoClass {
static {
System.out.println("Статический блок DemoClass выполнен!");
// Здесь может быть тяжелая операция
}
static int value = computeValue();
private static int computeValue() {
System.out.println("Статический метод computeValue() вызван");
return 42;
}
}Объяснение: Процесс загрузки класса в Java состоит из трех фаз: загрузка (loading) — поиск и чтение байт-кода, связывание (linking) — верификация, подготовка статических полей с значениями по умолчанию, и инициализация (initialization) — выполнение статических блоков и инициализаторов.
Class.forName() по умолчанию выполняет все три фазы. ClassLoader.loadClass() останавливается после связывания. Разница критична для классов с тяжелой статической инициализацией (регистрация драйверов, создание пулов соединений, загрузка native-библиотек). Кроме того, статическая инициализация может выбросить ExceptionInInitializerError, что трудно предсказать при динамической загрузке.
#Java #советы
👍4