Java漫游笔记-06-异常

人非圣贤,孰能无过?

其实圣贤也会犯错,更何况是人(yuan)写的程序。
不过,程序出错时,只要能做到以下几点,用户一般就会原谅你:

  • 用恰当的方式告知用户。
  • 处理异常,把程序拉回安全的状态,让用户可以继续操作。
  • 否则,保存数据并以合适的方式退出。

异常处理机制

Java 语言本身提供了一套异常处理机制:当我们的程序不能按照正常路径执行时,可以通过另一条路径退出
在 Java 中,如果某个方法执行出错,就会抛出一个封装了错误信息的异常对象。

异常继承结构

学习 Java 的异常处理机制,既要学习它特定的语法,还要大致了解相关类的继承结构。

Java 的设计者把程序出错的类型分为:ErrorException ,它们都继承自 Throwable 类。

只有当对象是 Throwable 类(以及它的子类)的实例时,才能通过 Java 虚拟机或者 throw 语句抛出。类似地, catch 语句也只能 catch 它的对象。

Throwable 对象一般包含其创建时的线程执行堆栈快照,错误信息的字符串,原因(cause)等内容。

Error

在 Java 中,Error 是非常严重的问题,例如,虚拟拟机崩溃、内存溢出之类的,程序不应尝试抛出这种类型的异常对象
遇到这种错误,我们基本上也无能为力,让它随风飘逝吧。

Exception

Exception 又分为运行时异常( RuntimeException )和非运行时异常。

运行时异常

RuntimeException 是 Java 虚拟机正常运行期间抛出的异常。
运行时异常一般是由开发者自己编写的程序导致的。
常见的有:

  • 空指针异常:NullPointerException
  • 类型强制转换异常:ClassCastException
  • 参数异常:IllegalArgumentException
  • 数组越界异常:ArrayIndexOutOfBoundsException

如果出现 RuntimeException 就该自己来擦屁股了。

非运行时异常

程序本身并没有错,但是由于执行了某些特定的操作又有可能会产生问题,编译器强制你先打预防针的,就属于非运行时异常。
常见的有:

  • I/O 操作可能生成的异常:IOException
  • 数据库操作可能生成的异常:SQLException
  • 试图通过类名加载类可能生成的异常:ClassNotFoundException

对于非运行时异常,如果我们能够处理,就处理。
如果不能处理,则应该往外抛出,让别人继续来处理,而不是粗暴地把它吃掉。

自定义异常

虽然 Java 的类库预定义了很多异常,但是如果这些都不是你的菜,那么自定义异常就是顺理成章的事。
自定义异常很简单,直接继承 Exception 或者是 RuntimeException 即可。

异常处理语法

关于 finallyreturn 的关系,只要记住 2 点就行了:

  • finally 总是会被执行。
  • return 是当前方法的出口。

因此,只要有 finally ,无论是否发生异常,在你结束方法之前,都会跑到它那里。
如果 finally 里面有 return ,那么就意味着:不管你前面是否有 return (或者是 throw ),执行到 finallyreturn ,就该说拜拜了。

总而言之,如果你想在 catch 中返回,或者是继续抛出异常,那么就不要在 finally 里面也返回。

另外,如果需要把已捕获的异常重新抛出,注意使用带 cause 的构造方法,或者是调用 initCause() 方法,来避免堆栈信息的丢失。

断言(assert)和异常的区别

  • 断言是一种错误检查机制。
  • 断言相当于前置条件,它的错误是致命的、不可恢复的。
  • 断言一般只用于开发和测试阶段,在生产环境中应该禁用。