Опишите особенности работы с Shutdown Hooks
Shutdown Hook – это обработчик завершения работы JVM. Действия, которые необходимо выполнить при прекращении работы программы, описываются в реализации объекта типа Thread, и передаются в Runtime.getRuntime().addShutdownHook().
При использовании обработчика нужно учитывать ряд нюансов:
1. Нет гарантии, что он будет выполнен целиком, и выполнен вообще. Хуки вызываются при нормальном завершении программы – завершении всех пользовательских потоков или вызове System.exit(). Например вызов System.halt() или получение от системы SIGKILL программа завершится незамедлительно. Это может случиться как до выполнения обработчиков, так и во время. Сигнал SIGTERM запустит обработчики, но ОС может не дождаться завершения и оборвать процесс.
2. В хуке нельзя использовать System.exit(0). Завершить работу можно ненулевым кодом, или методом System.halt(). Возврат нулевого кода после старта хуков приведет к зависанию программы.
3. Набор обработчиков задается до их старта. Когда процесс обработки начался, новый вызов addShutdownHook() вызовет исключение.
4. Нет гарантий о порядке выполнения. Если обработчиков несколько, они могут вызываться в случайном порядке, и даже параллельно, в соседних потоках. Об этом намекает и форма объявления обработчика – класс Thread.
Shutdown Hook – это обработчик завершения работы JVM. Действия, которые необходимо выполнить при прекращении работы программы, описываются в реализации объекта типа Thread, и передаются в Runtime.getRuntime().addShutdownHook().
При использовании обработчика нужно учитывать ряд нюансов:
1. Нет гарантии, что он будет выполнен целиком, и выполнен вообще. Хуки вызываются при нормальном завершении программы – завершении всех пользовательских потоков или вызове System.exit(). Например вызов System.halt() или получение от системы SIGKILL программа завершится незамедлительно. Это может случиться как до выполнения обработчиков, так и во время. Сигнал SIGTERM запустит обработчики, но ОС может не дождаться завершения и оборвать процесс.
2. В хуке нельзя использовать System.exit(0). Завершить работу можно ненулевым кодом, или методом System.halt(). Возврат нулевого кода после старта хуков приведет к зависанию программы.
3. Набор обработчиков задается до их старта. Когда процесс обработки начался, новый вызов addShutdownHook() вызовет исключение.
4. Нет гарантий о порядке выполнения. Если обработчиков несколько, они могут вызываться в случайном порядке, и даже параллельно, в соседних потоках. Об этом намекает и форма объявления обработчика – класс Thread.
👍8🔥3
🔥Незаменимый инструмент для автоматизации тестирования на Java
👉Освойте его на бесплатном открытом уроке «Возможности тестирования через Spring Contract Testing» от OTUS.
📖На вебинаре вы вместе с опытным экспертом познакомитесь с возможностями тестирования через Spring Contract Testing и получите ответы на любые свои вопросы по теме.
📆Занятие пройдёт 31 января в 20:00 мск и будет приурочено к старту курса «Java QA Engineer. Professional». Доступна рассрочка на обучение!
💪Пройдите бесплатный тест прямо сейчас, чтобы занять место на открытом уроке и получить запись: Пройти тест
Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963. erid: LjN8K5PpH
👉Освойте его на бесплатном открытом уроке «Возможности тестирования через Spring Contract Testing» от OTUS.
📖На вебинаре вы вместе с опытным экспертом познакомитесь с возможностями тестирования через Spring Contract Testing и получите ответы на любые свои вопросы по теме.
📆Занятие пройдёт 31 января в 20:00 мск и будет приурочено к старту курса «Java QA Engineer. Professional». Доступна рассрочка на обучение!
💪Пройдите бесплатный тест прямо сейчас, чтобы занять место на открытом уроке и получить запись: Пройти тест
Реклама. ООО "ОТУС ОНЛАЙН-ОБРАЗОВАНИЕ". ИНН 9705100963. erid: LjN8K5PpH
🔥4👍1
Что происходит если не обработать исключение?
Если не было предпринято дополнительных действий, в этой ситуации нет никаких хитростей. Всё приложение, и даже метод main(), выполняется в потоках. Поток, в котором было выброшено и не обработано исключение, остановится, и распечатает стектрейс в вывод System.err. Если это был последний пользовательский поток, приложение начнет завершение работы.
Для изменения логики обработки непойманных исключений в Java существует функциональный интерфейс Thread.UncaughtExceptionHandler.
Обработчик упущенных исключений может быть установлен (в порядке возрастания приоритета):
• глобально на всё приложение, статическим методом Thread.setDefaultUncaughtExceptionHandler();
• для группы потоков, переопределением метода uncaughtException() в реализации объекта подкласса ThreadGroup (т.к. ThreadGroup сам является наследником UncaughtExceptionHandler);
• для отдельного потока, методом setUncaughtExceptionHandler().
Естественно, установка нестандартного обработчика не имеет обратной силы. Используя его, нужно убедиться, что он установлен достаточно рано, до выброса какого-либо исключения.
Хорошей практикой считается обрабатывать исключение настолько близко к месту его выброса, насколько возможно. Следовательно, использование глобальных обработчиков – самый плохой вариант.
Так же как в случае различных финализаций, несмотря на все её недостатки, глобальная обработка иногда лучше, чем ничего. Она может, например, дать последний шанс освободить внешние ресурсы, или уведомить о некорректной работе программы более эффективно, чем через логи.
Когда код с исключением выполняет ExecutorService, мы не имеем прямого доступа к объектам потока. Но в этом случае результатом выполнения будет объект типа Future. Такой отложенный объект при попытке прочитать значение перевыбросит полученное исключение, завернув его в ExecutionException. Новое исключение-обертка уже пойдет по обычному пути обработки текущего потока. Исключение как бы перекочует из внутреннего потока пулла во внешний, который использует этот пулл.
Если же пользовательский код не станет дожидаться результатов, исключение будет потеряно, не оставив даже стектрейса в потоке вывода. Для предотвращения такой ситуации стоит снабдить поток обработчиком сразу после создания, определив для сервиса собственную ThreadFactory.
Обычно, если фреймворк скрывает от пользователя детали работы с потоками, он также скрывает и детали работы с исключениями, оставляя свой специальный способ назначить обработчик. И этот специальный обработчик – более специфичный, а значит более правильный подход, чем стандартная глобальная обработка исключений Java. Так, например, в Spring MVC применяется аннотация @ExceptionHandler.
Если не было предпринято дополнительных действий, в этой ситуации нет никаких хитростей. Всё приложение, и даже метод main(), выполняется в потоках. Поток, в котором было выброшено и не обработано исключение, остановится, и распечатает стектрейс в вывод System.err. Если это был последний пользовательский поток, приложение начнет завершение работы.
Для изменения логики обработки непойманных исключений в Java существует функциональный интерфейс Thread.UncaughtExceptionHandler.
Обработчик упущенных исключений может быть установлен (в порядке возрастания приоритета):
• глобально на всё приложение, статическим методом Thread.setDefaultUncaughtExceptionHandler();
• для группы потоков, переопределением метода uncaughtException() в реализации объекта подкласса ThreadGroup (т.к. ThreadGroup сам является наследником UncaughtExceptionHandler);
• для отдельного потока, методом setUncaughtExceptionHandler().
Естественно, установка нестандартного обработчика не имеет обратной силы. Используя его, нужно убедиться, что он установлен достаточно рано, до выброса какого-либо исключения.
Хорошей практикой считается обрабатывать исключение настолько близко к месту его выброса, насколько возможно. Следовательно, использование глобальных обработчиков – самый плохой вариант.
Так же как в случае различных финализаций, несмотря на все её недостатки, глобальная обработка иногда лучше, чем ничего. Она может, например, дать последний шанс освободить внешние ресурсы, или уведомить о некорректной работе программы более эффективно, чем через логи.
Когда код с исключением выполняет ExecutorService, мы не имеем прямого доступа к объектам потока. Но в этом случае результатом выполнения будет объект типа Future. Такой отложенный объект при попытке прочитать значение перевыбросит полученное исключение, завернув его в ExecutionException. Новое исключение-обертка уже пойдет по обычному пути обработки текущего потока. Исключение как бы перекочует из внутреннего потока пулла во внешний, который использует этот пулл.
Если же пользовательский код не станет дожидаться результатов, исключение будет потеряно, не оставив даже стектрейса в потоке вывода. Для предотвращения такой ситуации стоит снабдить поток обработчиком сразу после создания, определив для сервиса собственную ThreadFactory.
Обычно, если фреймворк скрывает от пользователя детали работы с потоками, он также скрывает и детали работы с исключениями, оставляя свой специальный способ назначить обработчик. И этот специальный обработчик – более специфичный, а значит более правильный подход, чем стандартная глобальная обработка исключений Java. Так, например, в Spring MVC применяется аннотация @ExceptionHandler.
👍14🔥5🎉2
This media is not supported in your browser
VIEW IN TELEGRAM
Ответишь — пройдешь на продвинутый курс "Java Developer. Professional" от OTUS по специальной цене + получишь доступ к записям открытых уроков курса курса
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5❤2👍2
Можно ли поймать Error?
Технически, Error как и любой другой Throwable можно поймать в блок catch. Такой код абсолютно валидный и скомпилируется без проблем.
На практике, согласно спецификации, значение исключения типа Error – необрабатываемая ошибка, ловить которую нет смысла.
Более того, выброс исключения подтипа VirtualMachineError означает, что JVM находится в сломанном состоянии. Дальнейшая работа непредсказуема: OutOfMemoryError приводит к невозможности создания новых объектов, StackOverflowError теряет фреймы стека вызова, и так далее.
Так как ловить Error не нужно, объявление её в секции throws сигнатуры метода необязательно. Как и RuntimeException, Error – разновидность unchecked exception.
Технически, Error как и любой другой Throwable можно поймать в блок catch. Такой код абсолютно валидный и скомпилируется без проблем.
На практике, согласно спецификации, значение исключения типа Error – необрабатываемая ошибка, ловить которую нет смысла.
Более того, выброс исключения подтипа VirtualMachineError означает, что JVM находится в сломанном состоянии. Дальнейшая работа непредсказуема: OutOfMemoryError приводит к невозможности создания новых объектов, StackOverflowError теряет фреймы стека вызова, и так далее.
Так как ловить Error не нужно, объявление её в секции throws сигнатуры метода необязательно. Как и RuntimeException, Error – разновидность unchecked exception.
👍15🔥4❤3
Присоединяйтесь к нашему бесплатному курсу и начните увлекательное путешествие в мир Java!
Изучайте основы, создавайте программы, разбирайтесь с методами и анализируйте ошибки в коде. Практика, упражнения и проверочные тесты помогут вам освоить навыки программирования.
🎓 Чему вы научитесь:
— Создавать программы с использованием основных конструкций языка.
— Разделять код на методы для повторного использования.
— Анализировать ошибки в коде с использованием отладочной печати.
💼 Включено в курс:
29 уроков (видео и/или текст), 35 упражнений в тренажере, 95 проверочных тестов + дополнительные материалы.
Вы с нами?😉
Изучайте основы, создавайте программы, разбирайтесь с методами и анализируйте ошибки в коде. Практика, упражнения и проверочные тесты помогут вам освоить навыки программирования.
🎓 Чему вы научитесь:
— Создавать программы с использованием основных конструкций языка.
— Разделять код на методы для повторного использования.
— Анализировать ошибки в коде с использованием отладочной печати.
💼 Включено в курс:
29 уроков (видео и/или текст), 35 упражнений в тренажере, 95 проверочных тестов + дополнительные материалы.
Вы с нами?😉
👍16🔥3🌚1
Какая разница между JDK и JRE?
JRE – Java Runtime Environment, Java-окружение времени выполнения. Это набор всего необходимого чтобы запустить скомпилированную Java-программу. Окружение состоит из виртуальной машины Java (JVM), библиотеки классов (Java Class Library), консольной команды java и прочей инфраструктуры. Тем не менее, JRE не достаточно чтобы создавать новые программы.
JDK – Java Development Kit, набор Java-разработчика. Это полнофункциональный SDK для Java. JDK включает в себя JRE, но кроме того содержит компилятор (javac) и другие инструменты разработки, такие как javadoc и jdb. С помощью JDK можно создавать и компилировать программы.
В большинстве случаев, если вам нужно только запускать Java программы, вы устанавливаете только JRE, если же вы планируете программировать на Java, вместо этого вам необходим JDK.
JRE – Java Runtime Environment, Java-окружение времени выполнения. Это набор всего необходимого чтобы запустить скомпилированную Java-программу. Окружение состоит из виртуальной машины Java (JVM), библиотеки классов (Java Class Library), консольной команды java и прочей инфраструктуры. Тем не менее, JRE не достаточно чтобы создавать новые программы.
JDK – Java Development Kit, набор Java-разработчика. Это полнофункциональный SDK для Java. JDK включает в себя JRE, но кроме того содержит компилятор (javac) и другие инструменты разработки, такие как javadoc и jdb. С помощью JDK можно создавать и компилировать программы.
В большинстве случаев, если вам нужно только запускать Java программы, вы устанавливаете только JRE, если же вы планируете программировать на Java, вместо этого вам необходим JDK.
👍16🔥2❤1❤🔥1🍌1
Зачем нужен package-info?
Обычно, чтобы создать новый пакет, вы создаете папку с соответствующим названием, и во всех ее .java файлах добавляете в начале строчку с названием пакета, вида package full.dir.path;. Этого вполне достаточно для работы.
Однако, дополнительно вы можете добавить в пакет его объявление – файл package-info.java. Несмотря на то, что это .java-файл, это не объявление класса. В названии класса дефисы запрещены, так что неоднозначности не возникнет.
Минимальное содержимое файла package-info.java – всё та же строка package full.dir.path;. Такой файл не несет практической пользы. Есть две вещи, которые можно в него добавить, чтобы польза появилась.
Первое – документация пакета. Javadoc-комментарий будет использоваться генератором документации. Пример – описание пакета java.lang. Его исходник вы можете найти в файле java/lang/package-info.java.
Второе возможное применение – аннотации уровня пакета. Для этого аннотация должна иметь Target PACKAGE. Например, некоторые пакеты Spring Framework помечены аннотацией @NonNullApi.
Обычно, чтобы создать новый пакет, вы создаете папку с соответствующим названием, и во всех ее .java файлах добавляете в начале строчку с названием пакета, вида package full.dir.path;. Этого вполне достаточно для работы.
Однако, дополнительно вы можете добавить в пакет его объявление – файл package-info.java. Несмотря на то, что это .java-файл, это не объявление класса. В названии класса дефисы запрещены, так что неоднозначности не возникнет.
Минимальное содержимое файла package-info.java – всё та же строка package full.dir.path;. Такой файл не несет практической пользы. Есть две вещи, которые можно в него добавить, чтобы польза появилась.
Первое – документация пакета. Javadoc-комментарий будет использоваться генератором документации. Пример – описание пакета java.lang. Его исходник вы можете найти в файле java/lang/package-info.java.
Второе возможное применение – аннотации уровня пакета. Для этого аннотация должна иметь Target PACKAGE. Например, некоторые пакеты Spring Framework помечены аннотацией @NonNullApi.
👍11🔥2🥰1😁1
📕 Книги для Java программиста - канал с книгами по Java. Постоянно выходят новинки как на русском так и на английском языке!
📰 Java News - канал с последними новостями из мира Java!
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥2❤1
Можно ли достать параметры метода рефлекшеном?
По умолчанию – нет. Рефлекшн-информация о параметрах метода представляется объектами класса Parameter. По умолчанию их свойство name синтетическое: "arg0", "arg1", и так далее. Метод isNamePresent при этом возвращает false, что значит что действительная информация об имени недоступна. Она не попадает даже в байт-код.
Начиная с Java 8 у компилятора (javac) появилась опция -parameters. В скомпилированный с этой опцией класс добавляются имена аргументов методов. Parameter#getName() тогда возвращает уже настоящее имя.
Классический пример, когда информация об именах может понадобиться – библиотека JSON сериализации Jackson. Параметры конструктора могут трактоваться ей как поля сериализационной формы.
До появления флага -parameters Jackson использовал для этого аннотации. Каждый параметр снабжался аннотацией @JsonProperty. Значением аннотации передавалась строка, которая повторяла имя параметра. Эти аннотации затем можно было получить, вызвав Method#getParameterAnnotations().
По умолчанию – нет. Рефлекшн-информация о параметрах метода представляется объектами класса Parameter. По умолчанию их свойство name синтетическое: "arg0", "arg1", и так далее. Метод isNamePresent при этом возвращает false, что значит что действительная информация об имени недоступна. Она не попадает даже в байт-код.
Начиная с Java 8 у компилятора (javac) появилась опция -parameters. В скомпилированный с этой опцией класс добавляются имена аргументов методов. Parameter#getName() тогда возвращает уже настоящее имя.
Классический пример, когда информация об именах может понадобиться – библиотека JSON сериализации Jackson. Параметры конструктора могут трактоваться ей как поля сериализационной формы.
До появления флага -parameters Jackson использовал для этого аннотации. Каждый параметр снабжался аннотацией @JsonProperty. Значением аннотации передавалась строка, которая повторяла имя параметра. Эти аннотации затем можно было получить, вызвав Method#getParameterAnnotations().
👍11🔥3
This media is not supported in your browser
VIEW IN TELEGRAM
Камерный митап для мобильных разработчиков, где каждый может предложить свой кейс для обсуждения по трем трекам: iOS, Android, Flutter.
Участники митапа — техлиды, руководители разработки и ведущие мобильные разработчики из команд Яндекс Go и Яндекс Про. В завершении вечера afterparty — нетворкинг, настолки, вкусная еда и напитки.
Место встречи: Москва-Сити, башня «Око»
Дата и время: 15 февраля, 18:30
Бесплатно. Количество мест ограничено. Регистрация обязательна
Подробнее
Участники митапа — техлиды, руководители разработки и ведущие мобильные разработчики из команд Яндекс Go и Яндекс Про. В завершении вечера afterparty — нетворкинг, настолки, вкусная еда и напитки.
Место встречи: Москва-Сити, башня «Око»
Дата и время: 15 февраля, 18:30
Бесплатно. Количество мест ограничено. Регистрация обязательна
Подробнее
👍7
Какой результат выведет следующая программа?
Anonymous Quiz
19%
A got caught B got caught
23%
B got caught
25%
A got caught
33%
Ошибку компиляции
👍21🔥7
Microservices | Вопросы с Собеседований
- Подборка вопросов по микросервисной архитектуре с реальных собеседований
- Авторские статьи по архитектуре, проектированию, базам данных
- Автор - Lead Developer с 8 лет опыта на Java/Kotlin
- Подборка вопросов по микросервисной архитектуре с реальных собеседований
- Авторские статьи по архитектуре, проектированию, базам данных
- Автор - Lead Developer с 8 лет опыта на Java/Kotlin
🔥5☃2
Как создать объект в обход конструктора?
Этот пост – не рекомендация. Описанное здесь крайне редко имеет основание к применению (если имеет вообще).
Десериализация – полагается, что сериализационная форма уже была когда-то сконструирована, теперь же экземпляр просто восстанавливается с помощью метода readObject. Вызывается конструктор ближайшего не serializable родителя.
Внутри десериализация использует ReflectionFactory.newConstructorForSerialization из пакета sun.reflect – метод создания объекта заданного типа с указанным (возможно родительским) конструктором. Можно использовать его напрямую. Конструктор всё же вызывается, но это может быть конструктор класса Object.
Unsafe.allocateInstance – непосредственно создает экземпляр не вызывая конструктор, ничего лишнего.
Оба способа позволяют создать объект, не вызван ни конструктор, ни инициализаторы полей. Все члены остаются со значениями по-умолчанию (null, 0, false). Однако для final поля дефолтным значением считается указанное в инициализации, оно и будет установлено.
Пользуясь этими грязными хаками, помните: пакеты sun.* никогда не были частью официально поддерживаемого API Java, и есть не во всех версиях Java.
Этот пост – не рекомендация. Описанное здесь крайне редко имеет основание к применению (если имеет вообще).
Десериализация – полагается, что сериализационная форма уже была когда-то сконструирована, теперь же экземпляр просто восстанавливается с помощью метода readObject. Вызывается конструктор ближайшего не serializable родителя.
Внутри десериализация использует ReflectionFactory.newConstructorForSerialization из пакета sun.reflect – метод создания объекта заданного типа с указанным (возможно родительским) конструктором. Можно использовать его напрямую. Конструктор всё же вызывается, но это может быть конструктор класса Object.
Unsafe.allocateInstance – непосредственно создает экземпляр не вызывая конструктор, ничего лишнего.
Оба способа позволяют создать объект, не вызван ни конструктор, ни инициализаторы полей. Все члены остаются со значениями по-умолчанию (null, 0, false). Однако для final поля дефолтным значением считается указанное в инициализации, оно и будет установлено.
Пользуясь этими грязными хаками, помните: пакеты sun.* никогда не были частью официально поддерживаемого API Java, и есть не во всех версиях Java.
👍13🔥3🤔2
Как исправить этот код, чтобы он вывел "I Love Programming Tests" корректно?
Anonymous Quiz
11%
Надо внутри while добавить i++ в конце, иначе будет бесконечный цикл.
5%
Надо в System.out.print передавать text[i].
12%
Надо объявить int i = 0.
72%
Надо выполнить все предыдущие пункты для корректной работы программы.
👍12🔥5
Узнайте на бесплатном практическом уроке «Java NIO» от OTUS и Александра Фисунова — Senior Kotlin Developer в SSP Software на проекте ВТБ.
На вебинаре вы:
— узнаете, что такое Java NIO и чем он отличается от Java IO
— разберете полезные возможности Java NIO, которые сильно упрощают жизнь и могут пригодиться любому разработчику;
— изучите Java Core и получите ответы на свои вопросы.
Встречаемся 15 февраля в 20:00 мск.
Открытый урок пройдет в преддверии обновленного запуска курса «Java Developer. Professional».
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576Please open Telegram to view this post
VIEW IN TELEGRAM
👍5👏3🔥2🥴1