Java异常处理的艺术
衡量一段代码质量的真正标准,并非是它在理想情况下运行得有多快,而是在混乱与未知面前,它能表现得有多坚韧。健壮的程序,如同经验丰富的船长,不惧怕风暴,因为它早已为各种意外做好了准备。
在Java中,异常处理机制就是我们为代码打造的‘应急预案’。但你是否曾想过,你的 try-catch
块究竟是在真正地‘处理’问题,还是仅仅在‘隐藏’问题?本文将不仅仅停留在语法的教学,更希望与你一同探讨异常处理背后的设计哲学,帮助你写出真正‘优雅’且‘可靠’的代码。
异常
异常的概念
异常是指在序执行过程中发生的一种特殊情况或者错误状态它打断了程序的正常流程,需要特别处理~~
我们从一个例子帮你了解异常
public class Demo1 {public static void main(String[] args) {int[] array = null;int[] array1 = {1, 2, 3};// 算术异常System.out.println(10 / 0);
// 空指针异常System.out.println(array.length);// 数组下标越界异常System.out.println(array1[100]);}
}
这个代码运行的结果是什么?这个代码是否能正常运行?是否能运行完?
很明显~~ 这个代码执行到第一个输出语句就跑出了这个异常,而且程序也结束。由此我们可以得出,代码中出现异常,程序就会终止
那我们有什么办法让程序不终止,即使发生了异常。兄弟,有的有的~~我们可以使用try-catch语句
具体如下
public class Demo1 {public static void main(String[] args) {int[] array = null;int[] array1 = {1, 2, 3};try{
// 算术异常System.out.println(10/0);}catch(Exception e){System.out.println(e.getMessage());}try{
// 空指针异常System.out.println(array.length);}catch(Exception e){System.out.println(e.getMessage());}try{
// 数组下标越界异常System.out.println(array1[100]);}catch(Exception e){System.out.println(e.getMessage());}}
}
这个代码执行的结果是什么呢?是否可以正常执行完?
显而易见,用try-catch语句包裹后,是可以正常执行完的·
我们可以从中看异常有算术异常、空指针异常、数组下标越界异常,那么还有什么异常呢?
那我们可以了解一下异常的类型~~
异常的类型
从中我们可以看出 最顶上有个Throwable。 Throwable的子类是Error,和Excepption
这个Error的概念是
通常表示由Java虚拟机(JVM)引发的严重问题,这些问题超出了应用程序的处理能力~~
那我们重点看看这个异常~~
我们从上面图片上可以看出,这里面有两个异常,一个是受检查异常和非受检查异常~~
受检查异常和非受检查异常的概念
受检查异常的定义~~
受检查异常也叫做编译时的异常~~ 就是程序在编译阶段就发生的异常~~
非受检查异常
非检查异常也就叫做运行时的异常~~就是程序在运行阶段发生的异常~~
刚才最开头举个例子就是非受检查异常~~
那让我们看看异常之间的关系,看下图
异常间的关系
Exception是所有异常的父类~~ RuntimeException是我橙色框圈住的异常父类~~ IOExcepiton的子类是FileNotFoundExcepiton~~
ok,异常的关系我们已经梳理完了
那我们说说try-catch语句~~
try-catch语句~~
语法格式
try{//catch括号里面的是异常类型}catch(ArithmeticException e){}catch (NullPointerException e){}catch (Exception e){}finally {}
让我们举一个具体的实例,让你们理解一下try-catch语句的使用以及注意事项~~
int[] array = null;int[] array1 = {1, 2, 3};try{System.out.println(array.length);System.out.println(array1[100]);}catch(ArithmeticException e){System.out.println(e.getMessage());}catch (NullPointerException e){System.out.println(e.getMessage());}catch (Exception e){System.out.println(e.getMessage());} finally {System.out.println("finally已经被执行~~");}
这个程序会输出什么?
我们由这个运行的结果,可以看出array1[100]数组下标越界异常没有被处理~~ 由此我们可以看出,catch语句只能执行一次~~它是按照顺序执行的~~一但捕获到了异常,这个catch'语句就不会再执行了~~最后finally类的语句是必须执行的,这个通常处理收尾工作~~ 比如资源回收等等~~
try{System.out.println(array.length);System.out.println(array1[100]);}catch(Exception e){System.out.println(e.getMessage());}catch (NullPointerException e){System.out.println(e.getMessage());}catch (ArrayIndexOutOfBoundsException e){System.out.println(e.getMessage());} finally {System.out.println("finally已经被执行~~");}
我们是否可以这样写?大家可以仔细考虑下~~
答案是不能的~~因为Exception是所有异常的父类~~~ 它可以捕获所有子类的异常~~它的范围很大~~这会导致其他catch语句都无法执行~~
ok,我们基本上把try-catch语句基本说完了~~ 那我们继续往后走~~
看看下面代码
public class Test {public static void main(String[] args) {int[] array = null;if(array == null) {throw new NullPointerException();}System.out.println(666);}
}
代码运行的结果⬇️
throw关键字
定义:
这个throw关键字是提前判断程序是否有可能抛出异常~~ 它是非常有用~~ 用来定位错误~~
注意:
1.throw跑出的对象必须是Exception或者Exception的子类对象~~
2.如果抛出的是RunTimeException或者RunTimeException的子类,则可以不用处理,直接交给JVM来进行处理~~
3.如果跑出的是编译时的异常,用户必须处理,否则无法通过编译
异常一旦发生,其后的代码就不会执行~~
看看下面的代码是否有问题??
那让我们具体看看
ok在方法后面使用throws IOException
也可以使用try-catch语句块进行包裹~~
由此我们可以得出受检查异常,必须在编译期间进行手动处理~~
throws关键字
定义:
throws关键字用于在方法声明中列出该方法可能抛出的异常,它告诉调用者这个方法可能会抛出哪些异常,调用者需要处理这些异常。使用throws实际上是将异常的处理中责任转移给了调用该方法的代码
注意:
1.throws必须跟在方法的参数列表之后
2.声明的异常必须是Exception或者Exception的子类
3.方法内部如果抛出了多个异常,throws之后必须跟多个异常类型,之间用逗号隔开,如果抛出多个异常类型具有父子关系,直接声明父类即可
自定义异常~~
有些时候官方定义的异常不够我们使用。我们这时候需要自定义异常,那我们应该怎么自定义异常呢?
这个下面的代码就是自定义异常的代码~~
这个代码需要继承父类Exception,实现父类的构造方法~~ 这个message,就是你要抛出异常的信息~~
class UserNameException extends Exception {public UserNameException(String message) {super(message);}
}class PasswordException extends Exception {public PasswordException(String message) {super(message);}
}
注意:
1.自定义异常通常会继承自Exception或者RuntimeExcepiton
2.继承自Exception的异常默认是受查异常
3.继承自RuntimeException的异常默认值非受查异常~
那我们用一个类来实现这些自定义异常~~
public class LogIn {private String userName = "admin";private String password = "123456";public void loginInfo(String userName, String password)throws UserNameException, PasswordException {if (!this.userName.equals(userName)) {throw new UserNameException("用户名错误!");}if (!this.password.equals(password)) {throw new PasswordException("密码错误!");}System.out.println("登陆成功");}public static void main(String[] args) {try {LogIn login = new LogIn();login.loginInfo("admi", "123456");} catch (UserNameException e) {e.printStackTrace();} catch (PasswordException e) {e.printStackTrace();}}
}
这个代码的执行结果是什么?
本文旨在分享一些个人见解,但限于作者的知识水平和认知范围,文中可能存在谬误或欠妥之处。我真诚地欢迎并感谢任何形式的批评与指正,期待在交流中共同进步。
如果觉得有用,请点亮那个“赞”吧!这样不仅方便你日后回顾,也能让更多有需要的朋友看到这篇文章。