异常
概述
程序在运行过程中,由于意外情况导致程序发生异常事件,默认情况下发生的异
常会中断程序的运行。
在Java中,把常见的异常情况,都抽象成了对应的异常类型,那么每种异常类型
都代表了一种特定的异常情况。
当程序中出现一种异常情况时,也会创建并抛出一个异常类型对象,这个对象就
表示当前程序所出现的问题。
异常的种类
我们平时使用的异常类型,都是 Exception 类的子类型,它们把异常划分成了
两种:
- 编译时异常
- 继承自 Exception 类,也称为checked exception
- 编译器在编译期间,会主动检查这种异常,如果发现异常则必须显示处理,
否则程序就会发生错误,无法通过编译
- 运行时异常
- RuntimeException 类及其子类,也称为unchecked exception
- 编译器在编译期间,不会检查这种异常,也不要求我们去处理,但是在运行
期间,如果出现这种异常则自动抛出
部分常见的异常
空指针异常
当读取的文件不存在或访问空指针是,会抛出NullPointerException异常。
如下:
public class TestNullPointerException {
public static void main(String[] args) throws IOException {
// 1 声明流
DataInputStream dis = new DataInputStream(new FileInputStream("data1.txt"));//data1.txt文件不存在
// 2 先操作写指定类型 后进行读指定类型的数据
dis.read();
}
}
运行结果:
数组越界
当访问的数组索引超过其有效范围时,会抛出ArrayIndexOutOfBoundsException异常。如下:数组有效长度为4(有效索引为3),当i=4时,对应的数组下标为4,即数组的第五个元素,而第五个元素不存在,故出现异常。
int[] arr = {1,2,3,4};
for (int i = 0; i <= arr.length; i++) {
System.out.println(arr[i]);
}
除零异常
当被除数为零时,抛出ArithmeticException异常
类型转换异常
当试图将一个对象强制转换为另一个不兼容的类型时,可能会抛出ClassCastException异常。
测试代码:
package com.briup.day14;
import java.io.*;
/**
* @author 谭梦寻
* @version 1.1
*/
public class TestException {
public static void main(String[] args) {
// 类转换异常
Object classException = new Test01("类转换异常");
Student stu = (Student) classException;
stu.getName();
}
}
class Test01 {
private String name;
public Test01() {
}
public Test01(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Student {
private int id;
private String name;
public Student() {
}
public Student(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
运行结果:
解读:
先创建并实例化了一个Test01类,向上转型成Object类型,再向下转型成Student类型,在编译过程中,向上和向下转型都没有问题,因为Object是所有类的父类,所以编译器不会提示错误。但是,Test01和Student类没有关联,无法进行转换,故在运行中抛出异常。
异常抛出
自动抛出
Java代码中,出现了提前指定好的异常情况的时候,代码会自动创建异常对象,并且将该异常对象抛出。如:代码中执行 String str = null; str.toString(); 的时候,代码会自动创建并抛出 NullPointerException 类型的异常对象,来表示当前这种异常情况。
手动抛出
try-catch
try-catch 语句块,就是用来对指定代码,进行异常捕获处理,并且处理完成后,JVM不会停止运行,代码还可以正常的往下运行。
如下案例:
// 通过java程序 读取a.txt内容 输入流 字节或字符输入流
public class TestFileInputStream {
public static void main(String[] args) {
// 1 声明流
InputStream input = null;
// 2 创建流的子类对象
try {
input = new FileInputStream("D:/a.txt");//本行代码不一定执行成功
// 3 进行读操作 表示每次读取一个字节信息 如果到了流的末尾 返回-1
int read = 0;
// System.out.println(read);//123
// System.out.println(input.read());//34
while ((read = input.read())!=-1) {
System.out.println(read);
}
} catch (FileNotFoundException e) {//这里两个catch可以用他们的父类代替
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 4 释放资源(文件)
try {
if (input != null) {
input.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
案例解读:
程序执行IO操作时,会在编译期间抛出IOException异常或其子类异常,通过try-catch方式,对异常进行捕获,从而让代码通过编译阶段。
finally语句
finally 关键字可以和 try、catch 关键字一起使用,固定搭配为: try-catch-finally ,它可以保证指定finally中的代码一定会执行,无论是否发生异常 。
固定格式 :
try {
可能出现异常的代码
}catch(异常类型 引用名) {
异常捕获后操作代码
}finally {
离开try或catch块前,必须要执行的代码
}
throws
throws关键字用于在方法声明中指定该方法可能抛出的异常类型。
public class TestException {
//抛出IO异常
public static void main(String[] args) throws IOException {
// 1 声明流
DataInputStream dis = new DataInputStream(new FileInputStream("data.txt"));
// 2 先操作写指定类型 后进行读指定类型的数据
dis.read();
}
}
当使用IO控制文件时,常常存在编译时异常,程序员一般借助throws关键字告诉编译器,该方法中如果出现IOException异常则主动抛出,传递给上一级,故能进行正常编译。