在下面的代码中,将捕获抛出的异常?
public interface MyInterface {
public void execute() throws Exception;
}
public class MyImplementor implements MyInterface {
public void execute() throws Exception {
throw new MyException();
}
}
public class MyMainClass {
public static void main(String args[]) {
try {
MyImplementor temp = new MyImplementor();
temp.execute();
} catch(MyException e) {
sysout("MyException");
} catch(Exception e) {
sysout("Exception");
}
}
}
(MyException
是一个扩展Exception
)
那么这个异常在哪里被抓住了?此外,编译器使用什么逻辑来决定它被捕获的位置?
如果我放置了
catch(Exception e)
之前的
catch(IOException e)
会改变控制流吗?
答案 0 :(得分:5)
那么这个异常在哪里被抓住了?
在第一个处理程序中。
此外,编译器使用什么逻辑来决定它被捕获的位置?
编译器不是“决定”......
行为由Java语言规范section 11.3指定:
“抛出异常时,控制从导致异常的代码转移到处理异常的try语句(§14.20)的最近动态封闭的catch子句“。
(强调补充。)
换句话说,将传播的异常(使用等效的instanceof
)与每个处理程序的异常类型进行比较,按处理程序的声明顺序进行比较。执行匹配异常的第一个。
如果我在“
catch(Exception e)
”之前放置“catch(IOException e)
”会改变控制流吗?
是。 (假设您的意思是MyException
而不是IOException
。)这是上述行为的直接逻辑结果。
这意味着您应首先使用处理程序为最具体的异常排序处理程序。如果你弄错了,一些Java编译器和代码质量/错误检测器工具会发出警告,但这不是编译错误。
答案 1 :(得分:3)
它的一些类似于if...else if
。如果满足一个条件,它将从剩余条件中退出...如果出现异常,catch(Exception e)
满足所有类型的异常,因为它是所有例外的父母。所以异常是在顶层本身捕获的。编译器不允许这样做。因此,请根据从底部到顶部的继承顺序放置catch
。然后只有你可以根据其类型获得异常。
答案 2 :(得分:2)
在您的情况下,如果您的代码抛出IOException,它将在IOException catch块中捕获,然后才会到达Exception catch块。在其他情况下,Exception-catch块将捕获任何其他异常
答案 3 :(得分:1)
a)你不能颠倒catch块的顺序。如果你这样做了,IOException的块将变得无法访问 - IOException的一个实例也是Exception的一个实例,因此catch (Exception e)
块会捕获它并且你永远不会遇到catch (IOException e)
块。然后代码将无法编译 - 不允许无法访问的代码。
b)由于MyException扩展了Exception而不是IOException,因此catch (IOException e)
块不会捕获它。因此它将被catch (Exception e)
块捕获。
更新
您现在已经改变了问题,所以答案略有不同:
a)你仍然无法扭转这些障碍。
b)现在您已将第一个块更改为catch (MyException e)
,抛出的异常将被捕获。程序是,编译器查看每个catch块。如果它试图处理的异常是被捕获的异常的实例,则执行该catch块。如果没有,它将进入下一个catch块。如果没有更多的catch块,则会突然终止执行(来自Java语言规范的术语)。
答案 4 :(得分:1)
在您的代码中,未定义MyException,但它应该扩展Exception或RuntimeException。 无论如何它都没有任何区别,你的程序将打印“MyException”,因为它是抛出的异常类型。