java异常设计

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java异常设计相关的知识,希望对你有一定的参考价值。

  • 异常的分类结构图

技术分享图片

  • 异常机制是为了解决什么问题?

它也是线程结束的一种方式,从某中角度来讲,它与正常return没有什么区别,只不过是一种异常的方式结束。那为什么需要这种异常的机制呢?异常机制本身也是划分了严重程度,如:Error/Exception. 它以一种不侵入正常流程编码的形式,尽量不让程序崩溃(Error类型的异常), 同时给开发者友好的提示信息(方便问题的定位)。

  • 各种异常在什么场景下出现?能否处理?

Error错误

  这种异常通常都是程序级别的错误,直接会引起程序崩溃。

  常见的异常有:VirtualMachineError(jvm错误)、AWTError、OutOfMemoryError(堆内存溢出)、StackOverflowError(栈内存溢出)、NoClassDefFoundError、NoSuchMethodError。

  这种错误通常程序本身无法处理,需要对JVM优化处理,如:参数大小设置、引入依赖包等。

RuntimeException运行时异常

  这种异常通常都是在程序运行的过程中出现的异常。要么是BUG,要么是参数错误,而这一切的异常情况在编码的时候根本无法预料。会让单个方法的调用直接异常结束.

  常见的异常有:IllegalArgumentException(不合法参数异常)、IllegalAccessException(不合法的访问)、ClassCastException(类型转换异常)、IndexOutOfBoundsException(边界异常)、NumberFormatException(数字格式异常).

  运行时异常通常有传入的参数错误或程序BUG引起,这种异常需要用户或开发者根据提示信息来修改问题。

CheckedException检查型异常

  非运行时异常,是在编码时显示定义的异常,这种异常必须捕获(try catch)或抛出(throws),否则编译时无法通过。

  常见的异常有:IOException(IO异常,如:SocketException网络异常,文件流异常)、SQLException(sql异常).

  检查型异常,通常都是可预见的异常情况,而在编码的时候进行的一种补救措施。

  • 根据什么来设计异常?

根据异常类型来设计

  Error错误类型的异常,通常都属于系统级别的问题. 除非我们要去终止整个进程,否则我们一般都不会涉及到此类的异常设计;

  CheckedException可检查型异常,属于应用编码级别的问题.它属于一种备用手段,比如:SocketException/FileException,捕获之后,还可以进一步的补救.我认为它属于一个另类的编程思想.

  RuntimeException运行时异常,属于请求级别/一次方法调用的问题. 在程序处理的时候,总会有想不周全的问题.比如:用户传入的参数不正确;开发者的BUG;这种问题通常都会中止此次请求或方法调用,返回错误提示信息,然后再由对应的人员去解决.


根据谁造成的问题谁来解决的原则

引起异常问题的原因无非两种:客户和开发者.

当我们的应用内存不够或磁盘空间不足或系统宕机,这种出现系统级别的错误. 只能由运维或开发者来解决,对于客户来说并不可见,也并不关心.

当我们的应用某个方法中的片段代码,因为开发者的疏忽,而非造成的BUG.这种问题只能由开发者来解决,对于客户来说并不可见,也不关心.

当客户调用某个方法时,传入的参数不正确或数据不正确,这种问题只能由客户来解决,而开发者只需要友好的提示给客户.


  • 异常的设计样例

/**
 * 程序BUG出现的异常.用于开发者定位问题所在.
 * @author yangyc
 */
public class AppException extends RuntimeException{

    public AppException(String message, Throwable cause) {
        super(message, cause);
    }
}

/**
 * 提示性异常.由调用者来解决.如果参数为空,参数格式不正确,数据获取不到等.
 * @author yangyc
 */
public class PromptException extends RuntimeException {
    public PromptException(String message, Throwable cause) {
        super(message, cause);
    }
}

/**
 * 远程调用服务的异常.这种在编码期就可以预料到的问题.
 * @author yangyc
 */
public class RpcException extends Exception {
    public RpcException(String message, Throwable cause) {
        super(message, cause);
    }
}


  • 使用异常技巧

1.什么时候使用检查型异常或运行时异常?

   异常可预见或可补救的情况,采用检查型异常,从编码的角度增强程序的健壮性. 相反无法预料, 问题出现就必须中止的问题,采用运行时异常.

2.异常什么时候捕获?

   通常在调用起点捕获或AOP的更上层统一处理,中间不要去捕获; 明确知道问题并可以对此类异常处理,则捕获,而这种类型的异常,通常都会进行异常转换,继续往上层抛出.

3.异常捕获时,try catch的内容应该是多少?

   一般不宜将捕获的代码太长,会影响异常处理机制的复杂度;同时,也应考虑将紧密代码放在一起,保证代码的可读性.

4.异常的转换

  有些时候,捕获异常之后,会抛出一个新异常,继续由后续程序处理.这时,就需要进行异常的转换.比如:将检查型异常转换成运行时异常.

5.异常的传递

  当出现异常转换时,要注意原始异常信息不丢失.应该使用 new XxxException(msg, e)这个方法.

6.尽早抛出异常,尽晚的捕获异常,明确的抛出异常类型

7.捕获异常后,不要忽略异常

public void doNotIgnoreExceptions() {
    try {
        // do something
    } catch (NumberFormatException e) {
        // this will never happen
    }
}

8.不要捕获Throwable

Throwable是所有异常(Exception)和错误(Error)的父类,虽然它能在catch从句中使用,但永远都不要这样做!如果你在catch从句中使用了Throwable,它将不仅捕获所有异常,它还将捕获所有错误,错误是由JVM抛出的,用来表明不打算让应用来处理的严重错误。OutOfMemoryError和StackOverflowError便是典型的例子,它们都是由于一些超出应用处理范围的情况导致的。


https://www.cnblogs.com/beatIteWeNerverGiveUp/p/5915255.html


以上是关于java异常设计的主要内容,如果未能解决你的问题,请参考以下文章

java 反射代码片段

片段中的 EditText 上的空指针异常 [重复]

Java异常处理机制

Java异常处理和设计

片段 getArguments() 空指针异常

Java语言基础之方法的设计