目录
一、异常概述与异常体系结构
异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常)
Java程序在执行过程中所发生的异常事件可分为两类:
- Error:Java虚拟机无法解决的严重问题。如:JVM系统内部错误、资源
耗尽等严重情况。比如:StackOverflowError和OOM。一般不编写针对性 的代码进行处理。 - Exception: 其它因编程错误或偶然的外在因素导致的一般性问题,可以使 用针对性的代码进行处理。例如:
- 空指针访问
- 试图读取不存在的文件
- 网络连接中断
- 数组角标越界
对于这些错误,一般有两种解决方法:一是遇到错误就终止程序的运行。另一种方法是由程序员在编写程序时,就考虑到错误的检测、错误消息的提示,以及错误的处理。
- 捕获错误最理想的是在编译期间,但有的错误只有在运行时才会发生。 比如:除数为0,数组下标越界等
- 分类:编译时异常和运行时异常
- 编译时异常: 是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一
般性异常。编译器要求Java程序必须捕获或声明所有编译时异常。对于这类异常,如果程序不处理,可能会带来意想不到的结果。
- 运行时异常:是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序
员应该积极避免其出现的异常。java.lang.RuntimeException类及它的子类都是运行时异常。对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
- 运行时异常:是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序
- 编译时异常: 是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一
Java 根据各个类库也定义了一些其他的异常,下面的表中列出了 Java 的非检查性异常。
异常 | 描述 |
---|---|
ArithmeticException | 当出现异常的运算条件时,抛出此异常。例如,一个整数"除以零"时,抛出此类的一个实例。 |
ArrayIndexOutOfBoundsException | 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。 |
ArrayStoreException | 试图将错误类型的对象存储到一个对象数组时抛出的异常。 |
ClassCastException | 当试图将对象强制转换为不是实例的子类时,抛出该异常。 |
IllegalArgumentException | 抛出的异常表明向方法传递了一个不合法或不正确的参数。 |
IllegalMonitorStateException | 抛出的异常表明某一线程已经试图等待对象的监视器,或者试图通知其他正在等待对象的监视器而本身没有指定监视器的线程。 |
IllegalStateException | 在非法或不适当的时间调用方法时产生的信号。换句话说,即 Java 环境或 Java 应用程序没有处于请求操作所要求的适当状态下。 |
IllegalThreadStateException | 线程没有处于请求操作所要求的适当状态时抛出的异常。 |
IndexOutOfBoundsException | 指示某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。 |
NegativeArraySizeException | 如果应用程序试图创建大小为负的数组,则抛出该异常。 |
NullPointerException | 当应用程序试图在需要对象的地方使用 null 时,抛出该异常 |
NumberFormatException | 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。 |
SecurityException | 由安全管理器抛出的异常,指示存在安全侵犯。 |
StringIndexOutOfBoundsException | 此异常由 String 方法抛出,指示索引或者为负,或者超出字符串的大小。 |
UnsupportedOperationException | 当不支持请求的操作时,抛出该异常。 |
下面的表中列出了 Java 定义在 java.lang 包中的检查性异常类。
异常 | 描述 |
---|---|
ClassNotFoundException | 应用程序试图加载类时,找不到相应的类,抛出该异常。 |
CloneNotSupportedException | 当调用 Object 类中的 clone 方法克隆对象,但该对象的类无法实现 Cloneable 接口时,抛出该异常。 |
IllegalAccessException | 拒绝访问一个类的时候,抛出该异常。 |
InstantiationException | 当试图使用 Class 类中的 newInstance 方法创建一个类的实例,而指定的类对象因为是一个接口或是一个抽象类而无法实例化时,抛出该异常。 |
InterruptedException | 一个线程被另一个线程中断,抛出该异常。 |
NoSuchFieldException | 请求的变量不存在 |
NoSuchMethodException | 请求的方法不存在 |
import java.io.File;
import java.io.FileInputStream;
import java.util.Date;
import java.util.Scanner;
/**
* @Description:异常测试
* @Author: dyq
* @Date: 2021/4/6
*/
public class ExceptionTest {
public static void main(String[] args) {
// ********************以下是编译时异常********************
File file = new File("hello.text");
FileInputStream fis = new FileInputStream(file);
int data = fis.read();
while(data!=-1){
System.out.println((char)data);
data= fis.read();
}
fis.close();
// *******************以下是运行时异常********************
//ArithmeticException 当出现异常的运算条件时,抛出此异常
// int a=10;
// int b =0;
// System.out.println(a/b);
//ArrayIndexOutOfBoundsException 数组下标越界异常
// int[] arr1 = new int[10];
// System.out.println(arr1[11]);
//ClassCastException 强转异常
// Object obj= new Date();
// String str = (String) obj;
//NumberFormatException 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
// String str ="123";
// str ="abc";
// int num = Integer.parseInt(str);
//InputMismatchException 输入异常
// Scanner scanner = new Scanner(System.in);
// int score = scanner.nextInt();
// System.out.println(score);
//NullPointerException 空指针异常
// int[] arr = null;
// System.out.println(arr[1]);
// String str = "哈哈哈哈哈";
// str = null;
// System.out.println(str.charAt(0));
}
}
二、异常处理机制一:try-catch-finally
举例:
/**
* @Description: 异常处理:抓抛模型
* 过程一:“抛”:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象。
*
* 过程二:“抓”:可以理解为异常的处理的方式:①:try-catch-finally ②:throws
*
* 二、try-catch -finally 的使用
*
* try{
* //可能出现异常的代码
* }catch(异常类型1 变量1){
* //处理异常的方式1
* }catch(异常类型2 变量2){
* //处理异常的方式2
* }catch(异常类型3 变量3){
* //处理异常的方式3
* }
*
* 。。。。。
* finally{
* //一定会执行的代码
* }
*
* 说明:
* 1.finally是可选的。
* 2.使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象
* 的类型,去catch中进行匹配
* 3.一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常处理,一旦处理
* 完成就跳出try-catch 结构(在没有写finally的情况下)
* 4.catch中的异常类型如果满足子类父类的关系,则谁声明在下无所谓
* catch中的异常类型如果满足父类关系,则要求子类一定声明在父类的上边,否则会报错。
* 5.常用的异常对象处理的方式: String getMessage() printstackTrace()
* 6.在try结构中声明的变量,再出了try结构以后,就不能再被调用
* 体会。使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。
* 相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。
* @Author: dyq
* @Date: 2021/4/6
*/
public class ExceptionTest1 {
public static void main(String[] args) {
String str = "123";
str ="abc";
try {
int num = Integer.parseInt(str);
System.out.println("hello----1");
}catch (NullPointerException e ){
System.out.println("出现空指针异常!");
}catch (NumberFormatException e ){
System.out.println("出现数字转换异常!");
}catch (Exception e ){ //Exception为上边两个异常的父类,放子类前会报错
System.out.println("出现异常!");
}finally {
System.out.println("hello------2");
}
}
String j = "我就做个显示!";
public String getMessage() {
return j;
}
}
不捕获异常时的情况
前面使用的异常都是RuntimeException类或是它的子类,这些类的异常的特点是:即使没有使用try和catch捕获,Java自己也能捕获,并且编译通过( 但运行时会发生异常使得程序运行终止 )。
如果抛出的异常是IOException等类型的非运行时异常,则必须捕获,否则编译错误。也就是说,我们必须处理编译时异常,将异常进行捕捉,转化为运行时异常
注意下面事项:
- catch 不能独立于 try 存在。
- 在 try/catch 后面添加 finally 块并非强制性要求的。
- try 代码后不能既没 catch 块也没 finally 块。
- try, catch, finally 块之间不能添加任何代码。
三、异常处理机制二:throws
public class ThrowsTest {
public static void main(String[] args) {
ThrowsTest t = new ThrowsTest();
try {
t.readFile();
} catch (IOException e) {
e.printStackTrace();
}
}
public void readFile() throws IOException {
FileInputStream in = new FileInputStream("hello.txt");
int b;
b = in.read();
while (b != -1) {
System.out.print((char) b);
b = in.read();
}
in.close();
}
}
1、开发中如何选择使用try-catch-finally 还是使用throws?
1、 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中有异常,必须使用try-catch-finally方式理。
2、执行的方法中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。|
2、 重写方法声明抛出异常的原则
四、 手动抛出异常
手写一个异常类MyException 继承RuntimeException
/**
* @Description: 如何显示异常:
* 1.继承于现有的异常结构:RuntimeException,Exception
* 2,提供全局常量:serialversionUID
* 3,提供构造器
* @Author: dyq
* @Date: 2021/4/18`在这里插入代码片`
*/
public class MyException extends RuntimeException {
static final long serialVersionUID = -7034897190745766939L;
public MyException() {
super();
} //构造器
public MyException(String message) {
super(message);
}
public MyException(String message, Throwable cause) {
super(message, cause);
}
}
编写测试代码,新建一个学生类:
public class Student {
public static void main(String[] args) {
try {
Student1 s = new Student1();
s.regist(-1001);
System.out.println(s);
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}
class Student1 {
private int id;
public void regist(int id) throws Exception {
if(id>0) {
this.id = id;
}else {
throw new MyException("不能输入负数!");
}
}
}
输出结果:
不能输入负数!
结果会显示的自定义的报错信息。
五、throw和throws区别:
throw表示抛出一个异常类的对象,生成异常对象的过程。声明在方法体内。
throws 属于异常处理的一种方式,声明在方法的声明处。