1. 异常概念
在程序中也是一样,程序猿是一帮办事严谨、追求完美的高科技人才。在日常开发中,绞尽脑汁将代码写的尽善尽美,在程序运行过程中,难免会出现一些奇奇怪怪的问题。有时通过代码很难去控制,比如:数据格式不对、网络不通畅、内存报警等。一位好的程序猿也要学习如何处理异常,完善我们的代码和程序。
2. 常见异常
java.lang.RuntimeException: 运行时异常
ClassCastException: 类类型转换异常,当试图将对象强制转换为不是实例的子类时,抛出该异常;
ArrayIndexOutOfBoundsException: 数组下标越界异常,当你使用不合法的索引访问数组时会抛出该异常;
NullPointerException: 空指针异常,通过null进行方法和属性调用会抛出该异常;
ArithmeticException: 算术运算异常,除数为0,抛出该异常;
NumberFormatException: 数字转换异常,当试图将一个String转换为指定的数字类型,而该字符串确不满足数字类型要求的格式时,抛出该异常;
InputMismatchException: 输入不匹配异常,输入的值数据类型与设置的值数据类型不能匹配。
2.1 java异常体系结构:
从上图中可以看到:
- Throwable : 是异常体系的顶层类,其派生出两个重要的子类 , Error 和 Exception
- Error : 指的是 Java 虚拟机无法解决的严重问题,比如: JVM 的内部错误、资源耗尽等 ,典型代表:
StackOverflowError 和 OutOfMemoryError ,一旦发生回力乏术。 - Exception : 异常产生后程序员可以通过代码进行处理,使程序继续执行。比如:感冒、发烧。我们平时所说的异常就是Exception 。(主要研究)
3. 异常分类
3.1 编译时异常(CompilationException):
通俗点儿讲:就是我们在编写代码时的异常(比如代码下面出现红色的波浪线)
3.1.1 IOException 输入输出流异常
广泛的说,什么时候会有IOException ,比如你文件都不到的时候 ,你在做数据库操作的时候数据库底层出现问题 ,或者你系统IO出问题了 ,系统拿不到文件句柄 ,你说的读着读着突然被删了,你可以试试,书不定真可以 ,你可以看有多少IOExeption个子类,差不多就有多少种类型。
3.1.2 FileNotFoundException 文件找不到的异常
注意,这里的找不到是在你的编译结果文件夹里面找不到,而不是在你的工程里面找不到,很多同学说自己工程里面有这个文件,为什么还要报这个异常?这个时候,你最好跑到你的编译文件放的文件夹下面,比如tomcat的webapps文件夹下面,找找你的工程对应的文件夹,看看那个里面有没有你的文件
3.1.3 ClassNotFoundException 类找不到异常
属于编译时异常,是在classloader加载类的时候发现类不存在在类路径的时候报出的。
3.1.4 DataFormatException 数据格式化异常
3.1.5 NoSuchFieldException 没有匹配的属性异常
3.1.6 NoSuchMethodException 没有匹配的方法异常
3.1.7 SQLException 数据库操作异常
3.1.8 TimeoutException 执行超时异常
3.2 运行时异常(RuntimeException):
通俗点儿讲:就是我们在执行代码时的异常(运行框会报出以下名字的异常)
ArrayIndexOutofBoundsException 数组越界异常
ClassCastException 类型转换异常
NullPointerException 空指针异常
IllegalAccessException 非法的参数异常
InputMismatchException 输入不匹配异常
4. 异常的处理方法
4.1 事前防御型
通俗点儿讲:在操作之前就做充分的检查,例如:
boolean ret = false;
ret = 登陆游戏();
if (!ret) {
处理登陆游戏错误;
return;
}
ret = 开始匹配();
if (!ret) {
处理匹配错误;
return;
}
ret = 游戏确认();
if (!ret) {
处理游戏确认错误;
return;
}
优点:可以时时了解代码中的异常方便且快速找到异常位置并处理。
缺陷:正常流程和错误处理流程代码混在一起 , 代码整体显的比较混乱,过程繁琐。
(不加return的话,一旦出现一个异常,后面异常会一起抛出,分辨不清)
4.2 事后认错型
通俗点儿讲:就是先操作, 遇到问题再处理,例如:
try {
登陆游戏();
开始匹配();
游戏确认();
选择英雄();
载入游戏画面();
...
} catch (登陆游戏异常) {
处理登陆游戏异常;
} catch (开始匹配异常) {
处理开始匹配异常;
} catch (游戏确认异常) {
处理游戏确认异常;
} catch (选择英雄异常) {
处理选择英雄异常;
} catch (载入游戏画面异常) {
处理载入游戏画面异常;
}
上述代码意思是:try{}中编写的是可能出现的异常的代码,catch()中写异常的名字例如(NullPointerException、ArithmeticException等),catch(){}中写异常的处理。(不明白的话可以往下面看,有详细介绍try()和catch() )
优势:正常流程和错误流程是分离开的 , 程序员更关注正常流程,代码更清晰,容易理解代码
异常处理的核心思想 。
缺点:部分异常执行后需要及时处理,这个方式需要等待try{}中所有代码执行完成
特别注意:如果catch()中异常之间有父子关系,那么一定是子类异常在前catch,父类异常在后catch,否则报错。
5. 编写异常throw(重点)
有些情况下我们想自定义一个异常,或者我们忘记了java中的异常名字也需要自定义异常,或者在 Java 中,可以借助 throw 关键字,抛出一个指定的异常对象,将错误信息告知给调用者。具体语法如下:(使用很频繁)
throw new XXXException("异常产生的原因");
实例:实现一个获取数组中任意位置元素的方法。
public static int getElement(int[] array, int index){
if(null == array){
throw new NullPointerException("传递的数组为null");
}
if(index < 0 || index >= array.length){
throw new ArrayIndexOutOfBoundsException("传递的数组下标越界");
}
return array[index];
}
public static void main(String[] args) {
int[] array = {1,2,3};
getElement(array, 3);
}
结果:
传递的数组下标越界
【 注意事项 】
- throw 必须写在方法体内部
- 抛出的对象必须是 Exception 或者 Exception 的子类对象
- 如果抛出的是 RunTimeException 或者 RunTimeException 的子类,则可以不用处理,直接交给 JVM 来处理,JVM处理完程序终止,这就是我们平常遇到异常时所看到的机制,也是java默认的。
- 如果抛出的是编译时异常,用户必须处理,否则无法通过编译
- 异常一旦抛出,其后的代码就不会执行(特别注意)