Две точки:
- Вы не можете объявить его для выброса
Exception
, потому что тогда оно вызовет более общее исключение, чем тот, который указывает метод eat()
в интерфейсе Bread
.Метод, унаследованный от суперкласса или интерфейса, не может генерировать более общие исключения, чем указано в суперклассе или интерфейсе. - Вы можете объявить его для выброса
RuntimeException
, потому что методы всегда могут генерировать непроверенные исключения, независимо от того, указаны вы ихв throws
предложении или нет.(Поэтому указание, что он может выдать RuntimeException
, является избыточным.)
Чтобы объяснить причину правила, которое я упомянул в первом пункте: предположим, вы делаете это:
// Allowed because Test implements Bread
Bread obj = new Test();
Если вы сейчас вызываете obj.eat()
, компилятор должен проверить, правильно ли вы обрабатываете все проверенные исключения, которые могут произойти в этом вызове.Это достигается путем просмотра типа переменной obj
, которая равна Bread
.Интерфейс Bread
указывает, что eat()
может выдавать MyException
(и неявно, подклассы MyException
).
Если вашему методу Test.eat()
было разрешено генерировать более общий вид проверяемого исключения,например, Exception
, компилятор не может проверить, просто посмотрев тип obj
, что вы правильно обрабатываете все проверенные исключения.
Для предотвращения этой проблемы правило состоит в том, что переопределенный метод не разрешенбросить более общие исключения.