1、异常
1.1、问题引出
public static void main(String[] args) {
int num1 = 10;
int num2 = 0;
int res = num1 / num2;
System.out.println("程序继续运行....");
}
1.2、解决方案 — 异常捕获
对异常进行捕获,保证程序可以继续运行
package Exception01;
public class Exception01 {
public static void main(String[] args) {
int num1 = 10;
int num2 = 0; // 可以使用Scanner() 获取;
// 1. num1 / num2 => 10 / 0
// 2. 当执行到 num1 / num2 因为 num2 = 0, 程序就会出现(抛出)异常 ArithmeticException
// 3. 当抛出异常后, 程序就退出崩溃了, 下面的代码就不在执行
// 4. 这样的程序设计不好, 不应该出现了一个不算致命的问题, 就导致整个系统崩溃
// 5. java 设计者, 提供了一个叫 异常处理机制来解决该问题
// int res = num1 / num2;
// 如果程序员, 认为一段代码可能出现异常/问题, 可以使用 try-catch 异常处理机制来解决
// 从而保证程序的健壮性
// 将该代码块->选中->快捷键 ctrl + alt + t -> 选中 try-catch
// 6. 如果进行异常处理, 那么即使出现了异常, 程序可以继续执行
try {
int res = num1 / num2;
} catch (Exception e) {
// e.printStackTrace();
System.out.println("出现异常的原因=" + e.getMessage()); // 输出异常信息
}
System.out.println("程序继续运行....");
}
}
1.3、定义
1.4、异常体系图一览
1.4.1、异常体系图
1.4.2、异常体系图的小结
1.5、常见的运行时异常
1.5.1、常见的运行时异常分类
- NullPointerException 空指针异常
- ArithmeticException 数学运算异常
- ArrayIndexOutOfBoundsException 数组下标越界异常
- ClassCastException 类型转换异常
- NumberFormatException 数字格式不正确异常
1.5.2、NullPointerException 空指针异常
当应用程序试图在需要对象的地方使用 null 时,抛出该异常
package exception_;
public class NullPointerException {
public static void main(String[] args) {
String name = null;
System.out.println(name.length());
}
}
1.5.3、ArithmeticException 数学运算异常
当出现异常的运算条件时,抛出此异常,例如,一个整数“除以零”时,抛出此类的一个实例
package exception_;
public class ArithmeticException {
public static void main(String[] args) {
int n1 = 100;
int n2 = 0;
System.out.println(n1 / n2);
}
}
1.5.4、ArrayIndexOutOfBoundsException 数组下标越界异常
用非法索引访问数组时抛出的异常,如果索引为负或大于等于数组大小,则该索引为非法索引
package exception_;
public class ArrayIndexOutOfBoundsException_ {
public static void main(String[] args) {
int[] arrayList = {1, 2, 3, 4};
for (int i = 0; i <= arrayList.length; i++) {
System.out.println(arrayList[i]);
}
}
}
1.5.5、ClassCastException 类型转换异常
当试图将对象强制转换为不是实例的子类时,抛出该异常
package exception_;
public class ClassCastException_ {
public static void main(String[] args) {
A b = new B(); // 向上转型
B b2 = (B) b; // 向下转型
C c2 = (C) b; // 这里抛出 ClassCastException
}
}
class A {}
class B extends A {}
class C extends A {}
1.5.6、NumberFormatException 数字格式不正确异常
当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常 => 使用异常我们可以确保输入是满足条件数字
package exception_;
public class NumberFormatException_ {
public static void main(String[] args) {
String str = "hello world";
// 将 String 转成 int
int num = Integer.parseInt(str); // 抛出 NumberFormatException
System.out.println(num);
}
}
1.6、编译异常
1.6.1、定义
编译异常是指在编译期间,就必须处理的异常,否则代码不能通过编译
1.6.2、常见的编译异常
1.6.3、代码演示
package exception_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Exception02 {
public static void main(String[] args) {
try {
FileInputStream fis;
fis = new FileInputStream("d:\\aa.jpg");
int len;
while ((len = fis.read()) != -1) {
System.out.println(len);
}
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2、异常处理
2.1、定义
异常处理就是当异常发生时,对异常处理的方式
2.2、异常处理的方式
2.3、示意图
2.4、try-catch 异常处理
2.4.1、定义
2.4.2、代码演示
package exception_;
public class ArithmeticException {
public static void main(String[] args) {
try {
int n1 = 100;
int n2 = 0;
int res = n1 / n2;
} catch (Exception e) {
// e.printStackTrace();
System.out.println(e.getMessage());
}
}
}
2.4.3、注意事项
package exception_;
public class TryCatchDetail {
public static void main(String[] args) {
// ctrl + alt + t
// 1. 如果异常发生了, 则异常发生后面的代码不会执行, 直接进入到 catch 块
// 2. 如果异常没有发生, 则顺序执行 try 的代码块, 不会进入到 catch
// 3. 如果希望不管是否发生异常, 都执行某段代码(比如关闭连接, 释放资源等)则使用如下代码- finally
try {
String str = "hello world";
int a = Integer.parseInt(str);
System.out.println("数字: " + a);
} catch (NumberFormatException e) {
System.out.println("异常信息=" + e.getMessage());
} finally {
System.out.println("finally 代码块被执行...");
}
System.out.println("程序继续...");
}
}
package exception_;
public class TryCatchDetail02 {
public static void main(String[] args) {
// 1.如果 try 代码块有可能有多个异常
// 2.可以使用多个 catch 分别捕获不同的异常, 相应处理
// 3.要求子类异常写在前面, 父类异常写在后面
try {
Person person = new Person();
// person = null;
System.out.println(person.getName()); // NullPointerException
int n1 = 10;
int n2 = 0;
int res = n1 / n2; // ArithmeticException
} catch (java.lang.NullPointerException e) {
System.out.println("空指针异常=" + e.getMessage());
} catch (java.lang.ArithmeticException e) {
System.out.println("算术异常=" + e.getMessage());
} catch (Exception e) {
// e.printStackTrace();
e.getMessage();
} finally {
System.out.println("我无论如何都会执行");
}
}
}
class Person {
private String name = "jack";
public String getName() {
return name;
}
}
package exception_;
public class TryCatchDetail03 {
public static void main(String[] args) {
/*
可以进行 try-finally 配合使用, 这种用法相当于没有捕获异常,
因此程序会直接崩掉/退出, 应用场景, 就是执行一段代码, 不管是否发生异常,
都必须执行某个业务逻辑
*/
try {
int n1 = 10;
int n2 = 0;
System.out.println(n1 / n2);
} finally {
System.out.println("执行了 finally..");
}
System.out.println("程序继续执行..");
}
}
2.4.4、try-catch-finally 执行顺序小结
2.4.5、代码演示
如果用户输入的不是一个整数,就提示他反复输入,直到输入一个整数为止
package exception_;
import java.util.Scanner;
public class TryCatchExercise04 {
public static void main(String[] args) {
// 如果用户输入的不是一个整数, 就提示他反复输入, 直到输入一个整数为止
// 1. 创建 Scanner 对象
// 2. 使用无限循环, 去接收一个输入
// 3. 然后将该输入的值, 转成一个 int
// 4. 如果在转换时, 抛出异常, 说明输入的内容不是一个可以转成 int 的内容
// 5. 如果没有抛出异常, 则 break 该循环
Scanner scanner = new Scanner(System.in);
int num = 0;
String inputStr = "";
while (true) {
System.out.print("请输入一个整数: ");
inputStr = scanner.next();
try {
num = Integer.parseInt(inputStr);
break;
} catch (NumberFormatException e) {
System.out.println("输入的类型不正确, 请重新输入!");
}
}
System.out.println("num=" + num);
}
}
2.5、throws 异常处理
2.5.1、定义
2.5.2、注意事项和使用细节
package throws_;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ThrowsDetail {
public static void main(String[] args) {
f2();
}
public static void f2() /*throws ArithmeticException*/ {
// 1.对于编译异常, 程序中必须处理, 比如 try-catch 或者 throws
// 2.对于运行时异常, 程序中如果没有处理, 默认就是 throws 的方式处理
int n1 = 10;
int n2 = 0;
double res = n1 / n2;
}
public static void f1() throws FileNotFoundException {
// 这里大家思考问题 调用 f3() 报错
// 1. 因为 f3() 方法抛出的是一个编译异常
// 2. 即这时, 就要 f1() 必须处理这个编译异常
// 3. 在 f1() 中, 要么 try-catch-finally, 或者继续 throws 这个编译异常
f3(); // 抛出异常
}
public static void f3() throws FileNotFoundException {
FileInputStream fis = new FileInputStream("d://aa.txt");
}
public static void f4() {
// 1. 在 f4()中调用方法 f5() 是 OK
// 2. 原因是 f5() 抛出的是运行异常
// 3. 而 java 中, 并不要求程序员显示处理, 因为有默认处理机制
f5();
}
public static void f5() throws ArithmeticException {
}
}
class Father { // 父类
public void method() throws RuntimeException {
}
}
class Son extends Father { // 子类
// 3. 子类重写父类的方法时, 对抛出异常的规定: 子类重写的方法,
// 所抛出的异常类型要么和父类抛出的异常一致, 要么为父类抛出的异常类型的子类型
//4. 在 throws 过程中, 如果有方法 try-catch, 就相当于处理异常, 就可以不必 throws
@Override
public void method() throws ArithmeticException {
}
}
2.6、自定义异常
2.6.1、定义
2.6.2、自定义异常的步骤
2.6.3、代码实现
要求范围在 18 – 120 之间,否则抛出一个自定义异常
package throws_;
public class CustomException {
public static void main(String[] args) {
int age = 180;
// 要求范围在 18 – 120 之间, 否则抛出一个自定义异常
if (!(age >= 18 && age <= 120)) {
//这里我们可以通过构造器,设置信息
throw new AgeException("年龄需要在 18~120 之间");
}
System.out.println("你的年龄范围正确");
}
}
// 自定义一个异常
// 1. 一般情况下, 我们自定义异常是继承 RuntimeException
// 2. 即把自定义异常做成运行时异常, 好处是我们可以使用默认的处理机制
// 3. 即比较方便
class AgeException extends RuntimeException {
public AgeException(String message) { // 构造器
super(message);
}
}