学习目标
异常机制
异常概念
本质是当程序出现异常错误时,程序能安全的退出、处理完后继续执行的机制。
异常处理即程序在出现问题时一九可以正确的执行完。
代码示例:异常处理小案例
package test.Exception;
public class Test01 {
public static void main(String[] args) {
System.out.println("step1");
// 异常处理
try{ // 利用 try 来处理异常
int a = 1/0; // 正常情况下是会报异常
} catch (Exception e){ // 使用异常对象 e 来捕获异常
e.printStackTrace(); // 使用 printStackTrace() 来打印捕获的异常信息
}
System.out.println("step2");
}
}
Java 处理异常方式
1.抛出异常:在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象,会停止当前执行路径,并把异常对象提交给 JRE。
2.捕获异常:JRE 得到该异常后,会寻找相应的代码来处理该异常。JRE 在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止。
异常分类
简述
JDK 中定义了很多异常类,这些类对应了各种各样可能出现的异常事件,所有的异常对象都是派生于 Throwable 类的一个示例。如果内置的异常类不能满足需求,还可以创建自己的异常类。
Java 对异常类进行了分类,不同类型的异常分别用不同的 Java 类表示,所有异常的根类为 java.lang.Throwable。
Throwable 下又派生了两个子类 Error 和 Exception。(只需要管 Exception 即可)
Java 异常类的层次结构如下图所示:
Error 异常
Error 表示系统 JVM 已经处于不可恢复的崩溃状态中。不需要管。
Exception 异常
Exception 是程序本身能够处理的异常,如:空指针异常(NullPointerException)、数组下标越界异常(ArrayIndexOutOfBoundsException)、类型转换异常(ClassCastException)、算数异常(ArithmeticExveption)、数字格式异常(NumberFormatException)、数字格式异常(NumberFormatException)。
Exception 类是所有异常类的父类,其子类对应了各种可能出现的异常事件。
常见 Java 异常可分为:
(1)RuntimeException 运行时异常
(2)CheckedException 已检查异常
RuntimeException
由系统自动检测此类异常并将其交给缺省的异常处理程序(用户可不必对其处理)。
这类异常通常是由编程错误导致的,所以在编写程序时,不要求必须使用异常处理机制来处理这类异常,时常需要增加 “逻辑处理来避免这些异常”。
代码示例:算数异常(ArithmeticExveption):试图除 0
解决方案:
从逻辑上去处理这个异常,修改代码
package test.Exception;
public class Test02 {
public static void main(String[] args) {
int b = 0;
if (b != 0 ){ // 增加一个非 0 判断来避免异常
System.out.println(1/b);
}
}
}
代码示例:空指针异常(NullPointerException)
当程序访问一个空对象的成员变量或方法,或者访问一个空数组的成员时会发生空指针异常(NullPointerException)
解决方案:
解决空指针异常,通常是增加非空判断;
package test.Exception;
public class Test02 {
public static void main(String[] args) {
String str=null;
if (str != null ){ // 增加一个非空判断来避免异常
System.out.println(str.charAt(0));
}
}
}
代码示例:类型转换异常(ClassCastException)
在引用数据类型转换时,有可能发生类型转换异常(ClassCastException)
解决方案:
增加判断
package test.Exception;
public class Test02 {
public static void main(String[] args) {
Animal a = new Dog();
if(a instanceof Cat) { //增加一个非空判断来避免异常
Cat c = (Cat) a;
}
}
}
代码示例:数组下标越界异常(ArrayIndexOutOfBoundsException)
当程序访问一个数组的某个元素时,如果这个元素的索引超出了 0~数组长度-1 这个范围,则会出现数组下标越界异常(ArrayIndexOutOfBoundsException)
解决方案:
增加关于边界的判断来避免异常
package test.Exception;
public class Test02 {
public static void main(String[] args) {
int[] arr = new int[5];
int a = 5;
if(a < arr.length) { // 增加关于边界的判断来避免异常
Syetem.out.println(arr[a]);
}
}
}
代码示例:数字格式异常(NumberFormatException)
在使用包装类将字符串转换成基本数据类型时,如果字符串的格式不正确,则会出现数字个数异常(NumberFormatException)。
解决方案:
引入正则表达式判断是否为数字。
package test.Exception;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Test02 {
public static void main(String[] args) {
String str = "123sasd";
Pattern p = Pattern.compile("^\\d+$");
Matcher m = p.matcher(str);
if (m.matches()){ // 如果 str 匹配到数字的正则表达式,才会转换
System.out.println(Integer.parseInt(str));
}
}
}
异常注意事项:
CheckedException 已检查异常
所有不是 RuntimeException 的异常,统称为 CheckedException,又称之为 “已检查异常”。
比如 IOException、SQLException 等和用户自定义的 Exception 异常。
这类异常在编译时就必须做出处理与检查,否则无法通过编译。
两种处理办法:
(1)使用 “try/catch” 捕获异常。
(2)使用 “throws” 声明异常。
异常处理
异常处理一:try-catch-finally--捕获异常
捕获异常是通过 3 个关键词来实现的:try-catch-finally。
用 try 来执行一段程序,如果出现异常,系统抛出一个异常,可通过它的类型来捕捉(catch)并处理它,
最后一步是通过 finally 语句为异常处理提供一个统一的出口,finally 所指定的代码都要被执行。
注意点:
(1)catch 语句可有多个;
(2)finally语句只能有一个,根据自己的需求可写可不写;作用是释放资源。
(3)如果两个 catch 语句中的两个类有关系,则子类放前,父类放后。
异常处理图解:
过程详细解析如下:
当异常处理的代码执行结束以后,不会回到 try 语句去执行尚未执行的代码。
.
代码示例:try_catch_finally 异常处理
package test.Exception;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.io.FileReader;
public class Test03 {
public static void main(String[] args) {
FileReader reader = null; // reader 初始化在try 之外定义,方便最后调用 close()
try{
// 定义 reader 引用对象,需要抛出异常
reader = new FileReader("D:/阿jun.docx");
// 第一次时读第一个内容(字母),read() 读出来是 int 类型,如果想看读的内容则需要强转为 char,同时需要抛出异常
char c = (char)reader.read();
// 读第二个内容(字母)
char c2 = (char)reader.read();
System.out.println("" + c + c2);
}catch (FileNotFoundException e){
e.printStackTrace(); // 打印异常
}catch (IOException e){
e.printStackTrace(); // 打印异常
}finally{
// 操作完成以后调用 close() 关闭资源
try{
if (reader != null){
reader.close();
}
}catch (IOException e){
e.printStackTrace(); // 打印异常
}
}
}
}
异常处理二:throws子句--声明异常
当 CheckedException 产生时,不一定立刻处理它,可以再把异常 throws 出去。
在一些情况下,当前方法并不需要处理发生的异常,而是向上传递给调用它的方法处理。
如果一个方法中可能产生某种异常,但并不能确定如何处理这种异常,则应根据异常规范在方法的首部声明该方法可能抛出的异常。
如果一个方法抛出多个已检查异常,则必须在方法的首部列出所有的异常,之间以逗号隔开。
代码示例:声明异常方式的异常处理
package test.Exception;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Test04 {
// 声明异常方式的异常处理
public static void main(String[] args)/* throws Exception */ {
try {
readFile(("D:/阿jun.docx"));
} catch (Exception e) {
e.printStackTrace();
}
}
public static void readFile(String path) throws Exception{
FileReader reader = null;
try {
reader = new FileReader(path);
char c = (char) reader.read();
char c2 = (char) reader.read();
System.out.println("" + c + c2);
} finally {
try{
if (reader!=null){
reader.close();
}
}catch (IOException e){
e.printStackTrace();
}
}
}
}
try-with-resource方法:自动关闭 Closeable 接口资源
JAVA中,JVM的垃圾回收机制可以对内部资源实现自动回收,给开发者带来了极大的便利。
但是JVM对外部资源(调用了底层操作系统的资源)的引用却无法自动回收,例如数据库连接,网络连接以及输入输出IO流等。
这些连接就需要我们手动去关闭,不然会导致外部资源泄露,连接池溢出以及文件被异常占用等。
JDK7之后,新增了"try-with-reasource"。它可以自动关闭实现了AutoClosable接口的类,实现类需要实现close()方法。
"try-with-resources声明",将try-catch-finally 简化为try-catch,这其实是一种语法糖,在编译时编译器仍然会进行转化为try-catch-finally语句。
代码示例:try-with-resource方法--自动关闭 Closeable 接口资源
package test.Exception;
import java.io.FileReader;
public class Test05 {
public static void main(String[] args){
try(FileReader reader = new FileReader("D:/阿jun.docx");){
char c = (char) reader.read();
char c2 = (char) reader.read();
System.out.println("" + c + c2);
} catch(Exception e){
e.printStackTrace();
}
}
}
自定义异常
感兴趣的话自行了解。
主要是在自写框架时,会使用到自定义异常。
异常处理秘诀
利用搜索引擎解决异常问题,分四步走:
1.查看异常信息,确认异常种类和相关 Java 代码行号。
2.确定上下文相关的一些关键信息(疑难问题、需求),没搜到时就在搜索语法中加上关键词,再没搜到就删减关键词,扩大泛微。
3.拷贝异常信息,搜索引擎搜索异常问题。
遇到异常以后可以去记录下来形成一篇文章,方便后期查阅
IDEA程序调试
调试的核心是设置断点。
程序执行到断点时,会暂时挂起,停止执行。
.
.
.
.