title: 异常
index_img: https://tuchuangs.com/imgs/2023/08/10/6e572ca2666c699d.png
tags:
- Java SE
categories:
- Java SE
excerpt: 异常处理
异常
异常继承体系
-
Error系统级错误(不是异常)
-
Exception程序可能出现的问题(不是错误),是异常的父类
-
RuntimeException异常的子类,运行时才会出现
-
其它异常:异常的子类,编译时异常
- 必须在编译时期处理
异常的作用
- 查询bug的关键参考信息
- 异常可以作为方法内部的一种特殊返回值,以便通知
调用者
底层的执行情况【相比直接打印结果,可以知道出错在哪一行,出现了说明问题】
异常处理
JVM默认异常处理
- 异常的名称、位置、原因等信息输出到控制台。
- 停止程序(后续代码不再执行)
public class Main {
public static void main(String[] args) {
System.out.println("我是测试语句1");
System.out.println(1 / 0);
System.out.println("看不见我");
}
}
try…catch捕获异常
这种方式,当出现异常,程序可以继续执行
用在调用处
格式
jdk7+支持catch中写多个异常(用|
),如果多种异常处理相同,可以使用
try{
可能出现的异常【注意可能】;
}catch(异常类型 变量名){
异常处理代码;
}
执行流程
- 没有异常,不会执行catch的语句
public class Main {
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9};
//没有异常
try {
System.out.println("正常执行");
} catch (AbstractMethodError e) {
System.out.println("数组越界"); //不会执行
}
System.out.println("看得见我吗3?");
}
}
- 出现异常,该处产生一个相关异常对象【如数组越界】
catch
中的异常类型变量如果可以接收上方产生的异常(范围大于等于)- 可以被接收,然后执行
catch
中的代码 catch
中代码执行结束,直接执行try…catch
外的代码【不会返回try了】
- 可以被接收,然后执行
- 一次只能产生一个异常,匹配一个catch
public class Main {
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9};
//产生ArrayIndexOutOfBoundsException异常且可以捕获
try {
System.out.println("我正常执行");
System.out.println(arr[10]);
System.out.println("看不见我"); //不会执行
} catch (Exception e) {
System.out.println("数组越界");
}
System.out.println("看得见我吗?");
}
}
如果可能产生多个异常,可以写多个catch,但父类异常类型应该写在最后
public class Main {
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9};
try {
System.out.println("我正常执行");
System.out.println(arr[10]);
System.out.println(1 / 0);
System.out.println(Integer.parseInt("java"));
} catch (NumberFormatException e) {
e.printStackTrace();
System.out.println("字符串格式不符合");
} catch (ArrayIndexOutOfBoundsException e) {
e.printStackTrace();
System.out.println("数组越界异常");
} catch (ArithmeticException e) {
e.printStackTrace();
System.out.println("算数异常");
} catch (Exception e) {
e.printStackTrace();
System.out.println("运行时异常");
}
System.out.println("看得见我吗?");
}
}
catch
捕获不到异常,不会执行其中的代码- 异常不存在,正常执行
- 异常范围不符,产生了但捕获不到,会交由JVM处理【控制台+终止】
public class Main {
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9};
//产生ArrayIndexOutOfBoundsException异常,但不可捕获
try {
System.out.println("正常执行");
System.out.println(arr[10]);
} catch (AbstractMethodError e) { //不匹配的异常,jvm处理
System.out.println("数组越界");
}
System.out.println("看得见我吗3?"); ///不会执行
}
}
Throable提供的方法
方法名 | 描述 |
---|---|
public String getMessage() | 返回此 throwable 的详细消息字符串 |
public String toString() | 返回此可抛出的简短描述 |
public void printStackTrace() | 把异常的错误信息输出在控制台 |
选其一即可:一般选择
printStackTrace()
,包含的信息最多。
public class Main {
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9};
//可捕获数组越界异常
try {
System.out.println(arr[10]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("throwable的详细消息字符串:" + e.getMessage());
System.out.println("异常简短信息:" + e.toString());
e.printStackTrace(); //将异常错误信息打印在控制台
}
System.out.println("看得见我吗3?");
}
}
抛出异常
throws
- 用在方法定义处,声明一个异常,本方法可能产生的异常
- 编译异常必须要写,运行时异常可以不写
public void 方法() throws 异常类型1,异常类型2....{
...
}
throw
- 用在方法内,结束方法
- 手动抛出异常对象,交给调用者,后面的代码不再执行【虚拟机接管了异常】
public void 方法(){
throw new NullpointerException();
}
案例
public class Main {
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9};
int[] arr1 = null;
int[] arr2 = {};
getMax(arr);
System.out.println("----------");
getMax(arr1);
System.out.println("----------"); //不会执行,上一步throw产生了异常,下面的都不会执行了
getMax(arr2);
}
// NullPointerException,ArrayIndexOutOfBoundsException是运行时异常,对于throws我们可以不用写
public static int getMax(int[] arr) /*throws NullPointerException,ArrayIndexOutOfBoundsException*/ {
if (arr == null) {
throw new NullPointerException("传入数组是null"); //空指针异常
}
if (arr.length == 0) {
throw new ArrayIndexOutOfBoundsException("传入数组长度为0"); //数组越界异常
}
System.out.println("如果异常有效我就看不见了");
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (max < arr[i]) {
max = arr[i];
}
}
return max;
}
}
抛出+捕获处理
在上一个案例,我们抛出异常,交由JVM默认处理异常【停止虚拟机执行后续代码】,接下来我们要try…catch
自行捕获处理,让后续代码可以执行。
public class Main {
public static void main(String[] args) {
int[] arr = {1, 3, 5, 7, 9};
int[] arr1 = null;
int[] arr2 = {};
System.out.println(handleException(arr)); // 输出9
System.out.println(handleException(arr1)); // 输出"传入数组是null",返回-1
System.out.println(handleException(arr2)); // 输出"传入数组长度为0",返回-1
}
public static int handleException(int[] arr) { //提取异常处理方法
try {
return getMax(arr);
} catch (NullPointerException | ArrayIndexOutOfBoundsException e) {
System.out.println(e.toString()); // 打印出异常的名字和详细信息
return -1; // 返回一个默认值
}
}
public static int getMax(int[] arr) {
if (arr == null) {
throw new NullPointerException("传入数组是null"); //包含具体的错误信息
}
if (arr.length == 0) {
throw new ArrayIndexOutOfBoundsException("传入数组长度为0"); //包含具体的错误信息
}
int max = arr[0];
for (int j : arr) {
if (max < j) {
max = j;
}
}
return max;
}
}
自定义异常
问题
java提供的异常不满足我们的需求,怎么办?
public class Friend {
String name;
int age;
public Friend() {
}
public Friend(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) { //这里产生的异常在java中没有描述,只好用运行时异常,方法内用throw
if(name.length()>5){
throw new RuntimeException();
}
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) { //这里产生的异常在java中没有描述,只好用运行时异常,throws可以不用(运行时异常可省略)
if(age<18 || age>40){
throw new RuntimeException();
}
this.age = age;
}
public String toString() {
return "Friend{name = " + name + ", age = " + age + "}";
}
}
public class Main {
public static void main(String[] args) {
Friend friend = new Friend();
Scanner sc = new Scanner(System.in);
while (true) { //使用循环产生异常,重写输入
try { //try...catch捕获异常
System.out.println("输入你想要的名字:");
String name = sc.nextLine();
friend.setName(name); //可能异常
System.out.println("输入你期望的年龄:");
String s = sc.nextLine();
int age = Integer.parseInt(s); //可能异常
friend.setAge(age); //可能数字格式化异常
break; //输入正确,跳出循环
} catch (NumberFormatException e) { //多张可能异常,可以多写几个catch,父类异常类型在最后
System.out.println("年龄格式错误");
} catch (RuntimeException e) {
System.out.println("姓名或年龄范围错误");
}
}
}
}
书写自定义异常
- 定义异常类
- 写继承关系
- 运行时异常继承RunTimeException【对于上方问日可以继承运行时异常】
- 编译时异常继承Exception
- 写空参构造
- 带参构造
public class NameException extends RuntimeException {
public NameException() {
}
public NameException(String message) {
super(message);
}
}
public class AgeException extends RuntimeException {
public AgeException() {
}
public AgeException(String message) {
super(message);
}
}
public class Friend {
String name;
int age;
public Friend() {
}
public Friend(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
if (name.length() > 5) {
throw new NameException("ameException:姓名太长"); //注意
}
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 18 || age > 40) {
throw new AgeException("AgeException:年龄不在范围"); //注意
}
this.age = age;
}
public String toString() {
return "Friend{name = " + name + ", age = " + age + "}";
}
}
public class Main {
public static void main(String[] args) {
Friend friend = new Friend();
Scanner sc = new Scanner(System.in);
while (true) { //使用循环产生异常,重写输入
try {
System.out.println("输入你想要的名字:");
String name = sc.nextLine();
friend.setName(name); //可能异常
System.out.println("输入你期望的年龄:");
String s = sc.nextLine();
int age = Integer.parseInt(s); //可能异常
friend.setAge(age); //可能数字格式化异常
break; //输入正确,跳出循环
} catch (NumberFormatException e) {
System.out.println("年龄格式错误");
} catch (AgeException e) { //年龄异常
e.printStackTrace();
} catch (NameException e) { //名字异常
e.printStackTrace();
}
}
}
}
标签:int,System,println,异常,public,out
From: https://www.cnblogs.com/SimpleWord/p/17689196.html