- Java提供的异常机制使程序的变得更加健壮【健壮性】,程序不会那么容易崩溃
异常详解
1.异常的基本概念
Java语言中,将程序执行过程中发生的不正常的情况称为异常
注:程序中的语法错误和逻辑错误不是异常
2.一个小case快速了解异常
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = 0;
int n = 0;
m = sc.nextInt();
n = sc.nextInt();
int ret = m / n;//如果n为0程序会怎么样?
System.out.println(ret);
}
}
如果n=0的话,可以发现程序会崩溃,崩溃的信息如下:/ by zero【产生了数学运算异常】
3.异常事件的分类
- Error(错误):Java虚拟机无法解决的严重问题。如:StackOverflowError(栈溢出)、OutOfMemory等情况,Error是严重错误,会导致程序崩溃
- Exception:Java在编译或运行或者运行过程中出现的错误
1)运行时异常:程序运行时发生的异常
2)编译时异常:在代码编写的阶段,编译器检查出的异常
4.异常体系图【重点】
1)异常分为两大类:运行时异常和编译时异常
2)运行时异常:编译器检查不出来的异常,对于运行时异常,可以不做处理,因为这类异常很普遍,若全处理后可能对程序的可读性和运行效率产生影响
3)编译时异常:是要求程序员必须进行处理的异常
5.常见的运行时异常
1)ArithmeticException —— 数学运算异常
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int m = 0;
int n = 0;
m = sc.nextInt();
n = sc.nextInt();
int ret = m / n;//如果n为0程序会怎么样?
System.out.println(ret);
}
}
异常结果图:
2)NumberFormatException —— 数字格式不正确的异常
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
//思考:若是输入汉字的字符怎么办?
//会出现数字格式不正确的异常
String num = sc.next();
int ret = Integer.parseInt(num);//将字符串转化为整型
System.out.println(ret);
}
}
异常结果图:
3)NullPointerException —— 空指针异常
public class Test {
public static void main(String[] args) {
String str1 = null;//空指针
String str2 = "abcdef";
System.out.println(str1.equals(str2));
}
}
异常结果图:
4)ArrayIndexOutOfBoundsException —— 数组下标越界异常
public class Test {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
for (int i = 0; i <= arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
异常结果图:
5)ClassCastException —— 类型转化异常
public class Test {
public static void main(String[] args) {
Father son = new Son();//向上转型
Grandson grandson = new Grandson();
grandson = (Grandson) son;
//正确的向下转型
Son son1 = (Son) son;//向下转型
}
}
异常结果图:
6.编译时异常
1)概念:编译异常是指在编译期间必须要处理的异常,否则代码不能通过编译
2)常见的编译异常
1> SQLException //操作数据库时,查询表可能发生的异常
2> IOException //操作文件时的异常
3> FileNotFoundException //不存在的文件异常
4> ClassNotFoundException //加载的类不存在的异常
5> EOFException //操作文件到文件末尾,发生异常
6> ILLegalArgumentException //参数异常
7.异常处理
1)什么是异常处理?
当异常发生时对程序中异常进行的处理
2)异常处理的方式
1> try - catch - finally
—— 使用try - catch - finally捕获代码中会发生的异常,系统自行处理
2> throws
—— 将要发生的异常抛出,交给调用者去处理,最顶级的处理者就是JVM
3)try - catch - finally处理机制详解
4)throws处理机制详解
1> 若一个方法中可能发生异常,但是不确定如何处理这种异常,则可把这种方法显示的声明抛出异常,表妹该方法不对异常进行处理,而有方法的调用者进行处理
2> 在方法声明中用throws遇见可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是该异常的父类
没有显示的处理异常的时候,默认的throws
public class Test {
public static void main(String[] args) {
hello();
}
private static void hello() {
f1();
}
private static void f1() {
int m = 10;
int n = 0;
System.out.println(m / n);
}
}
//如何解释以上代码的异常?
//JVM处理了该异常
//1.f1方法中出现的异常,发现f1方法自己没有try -catch - finally,则抛出,方法后面默认有一个throws
//2.f1方法throws后到了hello方法,hello方法也没有try -catch - finally,又抛出给main
//3.main方法中有没有try -catch - finally,则抛出给JVM机处理
//4.JVM机处理的方式很简单:抛出异常信息,然后程序崩溃
8.try - catch - finally 和 throws的代码解释
1)一个小case快速了解try - catch - finally
public class Test {
public static void main(String[] args) {
//对有异常的代码进行异常处理
try {
//1.若是try中没有发生异常,那么catch块中的代码不执行
int m = 6;
int n = 0;
int ret = m / n;
} catch (Exception e) {
//2.这里程序员可以设置自己想输出的内容
System.out.println(e.getMessage());//输出异常信息
//3.捕获到异常后,会继续执行后续的代码,程序不会被强制退出
}
System.out.println("happy~");
}
}
2)try - catch - finally 细节讨论
1> 如果异常发生,则异常后面的代码不会执行,直接进行到catch中执行catch的代码
2> 如果异常没有发生,那么不会进入到catch的代码中
3> 如果希望异常有没有发生都执行某段代码,那么使用finally无疑是你最好的choice
4> 若是有多个异常需要捕获,要求父类异常在后,子类异常在前【注:若是发生异常,只会进入一个catch块中进行捕获】
5> 可以进行try - finally的使用,这种做法没有捕获异常,程序会直接崩溃/退出【为了使用finally中的代码】
public class Test {
public static void main(String[] args) {
//对有异常的代码进行异常处理
try {
String data = "过去";
int num = Integer.parseInt(data);
//1.捕获到异常后,异常的后面代码不会执行
//2.若是没有捕获到异常,则不会进入catch的代码块中
System.out.println(data);
} catch (Exception e) {
System.out.println(e.getMessage());//输出异常信息
} finally {
//3.不管有没有异常必须执行finally中的代码
System.out.println("执行finally中的代码~");
}
//4.异常被捕获则执行后续的代码
System.out.println("happy~");
}
}
public class Test {
public static void main(String[] args) {
//进行多个异常的捕获:父类异常在后,子类异常在前
try {
String res = null;
String data = "过去";
System.out.println(res.equals(data));
int num = Integer.parseInt(data);
System.out.println(data);
} catch (NullPointerException e) {
System.out.println(e.getMessage());//输出异常信息
} catch (Exception e) {
System.out.println(e.getMessage());//输出异常信息
} finally {
System.out.println("执行finally中的代码~");
}
System.out.println("happy~");
}
}
3)throws细节讨论
1> 程序中编译异常,程序必须使用try - catch或throws处理
2> 运行时异常,若程序中没有处理,则默认是以throws的方式进行处理的
3> 子类重写父类方法的时候,对抛出异常的规定:子类重写的方法,所抛出的异常类型要和父类抛出的异常一致或为父类抛出异常类型的子类型
4> 在throws过程中,若是有方法使用了try - catch进行了处理,那么就不必使用throws抛出了
public class Test {
public static void main(String[] args) {
}
}
class Father {
public void say() throws RuntimeException {
int m = 5;
int n = 0;
System.out.println(m / n);
}
}
class Son extends Father {
@Override
//该地方的异常类型必须和父类一致或为父类异常类型的子类的
public void say() throws ArithmeticException {
super.say();
}
}
9.思考下面会输出什么?
代码1:
public class Test {
public static void main(String[] args) {
System.out.println(method());
}
private static int method() {
int i = 1;
try {
i++;
String[] names = new String[3];
if (names[1].equals("jack")) {
System.out.println(names[1]);
} else {
names[3] = "maria";
}
return 1;
} catch (ArrayIndexOutOfBoundsException e) {
return 2;
} catch (NullPointerException e) {
return ++i;
} finally {
return ++i;
}
}
}
代码2:
public class Test {
public static void main(String[] args) {
System.out.println(method());
}
private static int method() {
int i = 1;
try {
i++;
String[] names = new String[3];
if (names[1].equals("jack")) {
System.out.println(names[1]);
} else {
names[3] = "maria";
}
return 1;
} catch (ArrayIndexOutOfBoundsException e) {
return 2;
} catch (NullPointerException e) {
return ++i;
} finally {
++i;
System.out.println(i);
}
}
}
10.如果用户不是输入一个整数,那么一直提示他输入一个整数为止【重点】
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String data = "";
int num = 0;
while (true) {
System.out.println("请输入一个整数:");
data = sc.next();
try {
num = Integer.parseInt(data);
break;
} catch (Exception e) {
System.out.print("");
}
}
System.out.println("你输入的值是:" + num);
}
}
11.自定义异常
1)概念
当程序中出现了某些错误,但该错误信息并没有在Throwable的子类中描述处理,这时,我们可以自己设计异常类来描述该异常信息
2)自定义异常类的步骤
1> 定义类:自定义异常类名继承Exception或RuntimeException
2> 如果继承Exception,属于编译异常;继承RuntimeException,属于运行异常【常】
3)一个小case快速了解自定义异常
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int age = 0;
age = scanner.nextInt();
if (age < 0 || age > 120) {
throw new AgeException("年龄错误");
}
}
}
//自定义异常类
class AgeException extends RuntimeException {
public AgeException(String message) {
super(message);
}
}
12.throw和throws的区别
关键字 | 意义 | 位置 | 后面紧跟 |
throws | 异常处理的一种方式 | 方法声明处 | 异常类型 |
throw | 手动生成异常对象的关键字 | 方法体中 | 异常对象 |