异常分为两种{运行时异常RuntimeException}和{编译时异常}
运行时异常RuntimeException:运行时异常:继承自RuntimeException,编译阶段(写代码的时候)不会报错,运行时才会出现的异常。
编译时异常:写代码时就可能出现的错误提醒。
1.ArrayIndexOutOfBoundsException 数组越界异常
int[] arr = {11,22,33};
0 1 2
System.*out*.println(arr[0]);
System.*out*.println(arr[1]);
System.*out*.println(arr[2]);
System.out.println(arr[3]);//ArrayIndexOutOfBoundsException 数组越界异常
2.ArithmeticException 数学计算异常
System.out.println(10/0);
3.NullPointerException 空指针异常 ( 企业开发中常见 )
String name = null;
System.*out*.println(name);
System.*out*.println(name.length());//NullPointerException 空指针异常
1. 日期解析异常
//1.解析时间异常
String dataStr = "2024-11-12 11:24:32";
//2.创建一个简单的日期格式化对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//3.开始把字符串时间解析成日期对象
Date d = sdf.parse(dataStr);
此处不确定dataStr是一个标准格式的时间,所以在转换时可能出错,所以parse会报错
这里补充快捷键:
查看前代(光标放到类上):ctrl+alt+U
查看后代(光标放到类上):ctrl+H
解决方法有两种:
方式一:捕获异常 (try…catch)
这里有一个快捷键(ctrl+alt+T),选择第6个即可
private static void testException() {
try {
//1.解析时间异常
String dataStr = "2024-11-12 11:24:32";
//2.创建一个简单的日期格式化对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
//3.开始把字符串时间解析成日期对象
Date d = sdf.parse(dataStr);
} catch (Exception e) {
e.printStackTrace();
}
}
方式二:抛出异常( throws )
private static void testException() throws Exception {
//1.解析时间异常
String dataStr = "2024-11-12 11:24:32";
//2.创建一个简单的日期格式化对象
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//3.开始把字符串时间解析成日期对象
Date d = sdf.parse(dataStr);
//读一个文件
FileInputStream is = new FileInputStream("D:/meinv.png");
}
当代码中异常出现较多,我们直接抛出总异常 (Exception),这样throws这里就不会很复杂。
若能预知错误信息
go
//运行时异常:编译时不报错,运行的时候可能发生错误
int[] arr = new int[10];
int index = 11;
//解决运行时异常推荐的解决方案:能加预知到的异常数据进行校验排除
if (index < arr.length){
System.*out*.println(arr[11]);//编译时不报错,运行时发生异常
}
为什么我们要处理异常呢?
答:我觉得非常重要的一点就是防止程序崩溃,捕获异常可以防止程序因未处理的错误而突然终止。
1、异常是用来定位程序bug的关键信息;
2、可以作为方法内部的一种特殊返回值,以便通知上层调用者,方法的执行问题。
其次还可以返回
java
public static void main(String[] args) {
//目标:异常的作用
System.*out*.println(*device*(10,2));
System.*out*.println("----------------------------------");
System.*out*.println(*device*(10,0));
}
private static int device(int a,int b) {
if(b==0){
System.*out*.println("参数b不能为0");
throw new RuntimeException("/ 0");
}
return a / b;
}
思考:为什么要自定义异常?
答:Java无法为这个世界上全部的问题都提供异常类来代表, 如果企业自己的某种问题,想通过异常来表示,以便用异常来管理该问题,那就需要自己来定义异常类了。
问题严重,用自定义编译异常(继承Exception);问题不严重,用自定义运行异常(继承RuntimeException);常用自定义运行异常(企业常用)。
1、继承Exception
2、重写构造器:封装异常的错误信息。
3、抛出自定义编译时异常
自定义编译时异常:继承Exception
// 自定义编译时异常
// 1、继承Exception
// 2、重写构造器:封装异常的错误信息。
public class AgeIllegalException extends Exception{
//重写无参构造器
public AgeIllegalException() {
}
//重写有参挂构造器
public AgeIllegalException(String message) {
super(message); *//* *调用父类有参构造器初始化异常消息*
}
*//* *后面使用异常会获取异常消息,使用父类的getMessage()方法获取异常消息*
}
自定义运行时异常:继承RuntimeException
// 自定义运行时异常
// 1、继承RuntimeException
// 2、重写构造器:封装异常的错误信息。
public class AgeIllegalRuntimeException extends RuntimeException{
public AgeIllegalRuntimeException() {
}
public AgeIllegalRuntimeException(String message) {
super(message); *//* *调用父类有参构造器初始化异常消息*
}
}
下面是规范的处理方式:先抛出小的异常,为了系统的安全性,我们在抛出一个大的异常(当出现未知异常时) 。 ---> 推荐,更符合企业规范!!!
typescript
public static void main(String[] args) {
//目标:设置有效的年龄,有效年龄范围0~200,当年龄无效抛出年龄不合法的自定义异常
try {
*setAge*(100);
*setAge*(203);
} catch (AgeIllegalRuntimeException e) {
e.printStackTrace();//打印异常堆栈信息到控制台(异常完整信息,以后会写入日志文件),给开发人员看的
System.*out*.println("发生错误:"+e.getMessage()+",请重新输入年龄");//给用户看的(后面,这个信息会给到前端)
} catch (Exception e) {
e.printStackTrace();//打印异常堆栈信息到控制台(异常完整信息,以后会写入日志文件),给开发人员看的
System.*out*.println("系统繁忙,请稍后再试");//给用户看的(后面,这个信息会给到前端)
}
}
public static void setAge(int age){
if (age < 0 || age > 200){
//throw new RuntimeException("年龄不合法");//使用父类异常导致职责不清晰
//以后项目中异常要分类:
// 年龄异常,不仅给用户友好的消息提示,还要给管理员发送短信通知年龄和合法错误
// 运行时异常异常,不仅给用户友好的消息提示,还要给管理员发送短信未知错误
//如何解决:自定义年龄不合法异常,可以异常类型职责清晰
//3.抛出自定义运行时异常
//throw new 异常类型("友好的异常消息")
throw new AgeIllegalRuntimeException("年龄不合法");
}
System.*out*.println(age+"年龄合法,保存成功");
}
问:企业开发中为什么常用自定义运行时异常,很少使用自定义编译时异常?
答:减少代码侵入性(避免强制 try-catch 或 throws 声明)、符合 Spring 等框架的设计(如事务默认对运行时异常回滚)、避免过度捕获逻辑(由全局异常处理器统一处理),以及保持业务代码简洁性(仅对关键错误显式处理,其余交由上层统一管控)。这种策略使代码更灵活,降低耦合,更适合企业级分层架构和微服务场景。
年龄异常,不仅给用户友好的消息提示,还要给管理员发送短信通知年龄和合法错误
运行时异常异常,不仅给用户友好的消息提示,还要给管理员发送短信未知错误
开发过程中调用A方法时-->A调用B-->B调用C;C出现异常,C抛给B-->B抛给A-->A捕获处理异常
方案一:底层异常层层往上抛出,最外层捕获异常,记录下异常信息,并响应适合用户观看的信息进行提示.
例子:比如在京东官网。京东:re.jd.com/ ----》re.jd.com/dasd/dad/sd…
被最外层捕获异常,记录下异常信息,并响应适合用户观看的信息进行提示:www.jd.com/error2.aspx
方案二:最外层捕获异常后,尝试重新修复
public static void main(String[] args) {
// 目标:捕获异常后,尝试重新修复。
while (true) {
try {
*getPrice*();
break;
} catch (Exception e) {
System.*out*.println("价格输入有误,请重新输入!");
}
}
}
public static double getPrice(){
Scanner sc = new Scanner(System.*in*);
System.*out*.println("请输入商品价格:");
double price = sc.nextDouble();
return price;
}