Какие ошибки и исключения Java могут быть вызваны "пустым" выражением?
Какой подкласс класса java.lang.Throwable
может быть сброшен пустым оператором?
Под фразой "пустое выражение" я ссылаюсь на "ничего", "полуточку" и "полуколоны":
// ....
A(); B(); C();
try {
// nothing
} catch (java.lang.Throwable e) {
// which Throwable subclass might we see?
}
D(); E(); F();
try {
; // semi-colon
} catch (java.lang.Throwable e) {
// which Throwable subclass might we see?
}
G(); H(); I();
try {
; ; ;; ;;;;; ; ; ;;; ;; ;; ;; ;; ; ;; ; ;; // ... semi-colons
} catch (java.lang.Throwable e) {
// which Throwable subclass might we see?
}
J(); K(); L();
// ....
Какие подклассы Throwable могут быть выбраны между A();
и B();
или между C();
и D();
или между F();
и G();
или между I();
и J();
?
Или, скорее, , которые подклассы Throwable гарантированы не, чтобы отображаться между этими утверждениями
Те, что я знаю до сих пор, это InternalError
, OutOfMemoryError
, StackOverflowError
и UnknownError
.
Ответы
Ответ 1
Этот вопрос очень похож на на другой вопрос, который вы опубликовали. Думаю, я постараюсь рассмотреть оба вопроса здесь.
Поскольку вы ссылаетесь на JVMS, я предполагаю, что вы после официального ответа, и формальный ответ заключается в том, что ваш вопрос на самом деле не имеет смысла.: -)
Вопрос о том, как JVM выполнит фрагмент исходного кода Java, похож на то, чтобы математик правильно вычислил 10 + 10. Математик, вероятно, скажет что-то вроде "как вычислить, он не определен". Аналогично, JLS, который определяет значение фрагмента Java, не учитывает особенности его выполнения.
Итак, сначала позвольте мне немного оформить ваш вопрос: "Где в байт-коде (испускаемом ссылочной реализацией javac
), соответствующем данным Java-фрагментам, может VirtualMachineErrors
произойти?"
Этот вопрос, возможно, намного проще ответить. соответствующий раздел JVMS говорит
Реализация виртуальной машины Java бросает объект, являющийся экземпляром подкласса класса VirtualMethodError
, когда внутренняя ошибка или ограничение ресурсов препятствуют реализации семантики, описанной в этой главе. Эта спецификация не может предсказать, где могут возникать внутренние ошибки или ограничения ресурсов, и не дает точно указать, когда они могут быть сообщены.
Таким образом, ответ таков: между любыми двумя инструкциями байткода.
Теперь, чтобы вернуться к исходному вопросу: этот фрагмент, например
try {
// nothing
} catch (java.lang.Throwable e) {
// which Throwable subclass might we see?
}
скомпилирован в пустую программу, которая не может разумно исключить какие-либо исключения.
Относительно вашего последующего вопроса в комментарии:
Должен ли JLS 11.1.3 быть прочитан как "подклассы Throwable
гарантированно не появятся между байт-кодом, если он не является подклассом VirtualMachineError
"?
Да, вы могли бы так выразиться. Возможно, я бы назвал это несколько иначе: любая инструкция может порождать
- исключения, указанные в JVM Instruction set для данной инструкции,
- любое исключение типа
VirtualMachineError
- и никаких других исключений
Ответ 2
Компилятор, вероятно, удалит код, содержащий "ничего" или "пустые" операторы из байт-кода. Эквивалент в байт-коде будет точно подобен:
// ....
A(); B(); C();
D(); E(); F();
G(); H(); I();
J(); K(); L();
// ....
Конечно, во время выполнения может возникнуть какой-либо неожиданный Error
(например, UnknownError
), и обычно он не должен обрабатывать его в вашем приложении.
Самый близкий вид исключения, который может произойти где угодно (подчеркнутый, чтобы возможно покрыть время между двумя инструкциями байткода), асинхронные исключения:
Большинство исключений происходит синхронно в результате действия потока, в котором они происходят, и в точке в программе, которая, как указано, может привести к такому исключению. Асинхронное исключение, напротив, является исключением, которое может иметь место в любой момент выполнения программы.
Асинхронные исключения происходят только в результате:
-
Вызов метода (устаревшего) stop
класса Thread
или ThreadGroup
.
Методы (устаревшие) stop
могут быть вызваны одним потоком для воздействия на другой поток или все потоки в указанной группе потоков. Они асинхронны, поскольку они могут возникать в любой момент выполнения другого потока или потоков.
-
Внутренняя ошибка или ограничение ресурсов в виртуальной машине Java, которая препятствует реализации семантики языка программирования Java. В этом случае генерируемое асинхронное исключение является экземпляром подкласса VirtualMethodError
.
Но опять же, нет смысла заботиться об этом типе исключений (подклассы VirtualMethodError
), поскольку они представляют собой серьезную ошибку при выполнении JVM. Например, это может быть связано с ручным прерыванием пользователя с помощью Ctrl + C. В этом случае вы вряд ли сможете это сделать.
Ответ 3
Если вы не выполняете какую-либо инструкцию, тогда виртуальная машина вряд ли запросит память или закончит пространство стека для текущего потока. Поскольку другие исключения могут быть выброшены, потому что любое состояние в VM находится вне килта, я думаю, вы всегда должны ожидать InternalError
или UnknownError
. Следовательно, вы не должны ловить Throwable
, но Exception
, так как маловероятно, что вы сможете восстановиться после ошибки - если вы не создаете свою собственную структуру, возможно.