обоснование иерархии исключений Java - PullRequest
6 голосов
/ 03 августа 2011

Я считаю, что иерархия исключений Java сбивает с толку. Throwable делится на Error и Exception, а RuntimeException наследуется от Exception.

  1. Error является непроверенным исключением. Почему Error не наследуется от RuntimeException тогда?

  2. Exception является проверенным исключением. RuntimeException является непроверенным исключением, но оно наследуется от Exception. Не нарушает ли это принцип подстановки Лискова?

Разве не было бы больше смысла, если бы Throwable были разделены на Exception (проверено) и RuntimeException (не проверено), и Error наследовало бы от RuntimeExeption?

Ответы [ 4 ]

3 голосов
/ 03 августа 2011

Я считаю, что иерархия исключений Java сбивает с толку. Throwable делится на Error и Exception, а RuntimeException наследуется от Exception.

A Throwable - это все, что можно использовать для раскрутки стека вызовов. Это должно включать некоторый сбой уровня виртуальной машины (помеченный ошибкой) и что-то специфическое для приложения (помеченное исключением)

Error является непроверенным исключением. Почему тогда Error не наследуется от RuntimeException?

Просто потому, что ошибки не являются исключениями. Не было бы никакого смысла в том, чтобы «поймать» ошибку. Например, Что бы вы сделали после ловли OutOfMemoryError. Ошибки предназначены для обозначения чего-то серьезного, произошедшего на уровне виртуальной машины, которое не обязательно обрабатывается программистом

Исключение является проверенным исключением. RuntimeException является непроверенным исключением, но оно наследуется от Exception. Не нарушает ли это принцип подстановки Лискова?

Не совсем. Разработчики пытались сказать, что исключения ДОЛЖНЫ всегда проверяться. Ваш код будет чище, если все ваши методы объявят, какие исключения приложения / библиотеки они генерируют. Исключения RuntimeException должны создаваться только в случае более общих / динамических ситуаций, таких как NullPointerException, когда разработчик, возможно, не кодировал этот случай, но представляет собой серьезную ошибку, которая не совсем упоминается в спецификации приложения.

2 голосов
/ 14 августа 2013

Дизайн обработки исключений в двух наиболее популярных объектно-ориентированных средах (Java и .NET) основан на представлении о том, что вопрос о том, обрабатывать ли конкретное исключение, должен зависеть в первую очередь от его типа, и что типы исключения, которые вы захотите отловить, будут иметь иерархические классовые отношения. Я думаю, что Java и .NET делают это таким образом, потому что C ++ делал это именно так, а C ++ делал это таким образом из-за желания избежать жесткой привязки любых не примитивных типов, жестко запрограммированных в языке. В отсутствие жестко закодированного типа, к которому можно привести все исключения, оператор catch не может знать что-либо о любом типе исключения, для которого он явно не подготовлен. Если имеет смысл только перехватывать исключения, которые можно декодировать, оператор catch сможет разумно воздействовать на эти типы и только на те типы, которые являются производными от того, который содержится в операторе.

В ретроспективе, вероятно, было бы лучше, чтобы решения о том, над какими исключениями следует действовать и / или разрешать с помощью конкретных операторов catch, определялись другими способами, помимо иерархии классов. Среди прочего, одна попытка вызвать метод может потерпеть неудачу из-за множества проблем; если это произойдет, каждый catch, связанный с любым из этих проблем, должен сработать, но только когда все проблем были решены, должно возобновиться нормальное выполнение. К сожалению, ни в Java, ни в .NET нет механизма для достижения такого поведения.

Что касается макета верхнего уровня иерархии, я думаю, что было предположение, что любой тип исключения, который может быть вызван методом, всегда будет ожидаться кодом непосредственного вызова или никогда не ожидаться никаким кодом вызова. , Исключения последнего типа были классифицированы как Error или RuntimeException, тогда как исключения первого типа были размещены в другом месте. На практике вопрос о том, ожидается ли исключение вызывающей стороной метода, не должен зависеть от его места в иерархии или даже от типа исключения . Тот факт, что метод объявлен как throws FooException, не означает, что вызывающий код всегда будет ожидать, что может произойти исключение. В коде очень часто вызывается метод, который объявлен как выбрасывающий исключение, но полагаю, что обстоятельства, связанные с вызовом, таковы, что на практике конкретный вызов никогда не сгенерируется. Если исключение действительно происходит, оно должно вести себя как неожиданное исключение, , даже если внешний контекст выполнения ожидает перехват исключения этого типа . К сожалению, механизмы обработки исключений - это то, чем они являются, и я не ожидаю какого-либо серьезного пересмотра.

1 голос
/ 03 августа 2011

Я думаю, что даже лучшая иерархия

Throwable исключение CheckedException RuntimeException Ошибка

Эта иерархия разделяет исключения и ошибки (как сказал @Paarth) и позволяет перехватывать только все проверенные исключения (без исключений времени выполнения). Но, похоже, Джеймс Гослинг думал иначе ...

0 голосов
/ 03 августа 2011
  1. Ошибка не является подклассом Исключения, поскольку она не предназначена для отлова (как только возникает ошибка, обычно больше не ожидается, что программа будет функционировать).Так что ошибка должна занимать более высокое место в иерархии, как я считаю.

  2. Она не должна нарушать подстановку Лискова, потому что RuntimeException может быть перехвачена, если вы хотите, но только она не применяется.1008 *

...