| 一、异常机制 | 1.异常的概念 | 掌握 |
|---|---|---|
| 2.异常的本质 | 掌握 | |
| 3.异常的分类 | 掌握 | |
| 二、异常处理 | 1.try-catch-finally | 掌握 |
| 2.throws声明异常 | 掌握 | |
| 3.try-witch-resource新特性 | 掌握 | |
| 4.自定义异常 | 了解 | |
| 三、学会使用百度处理异常 | 1.处理异常的步骤 | 掌握 |
| 2.百度:超级搜索 | 掌握 | |
| 四、IDEA调试功能 | 如何使用IDEA调试功能进行调试 | 掌握 |
异常
一、异常机制
1.异常的概念
当程序运行出现意外情况时,如:用户输入错误、除数为0、需要处理的文件不存在、数组下标越界等,Java异常机制会自动生成一个Exception对象来通知程序,从而可以使程序中的异常处理代码和正常业务代码分离,提供更好地可读性和提高程序的健壮性。
2.异常的本质
所谓异常,就是程序在出现问题时,程序安全退出、异常机制处理完后依然可以正确地执行完。
package com.sundegan;public class Test {public static void main(String[] args) {System.out.println("step1");int i = 1/0;System.out.println("step2");}}//step1//Exception in thread "main" java.lang.ArithmeticException: / by zero// at com.sundegan.Test.main(Test.java:6)
程序出错后直接停止运行,”step2”不能继续执行。
public class Test {public static void main(String[] args) {System.out.println("step1");try {int i = 1/0;}catch (Exception e){e.printStackTrace();//打印异常信息}System.out.println("step2");}}//step1//java.lang.ArithmeticException: / by zero// at com.sundegan.Test.main(Test.java:7)//step2
程序在出现错误时,通过异常处理处理完后,依然可以往下执行。
Java是采用面向对象的方式来处理异常的,处理过程:
1)抛出异常:在执行一个方法时,如果发生异常,则这个方法生成代表该异常的一个对象,停止当前程序的执行,把异常对象提交给JRE。
2)捕获异常:JRE得到该异常对象后,寻找对应的代码来处理该异常。JRE在方法的调用栈中查找,从生成异常的方法开始回溯,直到找到相应的异常处理代码为止。
3.异常的分类
Java异常机制中引入了很多用来描述和处理异常的类,称为异常类,异常类定义中包含了该类异常的信息和对异常进行处理的方法,不同类型的异常用不同的Java类来表示,所有异常的跟类为java.lang.Throwable,Throwable下面又派生了两个子类:Error和Exception。Java异常类结构层次图如下所示:
3.1 Error
Error错误,一般是指与虚拟机相关的问题,如系统崩溃、虚拟机错误等,这种错误无法恢复或不可能捕获,将导致应用程序中断。通常应用程序无法处理这些错误,因此不应该试图使用catch来捕获Error对象。在定义方法时,也无须在其throws子句中声明该方法可能抛出Error及其任何子类。
3.2 Exception
异常是程序自身能处理的,如空指针异常、数组索引越界异常、类型转化异常、算术异常。Java将异常分为两种,Checked异常和Runtime异常,Java认为Checked异常都是可以在编译阶段被处理的异常,所以它强制程序处理所有的Checked异常;而Runtime异常则无须处理。
3.3 RuntimeException
Runtime运行时异常,如被0除、数组下标越界、空指针等,其产生比较频繁,处理麻烦,如果显式地声明或捕获将会对程序可读性和运行效率影响很大,因此由系统自动检测并交给缺省的异常处理程序(用户不用处理)。这类异常通常由编程错误导致,在编程时并不要求通过异常处理机制来处理这类异常,通常通过增加逻辑处理来避免这些异常。
public class Test {public static void main(String[] args) {//除数为0异常int b = 0;if(b != 0){c = a / b;}//空指针异常String str = null;if(str != null){System.out.println(str.charAt(0));}}}
class Animal{}class Dog extends Animal{}class Cat extends Animal{}public class Test {public static void main(String[] args) {//ClassCastException异常Animal a = new Dog();//Cat c = (Cat) a;这里不能强制类型转换if(a instanceof Cat){Cat c = (Cat) a;}}}
public class Test {public static void main(String[] args) {//数组索引越界异常int[] a = new int[5];//System.out.println(a[5]);只能到4int index = 5;if(index < 5 && index >= 0){System.out.println(a[index]);}//数字格式化异常String str = "123abc";System.out.println(Integer.parseInt(str));//引入正则表达式判断是否为数字Pattern p = Pattern.compile("^\\d+$");Matcher m = p.matcher(str);if(m.matches()){//如果str都为数字才会转换System.out.println(Integer.parseInt(str));}}}
3.4 CheckedException
所有不是RuntimeException的异常统称为CheckedException,又被称为“已检查异常”,如IOException、SQLException、用户自定义的异常等。这类异常在编译时必须被处理,否则无法通过编译。
二、异常处理
1.异常的处理方式之一:捕获异常
捕获异常通过使用三个关键字来实现的:try—catch—finally。使用try来执行一段程序,如果出现异常,系统抛出一个异常,可以通过它的类型来捕获(catch)处理。最后,通过finally为异常处理提供一个统一的出口,不管有没有出现异常,finally所指定的代码都会被执行。catch语句可有多条,分别捕获不同类型的异常,finally语句只能有一条,根据需要可有可无。
try{语句1;语句2;......}catch (Exception1 e){处理代码;}catch (Exception2 e){处理代码;}finally {资源回收语句;}
如果需要捕获的异常间存在父子关系,则子类异常放前面捕获,父类异常放后面捕获。
try—catch—finally语句块的执行过程:程序首先执行可能发生异常的try语句块,如果try语句块没有出现异常则正常向下执行,最后跳到finally语句块执行。如果try语句块出现异常,则中断执行并根据异常类型跳至相应的catch语句块处理,catch语句块执行完再执行finally语句块。
注:
- 即使try和catch语句块中有return语句,finally语句块也会执行,在执行完finally语句块后跳回return语句返回。
- finally语句块只有一种情况不会执行,在finally语句之前程序遇到了System.exit(0)退出。
技巧:选中需要处理代码,IDEA中使用Ctrl+Alt+t快捷键自动增加try—catch语句块。
public class Test {public static void main(String[] args) {try {FileReader reader = new FileReader("d:/a.txt");//创建一个a.txt文件的索引char c = (char)reader.read();//从文件中读一个字符,注意返回的是整数,因此要强制转型char c1 = (char)reader.read();System.out.println("" + c + c1);//可能存在的异常:文件不存在或文件为空} catch (FileNotFoundException e){//文件不存在e.printStackTrace();} catch (IOException e) {//文件读写错误e.printStackTrace();} finally {reader.close();//关闭文件,但有问题,这里reader变量是try语句块中的局部变量,//在finally语句块里无法找到,因此需把reader变量定义在try和catch语句块之外//因为这里是关闭文件,又可能出现异常,需要处理}}
public class Test {public static void main(String[] args) {FileReader reader = null;//先创建一个空的文件索引try {reader = new FileReader("d:/a.txt");//让该文件索引指向一个文件char c = (char) reader.read();//从文件中读一个字符,注意返回的是整数,因此要强制转型char c1 = (char) reader.read();System.out.println("" + c + c1);//可能存在的异常:文件不存在或文件为空} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {//此部分一定会执行//关闭文件,但有问题,这里reader变量是try语句块中的局部变量,//在finally语句块里无法找到,因此需把reader变量定义在try和catch语句块之外//因为这里是关闭文件,又可能出现异常,需要处理try {if (reader != null) {reader.close();}} catch (IOException e) {e.printStackTrace();}}}}
2.异常的处理方式之二:声明异常(throws语句)
在CheckedException异常发生时,可以把异常throws出去。
在方法中使用try—catch—finally语句时,由这个方法处理这个异常。但有些时候当前方法并不需要处理所发生的异常,而是向上传递给调用它的方法处理。
如果一个方法可能产生某种异常,但是并不能确定如何处理这种异常,则应根据异常规范在方法的首部声明该方法可能抛出的异常。如果一个方法抛出多个已检查异常,则必须在方法首部列出所有的异常,之间以逗号隔开。
public class Test {//往调用main方法的虚拟机抛出异常,给虚拟机处理public static void main(String[] args) /*throws Exception*/{try{readFile("d:/a.txt");}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 c1 = (char) reader.read();System.out.println("" + c + c1);} finally {try {if (reader != null) {reader.close();}} catch (IOException e) {e.printStackTrace();}}}}
使用抛出异常时,并不是对异常不处理,而是交给更上层的调用者处理,常见的是一层一层往外抛,最后交给顶层的框架来处理。
3.异常的处理方式之三:自动关闭
Java中,JVM的垃圾回收机制可以对内部资源实现自动回收,给开发者带来了极大的便利。但是JVM对外部的资源(调用了底层操作系统打开的资源)的引用却无法自动回收,例如数据库连接、网络链接以及输入输出IO流等。这些资源就需要我们手动的去关闭,不然会导致外部资源泄漏,比如连接池溢出、文件被异常占用等。
JDK7之后,实现了try—catch—resource,只使用try—catch就可以自动关闭我们打开的外部资源。但这只是一种语法糖,在编译时仍然会转化为try—catch—finally形式。
public class Test {public static void main(String[] args) {//在try语句块的括号里说明打开的资源,编译器会帮我们加finally语句块关闭这些资源//本质上和try——catch——finally没什么区别,只是编译器帮我们加上了关闭资源的代码try(FileReader reader = new FileReader("d:/a.txt");){char c = (char) reader.read();char c1 = (char) reader.read();System.out.println("" + c + c1);}catch (Exception e){e.printStackTrace();}}}
4.自定义异常
- 在程序中可能会遇到JDK提供的标准异常类无法充分描述我们想要表达的问题,这种情况下可以创建自己的异常类,即自定义异常。
- 自定义异常只需从Exception类或者它的子类派生出一个类即可。
- 自定义异常如果继承Exception,则为受检查异常,必须进行处理;如果不想处理,可以继承RuntimeException类。
- 习惯上,自定义异常类应该包含两个构造器:一个是默认的构造器,一个是带有详细信息的构造器。
在开发项目过程中,其实不需要自己自定义异常,如果是开发框架,就需要自定义异常,如在Spring框架中定义了许多自定义异常,有着自己的一整套异常体系,对应不同的异常情况。
三、利用百度解决异常
在学习和开发过程中,我们会遇到很多的异常,当遇到异常的时候不要慌,耐心解决掉这些异常才能有所提高,独立解决掉50次异常之后,我们以后遇到的异常基本都能自己解决。
1.解决异常的步骤
细心查看异常信息,确定异常种类和出错代码的位置;
- 确定上下文中的关键词;
- 拷贝异常信息到百度,查看相关帖子,寻找解决思路;
- 前面无法搞定,寻找同事朋友的帮忙;
- 最后,还是无法搞定再请示领导。
注:遇到异常不要马上搬救兵,一定要自己尝试解决,如果花了一些时间解决不掉一定要及时请教别人。一、只会找别人帮忙,次数多了别人会不耐烦,只是把别人当苦力。二、失去了自我提升的机会,自己解决掉一个异常,以后就有能力解决掉这一类异常,解决一类异常能大大提高自己的能力。
2.百度搜索的方法
使用百度/goole的关键是:关键词的确认。
- 寻找问题本身的关键词(名词)
- 寻找问题上下文的关键词(名词)
- 尽量细致地使用这些关键词进行搜索
-
四、IDEA的调试功能
https://www.bilibili.com/video/BV1oy4y1H7R6?p=146
1.断点(breakpoint)
IDEA提供了非常方便的程序调试功能,进行调试的核心是设置断点。程序执行到断点时,暂停执行,这样我们可以详细查看此时程序的运行情况。
在行号后面单击即可增加断点
- 在断点上单击即可取消断点
2.进入调试视图




| 中文名 | 英文名 | 图标 | 作用 |
|---|---|---|---|
| 单步调试:遇到方法跳过 | step over | ![]() |
若当前执行的是一个方法,则会把这个方法当作整体一步执行完,不会进入方法的内部 |
| 单步调试:遇到自定义方法进入 | step into | ![]() |
若当前执行的是一个自定义方法,则会进入这个方法的内部。JDK内部方法不会进入。 |
| 强制进入方法内部 | force step into | ![]() |
任何方法都能进入 |
| 跳出方法 | step out | ![]() |
当单步执行到子方法内时,用step out方法就可以执行完子方法余下部分,并返回到上一层方法 |
| 执行到光标处 | run to cursor | ![]() |
一直执行,到光标处停止,用在循环内部时,点击一次就执行一个循环 |
| 删除当前帧 | drop frame | ![]() |
将返回到当前方法的调用处(如上图,程序会返回到main方法中)重新执行,并且所有上下文变量的值也回溯到那时候 |







