异常
认识异常
异常分为两种{运行时异常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这里就不会很复杂。
补:运行时异常的处理(推荐的处理方式)
若能预知错误信息
//运行时异常:编译时不报错,运行的时候可能发生错误
int[] arr = new int[10];
int index = 11;
//解决运行时异常推荐的解决方案:能加预知到的异常数据进行校验排除
if (index < arr.length){
System.out.println(arr[11]);//编译时不报错,运行时发生异常
}
异常的作用
为什么我们要处理异常呢?
答:我觉得非常重要的一点就是防止程序崩溃,捕获异常可以防止程序因未处理的错误而突然终止。
1、异常是用来定位程序bug的关键信息;
2、可以作为方法内部的一种特殊返回值,以便通知上层调用者,方法的执行问题。
其次还可以返回
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); //调用父类有参构造器初始化异常消息
}
}
下面是规范的处理方式:先抛出小的异常,为了系统的安全性,我们在抛出一个大的异常(当出现未知异常时)。---> 推荐,更符合企业规范!!!
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 等框架的设计(如事务默认对运行时异常回滚)、避免过度捕获逻辑(由全局异常处理器统一处理),以及保持业务代码简洁性(仅对关键错误显式处理,其余交由上层统一管控)。这种策略使代码更灵活,降低耦合,更适合企业级分层架构和微服务场景。
年龄异常,不仅给用户友好的消息提示,还要给 管理员 发送短信通知年龄和合法错误 运行时异常异常,不仅给用户友好的消息提示,还要给管理员发送短信未知错误
异常处理方案
方案一:底层异常层层往上抛出,最外层捕获异常,记录下异常信息,并响应适合用户观看的信息进行提示.
例子:比如在京东官网。京东: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;
}