Java异常处理
# 异常处理
# Java异常处理
# 异常概述、体系
# 什么是异常?
- 异常是程序在“编译”或者“执行”的过程中可能出现的问题,**注意:**语法错误不算在异常体系中。
- 比如:数组索引越界、空指针异常、 日期格式化异常,等…
# 为什么要学习异常?
- 异常一旦出现了,如果没有提前处理,程序就会退出JVM虚拟机而终止.
- 研究异常并且避免异常,然后提前处理异常,体现的是程序的安全, 健壮性。
# 异常体系
Error:
- 系统级别问题、JVM退出等,代码无法控制。
Exception:java.lang包下,称为异常类,它表示程序本身可以处理的问题
RuntimeException及其子类
:运行时异常,编译阶段不会报错。 (空指针异常,数组索引越界异常)除RuntimeException之外所有的异常
:编译时异常,编译期必须处理的,否则程序不能通过编译。 (日期格式化异常)。
# 编译时异常和运行时异常
# 常见运行时异常
# 运行时异常
直接继承自RuntimeException或者其子类
,编译阶段不会报错,运行时可能出现的错误。
# 运行时异常示例
- 数组索引越界异常:
ArrayIndexOutOfBoundsException
- 空指针异常 :
NullPointerException
,直接输出没有问题,但是调用空指针的变量的功能就会报错。 - 数学操作异常:
ArithmeticException
- 类型转换异常:
ClassCastException
- 数字转换异常:
NumberFormatException
package com.Error;
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("+++++程序开始+++++");
/*1.数组索引越界异常: ArrayIndexOutOfBoundsException。*/
int[] arr = {1,2,3};
System.out.println(arr[3]); // 运行出错
/*2.空指针异常: NullPointerException* 直接输入没有问题,但是调用空指针的变量的功能就会报错 */
String name = null;
System.out.println(name.length()); // 运行出错
/*3.类型转换异常: ClassCastException */
Object o = 23;
String s = (String) o; //转换报错
/*5.数字操作异常: ArithmeticException */
int c = 10 / 0;
/*6.数字转换异常: NumberFormatException */
String number = "23";
Integer it = Integer.valueOf(number);
System.out.println(it + 1);
System.out.println("+++++程序结束+++++");
}
}
# 常见编译时异常
# 编译时异常
不是RuntimeException或者其子类的异常
,编译阶就报错,必须处理,否则代码不通过。
# 编译时异常示例
package com.Error;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo2 {
// 日期解析异常:throws ParseException
public static void main(String[] args) throws ParseException {
String date = "2015-01-12 10:23:21";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
}
}
编译时异常的特点
- 编译时异常:继承自Exception的异常或者其子类
- 编译阶段报错,必须处理,否则代码不通过。
# 异常的默认处理流程
①默认会在出现异常的代码那里自动的创建一个异常对象:ArithmeticException。
②异常会从方法中出现的点这里抛出给调用者,调用者最终抛出给JVM虚拟机。
③虚拟机接收到异常对象后,先在控制台直接输出异常栈信息数据。
④直接从当前执行的异常点干掉当前程序。
后续代码没有机会执行了,因为程序已经死亡。
默认异常处理机制。
默认的异常处理机制并不好,一旦真的出现异常,程序立即死亡!
# 编译时异常的处理机制
# throws
- throws:用在方法上,可以将方法内部出现的异常抛出去给本方法的调用者处理。
这种方式并不好,发生异常的方法自己不处理异常,如果异常最终抛出去给虚拟机将引起程序死亡。
小技巧
CTRL + ALT + T
构建异常操作
抛出异常格式
方法 throws 异常1 ,异常2 ,异常3 ..{
}
规范做法:
代表可以抛出一切异常
方法 throws Exception{
}
package com.Error;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo4 {
// public static void main(String[] args) throws ParseException, FileNotFoundException {
public static void main(String[] args) throws Exception {
System.out.println("程序开始");
parseTime("2021-11-11 11:11:11");
System.out.println("程序结束");
}
// 添加异常,如果触发了第一个异常之后,先抛出第一个异常,后面的异常就不会继续检测
// public static void parseTime(String date) throws ParseException, FileNotFoundException {
// throws 多个异常的时候,可以使用最大的异常, Exception
public static void parseTime(String date) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
InputStream is = new FileInputStream("E:/test.jpg");
}
}
运行结果:
程序开始
Thu Nov 11 11:11:11 CST 2021
Exception in thread "main" java.io.FileNotFoundException: E:\test.jpg (系统找不到指定的文件。)
at java.io.FileInputStream.open0(Native Method)
at java.io.FileInputStream.open(FileInputStream.java:195)
at java.io.FileInputStream.<init>(FileInputStream.java:138)
at java.io.FileInputStream.<init>(FileInputStream.java:93)
at com.Error.ExceptionDemo4.parseTime(ExceptionDemo4.java:23)
at com.Error.ExceptionDemo4.main(ExceptionDemo4.java:12)
# try…catch…
- 监视捕获异常,用在方法内部,可以将方法内部出现的异常直接捕获处理。
这种方式还可以,发生异常的方法自己独立完成异常的处理,程序可以继续往下执行。
抛出异常格式
try{
// 监视可能出现异常的代码!
}catch(异常类型1 变量){
// 处理异常
}catch(异常类型2 变量){
// 处理异常
}...
建议格式:
try{
// 可能出现异常的代码!
}catch (Exception e){
e.printStackTrace(); // 直接打印异常栈信息
}
Exception可以捕获处理一切异常类型!
package com.Error;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo5 {
public static void main(String[] args) {
System.out.println("程序开始");
parseTime("2021-11-11 11:11:11");
System.out.println("程序结束");
}
public static void parseTime(String date) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
InputStream is = new FileInputStream("E:/test.jpg");
} catch (Exception e) {
// 打印异常栈的信息
e.printStackTrace();
}
}
}
运行结果:
程序开始
java.text.ParseException: Unparseable date: "2021-11-11 11:11:11"
at java.text.DateFormat.parse(DateFormat.java:366)
at com.Error.ExceptionDemo5.parseTime(ExceptionDemo5.java:17)
at com.Error.ExceptionDemo5.main(ExceptionDemo5.java:11)
程序结束
# 前两者结合
- 方法直接将异通过throws抛出去给调用者
- 调用者收到异常后直接捕获处理。
package com.Error;
import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ExceptionDemo6 {
public static void main(String[] args) {
System.out.println("程序开始");
// 执行的时候检查异常,如果有异常可以抛出异常后继续执行后面的
try {
parseTime("2021-11-11 11:11:11");
System.out.println("操作成功");
} catch (Exception e) {
e.printStackTrace();
System.out.println("操作失败");
}
System.out.println("程序结束");
}
// 这里使用Execption抛出底层的异常
public static void parseTime(String date) throws Exception {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM-dd HH:mm:ss");
Date d = sdf.parse(date);
System.out.println(d);
InputStream is = new FileInputStream("E:/test.jpg");
}
}
运行结果:
程序开始
java.text.ParseException: Unparseable date: "2021-11-11 11:11:11"
at java.text.DateFormat.parse(DateFormat.java:366)
at com.Error.ExceptionDemo6.parseTime(ExceptionDemo6.java:22)
at com.Error.ExceptionDemo6.main(ExceptionDemo6.java:12)
操作失败
程序结束
# 运行时异常的处理机制
- 运行时异常编译阶段不会出错,是运行时才可能出错的,所以编译阶段不处理也可以。
- 按照规范建议还是处理:建议在最外层调用处集中捕获处理即可。
package com.Error;
public class ExecptionDemo7 {
public static void main(String[] args) {
/*
目标: 运行时的异常处理机制
可以不处理,编译阶段又不报错
按照理论规则: 建议还是处理,只需要在最外层捕获处理即可
*/
System.out.println("程序开始");
try {
chu(10,0);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("程序结束");
}
public static void chu(int a,int b){
System.out.println(a);
System.out.println(b);
int c = a / b;
System.out.println(c);
}
}
运行结果:
10
0
程序结束
java.lang.ArithmeticException: / by zero
at com.Error.ExecptionDemo7.chu(ExecptionDemo7.java:21)
at com.Error.ExecptionDemo7.main(ExecptionDemo7.java:12)
# 异常处理使代码更稳健的案例
需求
- 键盘录入一个合理的价格为止(必须是数值)。
分析
- 定义一个死循环,让用户不断的输入价格。
package com.Error;
import java.util.Scanner;
public class Test2 {
/*
需求: 需要输入一个合法的价格为止,要求价格大于0
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
try {
System.out.println("请您输入合法的价格:");
String pricesStr = sc.nextLine();
// 转换double类型的价格
double price = Double.valueOf(pricesStr);
// 判断价格是否大于0
if (price > 0){
System.out.println("定价:" + price);
break;
}else {
System.out.println("价格必须是正数");
}
} catch (Exception e) {
System.out.println("用户输入的数据有问题,请输入合法的数值,建议正数");
}
}
}
}
运行结果:
请您输入合法的价格:
12.11.1
用户输入的数据有问题,请输入合法的数值,建议正数
请您输入合法的价格:
12.1
定价:12.1
# 自定义异常
# 自定义异常的必要?
- Java无法为这个世界上全部的问题提供异常类。
- 如果企业想通过异常的方式来管理自己的某个业务问题,就需要自定义异常类了。
# 自定义异常的好处
- 可以使用异常的机制管理业务问题,如提醒程序员注意。
- 同时一旦出现bug,可以用异常的形式清晰的指出出错的地方。
# 自定义异常的分类
1、自定义编译时异常
- 定义一个异常类继承Exception.
- 重写构造器。
- 在出现异常的地方用throw new 自定义对象抛出,
作用:编译时异常是编译阶段就报错,提醒更加强烈,一定需要处理!!
2、自定义运行时异常
- 定义一个异常类继承RuntimeException.
- 重写构造器。
- 在出现异常的地方用throw new 自定义对象抛出!
作用:提醒不强烈,编译阶段不报错!!运行时才可能出现!!
示例:
创建一个自定义异常
package com.Error;
public class ItheimaAgeIlleagalException extends Exception{
/*
自定义编译时异常
1. 继承Exception
2. 重写构造器
*/
public ItheimaAgeIlleagalException() {
}
public ItheimaAgeIlleagalException(String message) {
super(message);
}
}
调用自定义异常报错
package com.Error;
public class ExecptionDemo8 {
public static void main(String[] args) {
try {
checkAge(201);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void checkAge(int age) throws ItheimaAgeIlleagalException {
if (age < 0 || age > 200){
// 抛出去一个异常对象给调用者
// throw: 在方法内部直接创建一个异常对象,并从此点抛出
// throws: 用在方法申明上的,抛出方法内部的异常
throw new ItheimaAgeIlleagalException(age + "is illeagel!");
}else {
System.out.println("年龄合法: 推荐商品给其购买");
}
}
}
运行结果:
com.Error.ItheimaAgeIlleagalException: 201is illeagel!
at com.Error.ExecptionDemo8.checkAge(ExecptionDemo8.java:16)
at com.Error.ExecptionDemo8.main(ExecptionDemo8.java:6)
上次更新: 2023/11/28, 22:03:59