异常
异常
概述
异常是指程序在执行过程中出现的非正常情况,如果不处理最终会导致JVM的非正常停止
异常的抛出机制:Java把不同异常用不同的类表示,一旦发生某种异常,就创建该异常类型的对象,并且抛出(throw)。然后程序员可以捕获(catch)到这个异常现象,并处理;如果没有捕获这个异常对象,那么这个异常对象会导致程序的终止。
常见异常
Error:StackOverflowError、OOM
Exception:
编译时异常(受检异常)在执行javac.exe时出现的异常:
- ClassNotFoundException
- FileNotFoundException
- IOException
运行时异常(非受检异常)在执行java.exe时出现的异常:
- ArrayIndexOutOfBoundsException
- NullPointerException
- ClassCastException
- NumberFormatException
- InputMismatchException
- ArithmeticException
异常处理
方式一:try-catch-finally
基本结构:
1 | try{ |
使用细节:
- 如果声明多个异常类型且存在子父类关系,则子类异常要写在上面。否则无关上下。
- catch中异常处理的方式:
- 自己编写输出的语句
- printStackTrace():打印异常的详细信息
- getMessage():获取发生异常的原因
- try中声明的结构,除了try结构后就不可以再调用了
- 将一定要被执行的代码写在finally
- 无论try中或catch中是否存在仍未被处理的异常,无论try中或catch中是否存在return,都会执行。唯一的例外:System.exit(0)会强行终止当前运行的VM
- 在开发中,有一些资源(输入流、输出流、数据库连接、Sokect),在使用完后,必须显式地进行关闭,否则会导致内存泄漏。
方式二:throws+异常类型
格式:public void test() throws 异常类型1,异常类型2,.....{//可能存在编译时异常的代码}
throws处理异常的方式,仅是将可能出现的异常抛给了此方法的调用者。调用者仍要考虑如何处理异常。
方法重写的要求:(针对编译时异常)
**(重要)**子类抛出的异常类型要么和父类异常类型一样,要么是父类异常类型的子类。
throws和try-catch-finally的选择:
- 如果程序代码中,涉及到资源的调用(流、数据库连接、网络连接等),则必须考虑使用try-catch-finally来处理,保证不出现内存泄漏。
- 如果父类被重写的方法没有throws异常类型,则子类重写的方法中如果出现异常,只能考虑使用try-catch-finally进行处理,不能throws。
- 开发中,方法a中依次调用了方法b,c,d等方法,方法b,c,d之间是递进关系。此时,如果方法b,c,d中有异常,我们通常选择使用throws,而方法a中通常选择使用try-catch-finally。
抛出异常对象
异常的处理过程中有两个过程,一个是“抛”,一个是“抓“
“抛”的过程在程序上就是产生异常对象的过程,具体又可以分为自动抛和手动抛,这里的throw就是手动抛的过程
“抓”的过程实际上就是处理异常的过程,上述的throws和try-catch-finally就是处理异常的过程。
throw的使用:写在方法里,格式是throw 异常对象
,这样就可以产生一个异常对象。
例子:
1 | try{ |
这个例子是想说明,自动抛和手动抛没有本质上的区别,都能被try-catch捕获。
自定义异常
如何自定义异常?
- 继承于现有的异常体系,通常继承于RuntimeException/Exception
- 通常提供几个重载的构造器
- 提供一个全局常量,声明为:static final long serialVersionUID
使用:通过throw 自定义异常类的对象
,将异常对象抛出
如果自定义异常类是非运行时异常,则必须考虑如何处理此异常类的对象
为什么要自定义异常类呢?
我们其实更关心的是,通过异常的名称就能直接判断此异常出现的原因。既然如此,我们就有必要在实际开发场景中,不满足我们指定的条件时,指明我们自己特有的异常类。通过此异常类的名称就能判断出具体出现的原因。