Java在执行过程中所发生的异常事件可以分为两类:Error和Exception.
Error:是指Java虚拟机无法解决的严重问题。如JVM内部错误,资源耗尽的严重情况。像栈溢出StackOverflowError和堆溢出OOM.一般出现这样的问题,不在编写针对性的代码进行处理。
Exception:是因为变成错误或偶然的外在因素导致的一般性的问题,可以使用针对性的代码进行处理。如空指针的访问,读取不存在的文件,网络连接中断,数组角标越界等问题。出现Exception错误,一般也有两种解决方案,一种是遇到错误终止程序运行,一种是在编写程序时,考略到错误检测,错误提示,以及错误处理。就是我们今天要说到的异常处理。而这也错误也可以被分为两种,分别是java的编译和运行期间出现的异常,编译时异常和运行时异常。
一、常见的运行异常:
// NullPointerException 空指针错误
public void test1() {
int[] arr = null;
System.out.println(arr[3]);
}
// ArrayIndexOutOfBoundsException 数组下标越界
public void test2() {
int[] arr = new int[3];
System.out.println(arr[3]);
}
// ClassCastException 类型转换错误
public void method4() {
Object object = new Date();
// 向下转型时,有data类型转为了string类型
String string = (String) object;
}
// InputMismatchException 若输入字符串则报异常
public void method6() {
Scanner scanner = new Scanner(System.in);
int score = scanner.nextInt();
System.out.println(score);
}
// ArithmeticException 除数为0
public void method7() {
int a = 10;
// 除数不能为0
int b = a / 0;
System.out.println(b);
}
常见的编译异常:一般编译异常很容易被发现,在书写代码的过程中就发现
public void test7() {
File file = new File("hello,test");
FileInputStream fil = new FileInputStream(file);// 实例化的时候会报错误
int data = fil.read();
while (data != -1) {
System.out.println((char) data);
data = fil.read();
}
fil.close();
}
二、异常的处理
一般有三种处理的方式,使用try-catch-finally、使用throw、使用自定义的异常类
1.try-catch-finally处理:
public void test2() {
// try中为可能会出现异常的代码,
try {
File file = new File("hello,txt");
FileInputStream fileInputStream = new FileInputStream(file);
int data = fileInputStream.read();
while (data != -1) {
System.out.println((char) data);
}
// 可能出现的异常列举,在catch中进行处理,满足其中一处的catch就可以跳出try-catch结构
} catch (FileNotFoundException e) {
e.printStackTrace();
// 或者使用,也可以提示信息
System.out.println(e.getMessage());
} catch (IOException e) {
e.printStackTrace();
}finally{// finally中是一定会被执行的结构,无论catch中是否有返回值,finally一定会被执行。
fileInputStream.close();
}
}
2.throw手动抛出一个异常类对象
public class ExceptionTest2 {
public static void main(String[] args) {
// 使用throws手动抛异常,最终也要有try-catch进行处理
try {
method2();
} catch (IOException e) {
e.printStackTrace();
}
method3();// 因为method3经过处理,再此处调用就不会异常
method4();// method4没有处理,还会报错,此时就要抛出去或者直接try-catch处理
}
public static void method4() throws IOException {
// 如果没有进过method3处理,还可以向上抛
method2();
}
public static void method3() {
// 在method3中使用try-catch进行处理
try {
method2();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void method2() throws IOException {
// 调用method1方法,抛给method2
method1();
}
// 关于文件流异常使用throws
public static void method1() throws FileNotFoundException, IOException {
FileInputStream fileInputStream = null;
File file = new File("hello,txt");
fileInputStream = new FileInputStream(file);
int data = fileInputStream.read();
while (data != -1) {
System.out.println((char) data);
}
fileInputStream.close();
}
}
> 这里要注意:
> 1.子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型。
> 2.如果父类的方法中没有抛出异常,则子类不能抛出异常
public static void main(String[] args) {
OverrideTest test = new OverrideTest();
test.display(new SubClass());
}
public void display(SuperClass s) {
try {
s.method();
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 父类
class SuperClass {
public void method() throws IOException {
}
}
// 子类继承父类
class SubClass extends SuperClass {
// 子类重写的方法抛出异常的类型不能大于父类抛出的异常类型
public void method() throws FileNotFoundException {
}
3.自定义异常类
public class EcDef extends Exception {
// 定义全局变量
static final long serialVersionUID = -703468725553783L;
// 空参构造器
public EcDef() {
}
// 带参构造器
public EcDef(String msg) {
super(msg);
}
}
public class EcmDef {
public static void main(String[] args) {
// 进行try-catch-finally处理
try {
int i = Integer.parseInt(args[0]);
int j = Integer.parseInt(args[1]);
int result = ecm(i, j);
System.out.println(result);
} catch (NumberFormatException e) {
System.out.println("数据类型不一致");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("缺少命令行参数");
} catch (ArithmeticException e) {
System.out.println("除数为0");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
// throw new 自定义异常类,通过throws抛出
public static int ecm(int i, int j) throws EcDef {
if (i < 0 || j < 0) {
throw new EcDef("分子或分母为负数了");
}
return i / j;
}
}
关于throw和throws区别:
throws是异常处理的一种方式,在方法处进行声明
throw是抛出异常对象,生成异常对象的过程,声明在方法体内。