异常处理/Debug追踪
异常处理
1.异常概述
- 任何一种程序设计语言设计的程序在运行时都有可能出现错误, 例如除数为0, 数组下标越界, 要读些的文件不存在等等。
- 捕获错误最理想的是在编译期间, 但有的错误只有在运行时才会发生。
- 对于这些错误, 一般有两种解决办法:
遇到错误就终止程序的运行。
由程序员在编写程序时, 就考虑到错误的检测、错误消息的提示, 以及错误的处理。
java异常:
- 在java语言中, 将程序执行中, 将程序执行中发生的不正常情况称为"异常"。
- java中的异常用于处理非预期的情况, 如文件不存在, 用户输入非法数据, 非法的参数, 网络通信时连接中断, 或者JVM内存溢出。
这些异常有的是因为用户错误引起,有的是程序错误引起的,还有其它一些是因为物理错误引起的。-
要理解Java异常处理是如何工作的,你需要掌握以下三种类型的异常:
- 检查性异常(编译期):最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
- 运行时异常(运行期): 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
- 错误(Error): 错误是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译期检查不到的。
java异常层次:
所有的异常类是从 java.lang.Exception 类继承的子类。
Exception 类是 Throwable 类的子类。除了Exception类外,Throwable还有一个子类Error 。
Java 程序通常不捕获错误。错误一般发生在严重故障时,它们在Java程序处理的范畴之外。
Error 用来指示运行时环境发生的错误。
例如,JVM 内存溢出。一般地,程序不会从错误中恢复。
异常类有两个主要的子类:IOException 类和 RuntimeException 类。
常见异常:
-
RuntimeExctption:
错误的类型转换
数组下标越界
空指针异常 -
IOException(读写文件异常)
从一个不存在的文件中读取数据
越过文件尾继续读取 EOFException
连接一个不存在的URL
2.Java内置异常类
下面的表中列出了 Java 定义在 java.lang 包中的检查性异常类。
异常 | 描述 |
---|---|
ClassNotFoundException | 应用程序试图加载类时,找不到相应的类,抛出该异常。 |
CloneNotSupportedException | 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。 |
IllegalAccessException | 拒绝访问一个类的时候,抛出该异常。 |
InstantiationException | 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。 |
InterruptedException | 一个线程被另一个线程中断,抛出该异常。 |
NoSuchFieldException | 请求的变量不存在 |
NoSuchMethodException | 请求的方法不存在 |
下面的表中列出了 Java 定义在 java.lang 包中的非检查性异常类。
异常 | 描述 |
---|---|
ArithmeticException | 当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例。 |
ArrayIndexOutOfBoundsException | 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。 |
ArrayStoreException | 试图将错误类型的对象存储到一个对象数组时抛出的异常。 |
ClassCastException | 当试图将对象强制转换为不是实例的子类时,抛出该异常。 |
IllegalArgumentException | 抛出的异常表明向方法传递了一个不合法或不正确的参数。 |
IllegalMonitorStateException | 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。 |
IllegalStateException | 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。 |
IllegalThreadStateException | 线程没有处于请求操作所要求的适当状态时抛出的异常。 |
IndexOutOfBoundsException | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 |
NegativeArraySizeException | 如果应用程序试图创建大小为负的数组,则抛出该异常。 |
NullPointerException | 当应用程序试图在需要对象的地方使用 null 时,抛出该异常 |
NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。 |
SecurityException | 由安全管理器抛出的异常,指示存在安全侵犯。 |
StringIndexOutOfBoundsException | 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。 |
UnsupportedOperationException | 当不支持请求的操作时,抛出该异常。 |
3.Throwable类常用方法
异常方法
下面的列表是 Throwable 类的主要方法:
- public String getMessage() : 返回关于发生的异常的详细信息。这个消息在 Throwable 类的构造函数中初始化了。
- public Throwable getCause() : 返回一个Throwable 对象代表异常原因。
- public String toString() : 使用getMessage()的结果返回类的串级名字。
- public void printStackTrace() : 打印toString()结果和栈层次到System.err,即错误输出流。
- public StackTraceElement [] getStackTrace() : 返回一个包含堆栈层次的数组。下标为0的元素代表栈顶,最后一个元素代表方法调用堆栈的栈底。
- public Throwable fillInStackTrace() : 用当前的调用栈层次填充Throwable对象栈层次,添加到栈层次任何先前信息中。
- 常用构造:
Exception(String message)
Exception(String message, Throwable cause) - 常用方法
String getMessage() 获得具体的异常信息
void printStackTrace() 将异常具体的信息打印输出到控制台
4.异常处理机制
- 在编写程序时, 经常要在可能出现错误的地方加上检测的代码, 如进行除法运算时, 要检测分母为0, 数据为空, 输入的不是数据而是字符等。过多的分支会导致程序的代码加长, 可读性差。因此采用异常机制。
- java异常处理: java采用异常处理机制, 将异常处理的程序代码集中在一起, 与正常的程序代码分开, 使得程序简洁, 并易于维护。
java的异常处理机制:
- java提供的是异常处理的抓抛模型。
- java程序的执行过程中如果出现异常, 会自动生成一个异常类对象, 该对象将被提交给java运行的系统, 这个过程称为抛出(throw)异常。
- 如果一个方法内抛出异常, 该异常会被抛出到调用方法中。如果异常没有在调用方法中处理, 它继续被抛给这个调用方法的调用者。这个过程将一直继续直到异常被处理。这一过程称为捕获(catch)异常。
- 如果一个异常回到main()方法, 并且main()也不处理, 则程序运行终止。
- 程序员通常只能处理Exception, 而对Error无能为力。
public static void main(String[] args) {
int i = 0;
try {//用try{}来括入一段有可能出现异常的代码段
System.out.println(3/i);//由于异常,程序中断,可以通过程序异常处理机制防止程序的中断
}catch(Exception e) {//Exception是所有异常的父类,当不知道捕获的是什么类型的异常时,可以直接使用Exception
//catch处理立场后,则程序可以继续运行
// e.printStackTrace();//打印异常信息
// System.out.println(e.getMessage());//输出异常
}
System.out.println("异常被处理后程序继续运行");
}
1.使用try…catch…finally处理异常
异常处理是通过try-catch-finally语句实现的。
在 try 块中出现了异常的语句的后续不会被执行。
使用 try-catch 处理异常后的逻辑语句会继续执行。
try{
......//可能产生异常的代码
}catch(ExceptionName1 | ExceptionName2 e1){//可以用"或"运算符来捕获多个异常
......//当产生ExceptionName1型异常时的处理措施
}catch(ExceptionName2 e2){
......//当产生ExceptionName2型异常时的处理措施
}catch(Exception){//防止捕获的异常不在上述范围内,最后捕获Exception类,逻辑上层次越高的异常应该放后面捕获
......//当捕获Exception异常时的处理措施
}finally{
......//无条件执行的语句
}
......;//后续的逻辑语句
例1:
public static void main(String[] args) {
int i = 0;
String[] s = new String[] {"a","b"};
A a = null;
try {
System.out.println(s[2]);//异常类:java.lang.ArrayIndexOutOfBoundsException
System.out.println(a.i);//异常类:java.lang.NullPointerException
System.out.println(3/i);//异常类:java.lang.ArithmeticException
}
catch(ArrayIndexOutOfBoundsException e1){
System.out.println("异常1:"+e1.getMessage());
}
catch(NullPointerException e2){
System.out.println("异常2:"+e2.getMessage());
}
catch(ArithmeticException e3){
System.out.println("异常3:"+e3.getMessage());
}
}
//多个catch{},捕获程序可能出现的异常,捕获第一个异常后,后面的catch{}不会再执行
class A{
int i;
}
如果明确知道产生的异常类型, 可以用该异常类作为catch的参数; 也可以用其父类Exception作为catch()的参数
例2:
public static void main(String[] args) {
int i = 0;
try {//用try{}来括入一段有可能出现异常的代码段
System.out.println("异常出现前的语句可以执行");
System.out.println(3/i);//由于异常,程序中断,可以通过程序异常处理机制防止程序的中断
System.out.println("异常出现后的语句不会被执行");
}catch(Exception e) {//Exception是所有异常的父类,当不知道捕获的是什么类型的异常时,可以直接使用Exception
//catch处理立场后,则程序可以继续运行
// e.printStackTrace();//打印异常信息
// System.out.println(e.getMessage());//输出异常
System.out.println("当捕获异常后采取的方法");
}finally {
System.out.println("finally{}里的语句无条件执行");
//System.out.println(3/i);//前提是没有异常
}
System.out.println("异常被处理后程序继续运行");
}
}
捕获异常的有关信息:
与其他对象一样, 可以访问一个异常对象的成员变量或者调用它的方法。
- getMessage()方法, 用来得到有关异常事件的信息
- pringStackTrace()方法, 用来跟踪异常事件发生时执行堆栈的内容
finally{}:
- 捕获异常的租后一步是通过finally语句为异常处理提供一个统一的出口, 使得在控制流转到到程序的其他部分以前, 能够对程序的状态作统一的管理。不论在try、catch代码块中是否发生了异常事件, finally块中的语句都会被执行。
- finally语句是可选的。
2.声明抛出异常
throws语句:
使用throw代码抛出异常, 再调用方法去捕获处理
注意: throws/throw区别,
throws用在函数上,声明该函数的功能可能会出现问题。throw用在方法体中将异常抛出,是问题暴露出来,用于处理, throw后面必须抛出异常
在方法体里面,遇见throw,程序就结束了。
/**
* throws抛出异常
*/
class B{
int i;
public void test() throws Exception{
B b = null;
System.out.println(b.i);
}
}
public static void main(String[] args) {
//可以在main方法继续抛出, 但会直接抛出给虚拟机, 在程序中就无法处理了
/**
* 创建try-catch捕获处理throws抛出的异常
*/
B b = new B();
try {
b.test();
} catch (Exception e) {
e.printStackTrace();
}
重写方法声明抛出异常的原则:
- (父类)被重写的方法抛出异常, 则(子类)重写的方法也要抛出异常
- (子类)重写方法不能抛出比(父类)被重写方法范围更大的异常类型
如: Exception>NullPointerException
3.人工抛出异常
java异常类对象除在程序执行过程中出现ichang时由系统自动生成并抛出, 也可根据需要人工创建并抛出
public class Test1 {
/**
* 人工抛出异常
*/
int age;
public void test(int age) throws Exception {//相应的,方法也要抛出异常
if (age >= 0 && age <= 150) {
this.age = age;
}else {
throw new Exception("年龄要在0到150之间");//new并抛出一个异常
}
}
public static void main(String[] args) {
Test1 t = new Test1();
try{
t.test(-100);
}catch(Exception e) {
//System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
5.创建用户自定义异常类
创建自定义异常类, 继承Exception类, 捕获和抛出自定义的异常类
class MyException extends Exception{
public MyException(String msg) {
super(msg);
System.out.println("自定义的异常信息");
}
}
public void test(int age) throws Exception {//相应的,方法也要抛出异常
if (age >= 0 && age <= 150) {
this.age = age;
}else {
// throw new Exception("年龄要在0到150之间");//new并抛出一个异常
throw new MyException("年龄要在0到150之间");//new并抛出一个自定义的异常
}
}
Debug追踪
使用IDEA断点调试功能, 查看程序的运行过程
-
Debug调试程序
可以让程序逐行 运行, 查看代码执行的过程, 调试程序出现的Bug -
使用方式:
在行号的左边,鼠标单击添加断点
右键菜单,Debug执行程序
程序会在第一个断点前停留 -
执行程序:
F8: 逐行执行程序
F7: 进入到方法中
SHIFT+F8: 跳出方法
F9: 跳到下一个断点, 没有下一个断点就结束程序
CTRL+F2: 退出Debug程序, 停止程序
Console: 切换到控制台