我不得不用一些代码回答这个问题:
假设我编写了以下方法规范:
public void manipulateData ( ) throws java.sql.SQLException, java.sql.SQLDataException
您正在为数据库编写代码 将使用此方法并且您想要处理每个方法的程序 特别。 try / catch子句应该是什么样的?
您可以使用no-ops-- empty blocks {} - 用于catch子句内容 我们只对这里的语句的语法和结构感兴趣。
我回答说:
try {
} catch(java.sql.SQLException e) {
}
catch(java.sql.SQLDataException e) {
}
由于这个原因,他没有接受答案:
“您的捕获条款的顺序错误。您能解释一下订单的重要性吗?”
他的回答是否正确?
答案 0 :(得分:42)
是的,他是对的。正如您在Javadoc中看到的那样,SQLDataException
是SQLException
的子类。因此,您的答案是错误的,因为它会在第二个catch
中创建一个无法访问的代码块。
在Java中,这段代码甚至无法编译。在其他语言(例如python)中,这样的代码会创建一个微妙的bug,因为SQLDataException
实际上会在第一个块中捕获,而不是在第二个块中捕获(如果它不是子类的话就是这种情况)。
如果你回答catch(java.sql.SQLException | java.sql.SQLDataException e) { }
,它仍然是不正确的,因为问题要求具体处理每个例外。
正确答案在Grijesh's answer
答案 1 :(得分:22)
在Java中,您必须首先放置包含最少的Exception。接下来的例外必须更具包容性(当它们相关时)。
例如:如果你把所有(最多)的包容性放在首位,那么永远不会调用下一个。像这样的代码:
try {
System.out.println("Trying to prove a point");
throw new java.sql.SqlDataException("Where will I show up?");
}catch(Exception e){
System.out.println("First catch");
} catch(java.sql.SQLException e) {
System.out.println("Second catch");
}
catch(java.sql.SQLDataException e) {
System.out.println("Third catch");
}
永远不会打印您希望打印的信息。
答案 2 :(得分:6)
由于以下原因,在捕获异常时排序很重要:
记住:
e
是参考变量catch(ExceptionType e){ }
小写字符e是对抛出(和捕获)ExceptionType
对象的引用。
您的代码未被接受的原因是什么?
重要的是要记住异常子类必须在它们的超类之前。这是因为使用超类的catch语句将捕获该类型及其任何子类的异常。因此,如果它来自超类,则永远不会到达子类 此外,在Java中,无法访问的代码是错误。
SQLException
是SQLDataException
+----+----+----+
| SQLException | `e` can reference SQLException as well as SQLDataException
+----+----+----+
^
|
|
+----+----+----+---+
| SQLDataException | More specific
+----+----+----+---+
如果你的写作有错误Unreachable code
(阅读评论):
try{
}
catch(java.sql.SQLException e){//also catch exception of SQLDataException type
}
catch(java.sql.SQLDataException e){//hence this remains Unreachable code
}
如果尝试编译此程序,您将收到一条错误消息,指出第一个catch语句将处理所有基于SQLException的错误,包括SQLDataException。 这意味着第二个catch语句永远不会执行。
正确解决方案?
要修复它反转catch语句的顺序。接下来是:
try{
}
catch(java.sql.SQLDataException e){
}catch(java.sql.SQLException e){
}
答案 3 :(得分:5)
SQLDataException
将永远不会被点击,因为SQLException
会在到达SQLDataException
之前捕获任何SQL例外。
SQLDataException
是SQLException
的子类
答案 4 :(得分:5)
考虑异常的继承层次结构:SQLDataException extends SQLException
因此,如果首先捕获“泛型”(即层次结构中最顶层的基类),那么“下面”的每个东西都属于同一类型由于多态性,即 SQLDataException isa
SQLException
因此你应该按照自下而上的顺序捕获它们w.r.t.继承层次结构,即子类首先一直到(泛型)基类。这是因为catch
子句按照您声明它们的顺序进行评估。
答案 5 :(得分:2)
Java Language Specification§11.2.3解释了这种情况:
如果catch子句可以捕获,则编译时错误 异常类E1和紧接着的前一个catch子句 封闭的try语句可以捕获E1或E1的超类。
普通英语版本:
更一般的例外必须在具体的例外之后。 更一般的例外必须在特定的例外之后。
答案 6 :(得分:1)
对于编译器,多个catch语句类似于if..else if..else if ..
因此,从编译器可以映射生成的异常(直接或通过隐式类型转换)的角度来看,它不会执行后续的catch语句。
为了避免这种隐式类型转换,您应该最后保留更通用的异常。应该在他的捕获语句的开头说明更多的派生,并且最通用的应该在最后的捕获声明中说明。
SQLDataException派生自SQLException,它是来自Exception的实习生。因此,您将无法执行catch(java.sql.SQLDataException e){}
此块中编写的任何代码。编译甚至是那种情况的标志,它是一个死代码并且不会被执行。
答案 7 :(得分:1)