Java之异常

异常

在Java对象中,异常对象都是派生于Throwable类的一个类实例

Throwable
    |-- Error
    |-- Exception
    	|-- IOException
    	|-- RuntimeException	//由编程错误导致的异常

由编程错误导致的异常属于RuntimeException;如果程序本身没有问题,但由于像I/O错误这类问题导致的异常属于其他异常。

Java语言规范将派生于Error类或RuntimeException类的所以异常称为非检查型异常(unchecked),即其他异常称为检查型异常。

如果在子类中覆盖了超类的一个方法,子类方法中声明的检查型异常不能比超类方法中声明的异常更通用(子类方法可抛出更特定的异常,或者根本不抛出任何异常)。

如果超类方法没有抛出任何检查型异常,子类也不能抛出任何检查型异常。

即是:如果编写一个方法覆盖超类,而这个超类方法没有抛出异常,那就必须捕获子类方法代码中的所有检查型异常。

一旦方法抛出了异常,这个方法就不会返回到调用者。

// 自定义异常
class MyException extends IOException{
    public MyExcetion(){}
    public MyException(String gripe){
        super(gripe);
    }
}

自定义的类中应该包含两个构造器,一个是默认的构造器,另一个是包含详细信息的构造器。

再次抛出异常时包装

可以在catch子句中抛出一个异常(通常,希望改变异常的类型时会这样做)

try{
    ... ...
} catch (SQLException e){
    throw new ServletException("database error: " + e.getMessage() );
}

不过,有一中更好的处理方法:把原始异常设置为新异常的原因

try{
    ...
} catch (SQLException original){
    var e = new ServletException("database error");
    e.initCause(original);
    throw e;
}

// 获取异常、
Throwable original = caughtException.getCause();

建议使用该种包装技术。这样可以在子系统中抛出高层异常,而不会丢失原始异常的细节。、

finally-return

==警告:==当finally子句包含return语句时,finally块中的return返回值会屏蔽掉整个try的返回值。

public static int parseInt(String s){
    try {
        return Integer.passeInt(s);
    } finally {
        return 0; // ERROR!!!
    }
}
  • 看起来会在 parseInt("42")调用中,try块的整体会返回整数42。不过,这个方法真正返回之前,会执行finally子句,使得方法最终返回0,而忽略之前的原返回值。
  • 更糟糕的是,考虑调用parseInt("zero")时,Integer.parseInt() 方法会抛出NumberFormatException 异常。然后执行finally子句,return语句甚至会吞掉整个异常!
  • *finally子句的体要用于清理资源。*不要将改变控制流的语句(return, throw, break, continue)放在finally子句中。
try-with-Resources

在Java 7中,常规关闭资源方式

// open a resource
try{
    // work with resource
} finally {
    // close the resource 
}

使用try-with-resources语句:

try(Resource res = ... ){
    // work with res
}

当 try 代码块(正常或异常)退出时,会自动调用 res.close()

/**
 * 指定多个资源
 */
try (var in = new Scanner(new FileInputStream("in.txt"), StandardCharsets.UTF_8);
     var out = new PrintWriter("out.txt", StandardCharsets.UTF_8))
{
    // work with resources
}

// 在Java 9 中,可以在try首部中提供之前声明的实事最终变量
public static printAll(String[] lines, PrintWirter out){
    try (out){	// efectively final variable
        ... ...
    }
}

try-with-resources自身也可以有 catch 子句,甚至还可以有一个 finally 子句。这些会在关闭资源之后执行。

异常使用技巧
  1. 异常处理不能代替简单的测试

    ​ 与简单的测试相比,捕获异常所花费的时间远大于普通检测代码,因此使用异常的基本规则是:只在异常情况下使用异常

  2. 不要过分地细化异常
    将正常处理与错误处理分开

  3. 充分利用异常层次结构

    • 不要只抛出 RuntimeException 异常,应该寻找一个合适的子类创建自己的异常类

    • 不要只捕获 Throwable 异常,否则将会使得代码更难度、更难维护

    • 考虑检查型异常与非检查型异常的区别。检查型异常本来就庞大,不要为逻辑错误抛出这些异常。

  4. 不要压制异常

  5. 检测错误时,“苛刻”比放任更好
    栈空调用 Stack.pop 时,返回null还是抛出异常?一般认为:最好在出错的地方抛出一个 EmptyStackException异常,要好于以后抛出一个空指针异常

  6. 不要羞于传递异常

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值