异常类
异常概念
异常指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。
在Java中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。
Java处理异常的方式是中断处理。
异常体系

异常分类
Throwable共有两个子类:
Error:严重错误,无法处理。如内存溢出,系统崩溃。
Exception:异常,可进行处理分为两种
运行时异常:都是
RuntimeException
类及其子类异常,如NullPointerException
(空指针异常)、IndexOutOfBoundsException
(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch
语句捕获它,也没有用throws
子句声明抛出它,也会编译通过。非运行时异常(编译异常):是
RuntimeException
以外的异常,类型上都属于Exception
类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如日期格式化异常,IOException
、SQLException
等以及用户自定义的Exception
异常,一般情况下不自定义检查异常。
打印异常

异常过程解析
package com.company;
public class MyException1 {
public static void main(String[] args) {
int[] a = {0, 1, 2};
int doing = ArrayTools.doing(a, 3);
System.out.println(doing);
}
}
class ArrayTools {
public static int doing(int[] arr, int i) {
return arr[i];
}}
异常处理
try…catch…finally
try:该代码块中编写可能产生异常的代码。
catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理。
finally:有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。
示例代码:
public class MyException2 {
public static void main(String[] args) {
try{
int a=1/0;
}catch (ArithmeticException e){
System.out.println(e.toString());
}finally {
System.out.println("bye-bye");
}
}
}
输出:
java.lang.ArithmeticException: by zero
bye-bye
如何获取异常信息:
Throwable类中定义了一些查看方法:
public String getMessage()
:获取异常的描述信息,原因(提示给用户的时候,就提示错误原因。
public String toString()
:获取异常的类型和异常描述信息(不用)。public void printStackTrace()
:打印异常的跟踪栈信息并输出到控制台。
注:当只有在try或者catch中调用退出JVM的相关方法,此时finally才不会执行,否则finally永远会执行。
throw
示例代码:
public class MyException2 {
public static void main(String[] args) {
int a = -10;
if (a < 0) {
throw new ArithmeticException("a不能小于0");
} else {
System.out.println(a);
}
}
}
输出:
Exception in thread "main" java.lang.ArithmeticException: a不能小于0
at com.company.MyException2.main(MyException2.java:9)
如果a<0则抛出异常,否则打印a
throws
声明异常:将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理(稍后讲解该方式),那么必须通过throws进行声明,让调用者去处理。
关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).
声明异常格式:
修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ }声明异常的代码演示:
public class MyException2 {
public static void main(String[] args) {
String s = "file1.txt";
try {
demo1(s);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void demo1(String a) throws IOException {
if (!"file.txt".equals(a)) {
throw new IOException("文件不存在");
} else {
System.out.println(a);
}
}
}
输出:
java.io.IOException: 文件不存在
at com.company.MyException2.demo1(MyException2.java:17)
at com.company.MyException2.main(MyException2.java:9)
注:
运行时异常被抛出可以不处理。即不捕获也不声明抛出。
如果finally有return语句,永远返回finally中的结果,避免该情况.
如果父类抛出了多个异常,子类重写父类方法时,抛出和父类相同的异常或者是父类异常的子类或者不抛出异常。
父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常。此时子类产生该异常,只能捕获处理,不能声明抛出
多个异常使用捕获又该如何处理呢?
一般我们是使用一次捕获多次处理方式,格式如下:
try{
编写可能会出现异常的代码
}catch(异常类型A e){ 当try中出现A类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}catch(异常类型B e){ 当try中出现B类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}注意:这种异常处理方式,要求多个catch中的异常不能相同,并且若catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。
多个异常分别处理。
多个异常一次捕获,多次处理。
多个异常一次捕获一次处理。
自定义异常类
实际开发中也会出现很多异常,这些异常很可能在JDK中没有定义过,这时需要我们自己去定义。
异常类如何定义:
自定义编译期异常:自定义类继承于
java.lang.Exception
。自定义运行时异常:自定义类继承于
java.lang.RuntimeException
。
Student:
public class Student {
private String sex;
public void setSex(String sex) throws Exception {
if ("男".equals(sex) || "女".equals(sex)) {
this.sex = sex;
} else {
throw new GendorException("性别必须是男或者女");
}
}
}
Test:
public class Test {
public static void main(String[] args) {
Student p = new Student();
try {
p.setSex("不知道");
} catch (Exception e) {
System.out.println("设置性别出错了");
e.printStackTrace();//输出异常信息
}
}
}
GendorException:
public class GendorException extends Exception {
public GendorException(String msg) {
super(msg);
}
}
输出:
设置性别出错了
com.company.GendorException: 性别必须是男或者女
at com.company.Student.setSex(Student.java:17)
at com.company.Test.main(Test.java:9)





