什么是异常传播?我试图谷歌它,但找不到令人满意的结果。最好用Java来解释这一点。
7 回答
令人惊讶的是,在关于异常的 Java 教程页面中对此进行了解释。
异常从一个方法传播到另一个方法,沿着调用堆栈向上传播,直到它被捕获。因此,如果a()
调用b()
,调用c()
,调用d()
,并且如果d()
抛出异常,则异常将从 d 传播到 c 到 b 到 a,除非这些方法之一捕获到异常。
简短回答:未捕获的异常在调用堆栈中传播,直到堆栈变空,这种传播称为异常传播。
长答案: 方法抛出异常后,运行时系统在调用堆栈中搜索包含可以处理异常的代码块(异常处理程序)的方法。搜索从发生错误的方法开始,并以调用方法的相反顺序通过调用堆栈进行。当找到合适的处理程序时,运行时系统会将异常传递给处理程序。此外,还有一个值得注意的点:
可以说,我们有一个方法链,其中 method3() 调用 method2(),method2() 调用 method1()。所以当
1) 在method3() 中发生异常,在method3() 中我们没有任何异常处理程序。
2) 未捕获的异常将在堆栈中向下传播,即它将检查method2() 中的适当异常处理程序。
3) 再次在 method2 中,如果我们没有任何异常处理程序,则再次将异常向下传播到 method1() 找到异常处理程序的地方。
例子:
class ExceptionPropagation{
void method3(){
int result = 100 / 0; //Exception Generated
}
void method2(){
method3();
}
void method1(){
try{
method2();
} catch(Exception e){
System.out.println("Exception is handled here");
}
}
public static void main(String args[]){
ExceptionPropagation obj=new ExceptionPropagation();
obj.method1();
System.out.println("Continue with Normal Flow...");
}
}
输出 :
异常在这里处理
继续正常流程...
仅传播未经检查的异常。检查异常抛出编译错误
[1] http://docs.oracle.com/javase/tutorial/essential/exceptions/definition.html
每当调用方法时,都会形成堆栈,并且首先从堆栈顶部抛出异常,如果未捕获,它将开始向下堆栈到先前的方法,直到未捕获为止。如果异常即使在到达堆栈底部后仍未被捕获,它会传播到 JVM 并终止程序。
未经检查的异常会在 java 中自动传播。节目 >
public class ExceptionTest {
public static void main(String[] args) {
method1();
System.out.println("after calling m()");
}
static void method1() {
method2();
}
static void method2() {
method3();
}
static void method3() {
throw new NullPointerException();
}
}
为了传播检查的异常,方法必须使用 throws 关键字抛出异常。节目 >
public class ExceptionTest {
public static void main(String[] args)
throws FileNotFoundException {
method1();
System.out.println("after calling m()");
}
static void method1() throws FileNotFoundException{
method2();
}
static void method2() throws FileNotFoundException{
method3();
}
static void method3() throws FileNotFoundException{
throw new FileNotFoundException();
}
}
传播未经检查的异常 (NullPointerException) >
使用 throws 关键字传播检查的异常 (FileNotFoundException) >
来自:http ://www.javamadesoeasy.com/2015/05/exception-propagation-in-java-deep.html
当异常发生时,传播是一个过程,其中异常从堆栈顶部到底部并进入调用链以被剪切,如果没有在那里捕获,则异常再次下降到前一个方法,依此类推,直到它被捕获或到达调用堆栈的最底部。这称为异常传播。
例如假设我们的堆栈是:
C()
b()
一种()
主要的()
如果在 c() 方法中发生异常并且如果它没有被处理,它将被传播到之前的 b() 方法,如果它没有在那里处理,它再次被传播到处理异常的 a() 方法等等。
异常可以在调用堆栈中的任何方法中处理,无论是 main() 方法、a() 方法、b() 方法还是 c() 方法。
回复主题
假设您有一个对象调用另一个对象,然后该对象调用另一个对象。如果在任何被调用的对象中抛出异常并且它没有被捕获,那么异常就会传播到调用方法(如果在任何地方都没有被捕获,则应用程序崩溃)。
class MyClass{
void myMethod(){
A a = new A();
a.doSomething(0);
}
}
class A{
double doSomething(int n){
return 1/n;
}
}
如果myMethod
执行了方法,就会在doSomething
object 的方法中抛出异常A
,并且异常传播到堆栈中的调用方法(因此在本例中异常传播到myMethod
of myClass
)。
在构建程序时,错误发生的地方并不是处理它的最佳位置,即错误是在错误发生的地方而不是错误发生的地方处理的。
如果我们为什么需要这个功能或者我们什么时候使用它,这反过来又可以回答这个功能的目的,
在几件事中,异常反向传播沿方法调用层次结构向后传播启用了 @transaction 概念,该概念是使用面向方面的编程概念自动启用的。(@transaction 有助于在 Spring 框架中回滚数据库)。在调用层次结构中声明 @transaction 的方法之前,异常传播必须自动触发 DB 回滚,然后您可以处理异常。与问题无关,但 @transaction 仅适用于运行时异常。