本质是当程序出现异常错误时,程序能安全的退出、处理完后继续执行的机制。
异常处理即程序在出现问题时一九可以正确的执行完。
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"); } }
1.抛出异常:在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象,会停止当前执行路径,并把异常对象提交给 JRE。
2.捕获异常:JRE 得到该异常后,会寻找相应的代码来处理该异常。JRE 在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止。
JDK 中定义了很多异常类,这些类对应了各种各样可能出现的异常事件,所有的异常对象都是派生于 Throwable 类的一个示例。如果内置的异常类不能满足需求,还可以创建自己的异常类。
Java 对异常类进行了分类,不同类型的异常分别用不同的 Java 类表示,所有异常的根类为 java.lang.Throwable。
Throwable 下又派生了两个子类 Error 和 Exception。(只需要管 Exception 即可)
Java 异常类的层次结构如下图所示:
Error 表示系统 JVM 已经处于不可恢复的崩溃状态中。不需要管。
Exception 是程序本身能够处理的异常,如:空指针异常(NullPointerException)、数组下标越界异常(ArrayIndexOutOfBoundsException)、类型转换异常(ClassCastException)、算数异常(ArithmeticExveption)、数字格式异常(NumberFormatException)、数字格式异常(NumberFormatException)。
Exception 类是所有异常类的父类,其子类对应了各种可能出现的异常事件。
常见 Java 异常可分为:
(1)RuntimeException 运行时异常
(2)CheckedException 已检查异常
由系统自动检测此类异常并将其交给缺省的异常处理程序(用户可不必对其处理)。
这类异常通常是由编程错误导致的,所以在编写程序时,不要求必须使用异常处理机制来处理这类异常,时常需要增加 “逻辑处理来避免这些异常”。
解决方案:
从逻辑上去处理这个异常,修改代码
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)
解决方案:
解决空指针异常,通常是增加非空判断;
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)
解决方案:
增加判断
package test.Exception; public class Test02 { public static void main(String[] args) { Animal a = new Dog(); if(a instanceof Cat) { //增加一个非空判断来避免异常 Cat c = (Cat) a; } } }
当程序访问一个数组的某个元素时,如果这个元素的索引超出了 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)。
解决方案:
引入正则表达式判断是否为数字。
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)); } } }
所有不是 RuntimeException 的异常,统称为 CheckedException,又称之为 “已检查异常”。
比如 IOException、SQLException 等和用户自定义的 Exception 异常。
这类异常在编译时就必须做出处理与检查,否则无法通过编译。
两种处理办法:
(1)使用 “try/catch” 捕获异常。
(2)使用 “throws” 声明异常。
捕获异常是通过 3 个关键词来实现的:try-catch-finally。
用 try 来执行一段程序,如果出现异常,系统抛出一个异常,可通过它的类型来捕捉(catch)并处理它,
最后一步是通过 finally 语句为异常处理提供一个统一的出口,finally 所指定的代码都要被执行。
注意点:
(1)catch 语句可有多个;
(2)finally语句只能有一个,根据自己的需求可写可不写;作用是释放资源。
(3)如果两个 catch 语句中的两个类有关系,则子类放前,父类放后。
过程详细解析如下:
当异常处理的代码执行结束以后,不会回到 try 语句去执行尚未执行的代码。
.
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(); // 打印异常 } } } }
当 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(); } } } }
JAVA中,JVM的垃圾回收机制可以对内部资源实现自动回收,给开发者带来了极大的便利。
但是JVM对外部资源(调用了底层操作系统的资源)的引用却无法自动回收,例如数据库连接,网络连接以及输入输出IO流等。
这些连接就需要我们手动去关闭,不然会导致外部资源泄露,连接池溢出以及文件被异常占用等。
JDK7之后,新增了"try-with-reasource"。它可以自动关闭实现了AutoClosable接口的类,实现类需要实现close()方法。
"try-with-resources声明",将try-catch-finally 简化为try-catch,这其实是一种语法糖,在编译时编译器仍然会进行转化为try-catch-finally语句。
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.拷贝异常信息,搜索引擎搜索异常问题。
遇到异常以后可以去记录下来形成一篇文章,方便后期查阅
调试的核心是设置断点。
程序执行到断点时,会暂时挂起,停止执行。
.
.
.
.