一、java异常
try
、catch
、fianlly
、throw
和throws
1.1 异常类的继承体系
二、异常限制
2.1 方法抛出异常
当覆盖方法的时候,只能抛出在基类方法的异常说明列出的那些异常。这意味着,当基类使用的代码应用到其派生类对象的时候,一样能够正常工作。
序号 | 描述 |
---|---|
1 | 父类没有声明异常,子类也不能有 |
2 | 不可抛出原有方法抛出异常的父类或者上层类 |
3 | 子类抛出的类型不能比父类更多 |
2.2 构造器抛出异常
异常限制对构造器不起作用,派生可以抛出任何异常,而不必理会基类构造器所抛出的异常,因为基类构造器被派生类调用的关系,所以派生类构造器的异常说明必须包含基类构造器的异常说明。
public void TestException() throws IOException {
}
public SupClass() throws IOException {
}
}
class SubClass extends SupClass{
/**
* 子类构造器,必须要包含父类构造器抛出的异常,否则编译报错,同时可以抛出其他任何异常
* @throws IOException
*/
public SubClass() throws IOException,Exception {
}
/**
* 方法覆盖,不能超过父类排除异常的范围;否则编译报错
* @throws Exception
*/
public void TestException() throws IOException {
}
三、异常捕获
捕获异常必须是从小往大的方式。
3.1 java7 提供的多异常捕获
四、 try_catch_finally_return执行顺序
如果
finally
中有return
语句,那么finally
中的语句块就会将catch
语句块中的return
变量给替换掉所以不建议在return
语句块中使用return
语句
public class Client {
public static int testTryCatchFinally() {
int value = 1;
try {
value = 2;
return value;//执行到这个地方的时候,保存一个副本,继续去执行finally中的语句,
//执行完成以后,再将保存的副本return 出去。
} catch (Exception e) {
} finally {
value = 3;
// return value;//去掉,则结果是 3
}
return value;
}
public static void main(String[] args) {
System.out.println(testTryCatchFinally());
}
五、java7 的自动关闭资源的try语句
- java垃圾回收机制不会回收任何物理资源,垃圾回收这能回收堆内存中对象占用的内存。
java7 增强了try语句的功能,它允许在try 关键字后紧跟一对圆括号,圆括号可以声明、初始化一个或者多个资源。
当然这些资源实现类必须要实现 AutoCloseable
或者Closeable
接口。
public class AutoCloseTest {
public static void main(String[] args) {
try (
InputStream in = new FileInputStream(new File("D:/test.java"));
PrintStream ps = new PrintStream(new FileOutputStream("a.txt"))
) {
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
六、异常处理规则
序号 | 描述 |
---|---|
1 | 不要过度使用异常,尽量提高代码健壮性(异常机制的效率比正常的流程控制效率低) |
2 | 不要使用过于庞大的try块;如果太大,可以分多个try块 |
3 | 不要忽略捕获到的异常,看情况,尽可能处理。 |
七、异常限制
- 当
父类
与接口
具有相同的方法而且方法同时抛出不同的异常
,这个时候是不允许的
上面的代码里面,在Test类里面不能够覆盖methodA
这个方法,因为编译器不知道需要指向那个异常。正确的代码:当父类或者接口某一个的方法被注释,就可以实现的了。
- 当父类的
构造方法
抛出异常,基类必须有一个构造方法是抛出相同异常或者此异常的父类
在子类构造器中调用父类构造器的原因。
- 当父类
方法
没有抛出异常,子类覆盖的方法
不能够抛出异常
- 当父类
方法
抛出异常,子类覆盖的方法可以不抛出异常
- 子类方法只能抛出父类方法的异常或者是其子异常
主要是因为子类在做向上转型的时候,不能正确地捕获异常
7.1 小结
但是从系统设计和开发的角度来分析,则尽量不要在构造函数中抛出异常
(1)构造函数抛出错误是程序员无法处理的
(2)构造函数不应该抛出非受检查异常
参考这片文章:[改善Java代码]不要在构造函数中抛出异常
八、异常丢失
- 在finally中抛出异常,可能会之前抛出的异常丢失
package thinkinginjava;
public class FinallyException {
public static void main(String[] args){
try{
try{
throw new RedException();
}finally{
//把上一个异常覆盖掉
throw new BlueException();
}
}catch(Exception e){
System.out.println(e);
}
}
}
class RedException extends Exception{}
class BlueException extends Exception{}
运行结果:thinkinginjava.BlueException
package thinkinginjava;
public class ReturnException {
public static void main(String[] args){
try{
throw new Exception();
}finally{
return;
}
}
}
没有任何输出
参考
如何阅读异常堆栈:你真的会阅读 Java 的异常信息吗
从头认识java-10.7 使用异常的限制汇总
java异常处理(父子异常的处理)
[改善Java代码]不要在构造函数中抛出异常