使用从未在方法主体中抛出的 throws 子句声明已检查的异常

问题描述

我了解捕获从未在相应 try 块中抛出的已检查异常是无效的。因为如果异常发生,编译器本身会强迫程序员处理异常。

例如,这个代码片段 -

try
{
}
catch(IOException e)
{
}

无效

但是为什么对于抛出从未在方法体中抛出过的已检查异常的方法,编译器的工作方式不一样?

例如,这个代码片段 -

void test() throws IOException
{
}

出人意料地有效

请解释其背后的原因。 TIA。

解决方法

因为您可能希望允许子类抛出此异常。

public abstract class Parent {
  public void doStuff() {}
}
public class Child {
  // this is illegal,because you throw more exceptions than the overridden method
  public void doStuff() throws IOException {}
}

这对于接口来说更加直观,其(非default)方法永远不会抛出异常但可以声明它。

,

It is a compile-time error 如果 catch 子句可以 catch 检查 异常类 E1 并且 try 块不是这种情况 对应catch子句可以抛出checked异常类 是 E1 的子类或超类,除非 E1 是 Exception 或 Exception 的超类。

这告诉你所有这些都是有效的:

try { }
catch(Exception e){}

--

try{ }
catch(NullPointerException  e) {}

--

try{ }
catch(ArrayIndexOutOfBoundsException  e) {}

--

try{ }
catch(RuntimeException e) {}

--

try{ }
catch(Error e) {}

--

try{ }
catch(Throwable e){ }

它与空块无关。它与您检查的 Exception 子类的不可能路径有关。


Exception 的子类会发生什么?例如 IOexception:那些是无法访问的 catch 块。 try 块中的任何内容都不会导致该异常,因此编译器只会告诉您:永远不会执行该块,因为它永远不会捕获该子异常。

throws 的区别:在此上下文中不存在无法访问代码的概念。方法抛出异常的可能性并不以方法的定义结束。例如:

abstract void readFile(String path) throws IOException;

这个方法甚至没有块,因为它是一个抽象方法。很容易猜到这一行永远不会抛出任何 IOException。但它为将实现它的扩展定义了一个行为。为了覆盖它,您的方法必须抛出 IOException

同样,如果有人覆盖了你的测试方法:

@Override
void test() throws IOException
{
   readFile(file);
}

与您的第一个 try-catch 块相反,这并非不可能发生。

,

Java 遵循“处理或声明”规则。

如果在您的代码中声明了已检查异常,您必须处理它(在 try/catch 块中)或声明它(在方法签名上添加“throws”)。

当您说您的方法可能会抛出异常时,使用您的方法的每个人都必须处理或声明该异常。如果您处理它,您就可以使您的代码能够恢复。如果你声明它,你就是把问题传递给调用者。

如果你声明'throws',编译器就很好,他知道当你的方法被调用时要做什么。

如果您声明了一个实际上并不存在的异常,您就是让代码的用户意识到,在未来的版本中,您可能会添加该异常。用户将为您添加该例外的那一天做好准备。

,

指定表示该方法可以抛出异常或不能抛出。但是编译器不检查它,因为他实际上不能。所以try块只检查指定。这 重点是编译器看不到实际调用异常和方法指定之间的区别。如果您在 try 块中调用 test() ,它将有效。对不起我的英语)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...