为什么当方法永远不会抛出异常时编译器允许抛出
Why does the compiler allow throws when the method will never throw the Exception
我想知道为什么 java 编译器允许在方法声明中抛出异常,而方法永远不会抛出异常。因为"throws"是一种处理异常的方式(告诉调用者去处理它)。
因为有两种处理异常的方式(throws & try/catch)。在 try/catch 中,它不允许捕获未在 try 块中抛出的异常,但它允许在可能不会抛出异常的方法中抛出。
private static void methodA() {
try {
// Do something
// No IO operation here
} catch (IOException ex) { //This line does not compile because
//exception is never thrown from try
// Handle
}
}
private static void methodB() throws IOException { //Why does this //compile when excetion is never thrown in function body
//Do Something
//No IO operation
}
throws
子句是方法契约的一部分。它要求方法的调用者表现得好像指定的异常可能会被方法抛出(即捕获异常或声明自己的 throws
子句)。
方法的初始版本可能不会抛出 throws
子句中指定的异常,但未来的版本可以在不破坏 API 的情况下抛出它(即任何现有代码调用该方法仍然会通过编译)。
反之亦然。如果方法用于抛出 throws
子句中指定的异常,但它的未来版本不再抛出它,则应保留 throws
子句以免破坏使用的现有代码你的方法。
第一个例子:
假设您的代码使用 methodB
:
private static void methodA() {
methodB(); // doesn't have throws IOException clause yet
}
如果以后想把methodB
改成抛出IOException
,methodA
会停止通过编译。
第二个例子:
假设您的代码使用 methodB
:
private static void methodA() {
try {
methodB(); // throws IOException
}
catch (IOException ex) {
}
}
如果您从 methodB
的未来版本中删除 throws
子句,methodA
将不再通过编译。
当methodA
为private
时,这个例子不是很有趣,因为它只能在本地使用(在同一个class内,很容易修改所有方法叫它)。
但是,如果它变成 public
,您不知道谁使用(或将使用)您的方法,因此您无法控制所有可能因添加或删除而中断的代码throws
子句。
如果它是一个实例方法,还有另一个允许 throws
子句的原因,即使你不抛出异常 - 该方法可以被覆盖,覆盖方法可能会抛出异常,即使基础 class 实现没有。
因为签名定义了方法的契约。即使该方法现在不抛出 IOException,也许将来会抛出,并且您要为这种可能性做好准备。
假设您现在只是为该方法提供一个虚拟实现,但您知道稍后实际实现可能会抛出 IOException。
如果编译器阻止您添加此 throws 子句,那么一旦您提供了该方法的实际实现,您将被迫(递归地)重新处理对该方法的所有调用。
关键字 throws 告诉程序员方法中可能会发生 IOException。现在,如果您没有指定 try/catch,这意味着当抛出异常时程序将停止工作,而在 try/catch 中,如果抛出异常,您可以通过执行其他操作来处理它。
使用 throws 提高可读性和指定异常的可能性,并使用 try/catch 告诉程序在发生异常时应该做什么。
methodB抛出IOException,所以调用methodB的方法负责捕获methodB抛出的异常。尝试从其他方法调用 methodB,它会要求您捕获它或重新抛出 IOException。在某个地方,您将不得不在链中捕获 IOException(在 try/catch 块中)。 所以你不会得到编译时错误。
private void sampleMethod(){
尝试 {
方法B();
} 赶上(IOException e){
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
methodA 中的 try/catch 固然吞掉了异常,也就是说 methodA 负责捕获 try/catch 块中的异常。
“任何 java 程序中的每个语句都必须可访问,即每个语句必须至少可执行一次”
所以,你会得到编译器错误,因为你的 try 块没有任何代码导致 IOException。
我想知道为什么 java 编译器允许在方法声明中抛出异常,而方法永远不会抛出异常。因为"throws"是一种处理异常的方式(告诉调用者去处理它)。
因为有两种处理异常的方式(throws & try/catch)。在 try/catch 中,它不允许捕获未在 try 块中抛出的异常,但它允许在可能不会抛出异常的方法中抛出。
private static void methodA() {
try {
// Do something
// No IO operation here
} catch (IOException ex) { //This line does not compile because
//exception is never thrown from try
// Handle
}
}
private static void methodB() throws IOException { //Why does this //compile when excetion is never thrown in function body
//Do Something
//No IO operation
}
throws
子句是方法契约的一部分。它要求方法的调用者表现得好像指定的异常可能会被方法抛出(即捕获异常或声明自己的 throws
子句)。
方法的初始版本可能不会抛出 throws
子句中指定的异常,但未来的版本可以在不破坏 API 的情况下抛出它(即任何现有代码调用该方法仍然会通过编译)。
反之亦然。如果方法用于抛出 throws
子句中指定的异常,但它的未来版本不再抛出它,则应保留 throws
子句以免破坏使用的现有代码你的方法。
第一个例子:
假设您的代码使用 methodB
:
private static void methodA() {
methodB(); // doesn't have throws IOException clause yet
}
如果以后想把methodB
改成抛出IOException
,methodA
会停止通过编译。
第二个例子:
假设您的代码使用 methodB
:
private static void methodA() {
try {
methodB(); // throws IOException
}
catch (IOException ex) {
}
}
如果您从 methodB
的未来版本中删除 throws
子句,methodA
将不再通过编译。
当methodA
为private
时,这个例子不是很有趣,因为它只能在本地使用(在同一个class内,很容易修改所有方法叫它)。
但是,如果它变成 public
,您不知道谁使用(或将使用)您的方法,因此您无法控制所有可能因添加或删除而中断的代码throws
子句。
如果它是一个实例方法,还有另一个允许 throws
子句的原因,即使你不抛出异常 - 该方法可以被覆盖,覆盖方法可能会抛出异常,即使基础 class 实现没有。
因为签名定义了方法的契约。即使该方法现在不抛出 IOException,也许将来会抛出,并且您要为这种可能性做好准备。
假设您现在只是为该方法提供一个虚拟实现,但您知道稍后实际实现可能会抛出 IOException。 如果编译器阻止您添加此 throws 子句,那么一旦您提供了该方法的实际实现,您将被迫(递归地)重新处理对该方法的所有调用。
关键字 throws 告诉程序员方法中可能会发生 IOException。现在,如果您没有指定 try/catch,这意味着当抛出异常时程序将停止工作,而在 try/catch 中,如果抛出异常,您可以通过执行其他操作来处理它。
使用 throws 提高可读性和指定异常的可能性,并使用 try/catch 告诉程序在发生异常时应该做什么。
methodB抛出IOException,所以调用methodB的方法负责捕获methodB抛出的异常。尝试从其他方法调用 methodB,它会要求您捕获它或重新抛出 IOException。在某个地方,您将不得不在链中捕获 IOException(在 try/catch 块中)。 所以你不会得到编译时错误。
private void sampleMethod(){ 尝试 { 方法B(); } 赶上(IOException e){ // TODO 自动生成的 catch 块 e.printStackTrace(); } }
methodA 中的 try/catch 固然吞掉了异常,也就是说 methodA 负责捕获 try/catch 块中的异常。 “任何 java 程序中的每个语句都必须可访问,即每个语句必须至少可执行一次” 所以,你会得到编译器错误,因为你的 try 块没有任何代码导致 IOException。