Какие ошибки и исключения 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, так как маловероятно, что вы сможете восстановиться после ошибки - если вы не создаете свою собственную структуру, возможно.