一 认识常见异常
在你所写过的代码中,你已经接触过一些异常了,我们可以通过一些简单的代码让我们理解一些简单的异常
1 除0异常(算术异常)
public class winning { public static void main(String[] args) { System.out.println(10/0); } }
我们都知道0是不能作为除数的,那么在这里作为除数运行之后结果如下:
画出圈的地方就是我们异常的一个种类,称为算术异常
2 数组越界异常
public class winning { public static void main(String[] args) { int[] array = {1,2,3}; System.out.println(array[4]); } }
运行结果:
3 空指针异常
public class winning { public static void main(String[] args) { int[] array = null; System.out.println(array[0]); } }
运行结果:
二 异常的体系
Exception是我们所有异常的父类,其中Error以及RuntimeException是我们平时所说的一个非受查异常(运行时异常),其他的异常为受查异常(编译时异常),前面介绍的几种常见的异常,就是RuntimeException的子类。
对于这些异常的处理,我们建议统一利用try-catch去处理,而且catch处理异常时,如果有父子类的异常,我们应该要遵循先写子类的异常,在写父类的异常。
三 异常的用法(try-catch语句)
1概述与代码理解
1 对于编写了一段代码,如果其中的一行发生了异常,那么之后的语句就不再执行(这是因为没有自己处理异常,那么就会交给JVM来处理)
2 对于使用try-catch语句来处理异常,把有可能出现异常的语句放在try中,如果try语句中的一行发生了异常,那么try语句中的下一行将不执行,但不影响后面的语句执行
3 对于try-catch语句,catch后面要跟着异常的类型,以及要相对应的定义一个变量。
public class winning { public static void main(String[] args) { try { int[] array = null; System.out.println(array[0]); System.out.println("abc"); }catch(NullPointerException e){ //打印出异常的调用栈 e.printStackTrace(); System.out.println("捕获到空指针异常了"); } System.out.println("执行了"); } }
运行结果:
2 注意事项
1 try-catch语句不能单独使用,必须联合起来处理异常
2 可以有多个catch,但不能有多个try
3 catch中可以写多个异常的类型,类型之间需要利用|隔开,但是变量必须定义到所写的最后一个类型的后面(也就是变量只能定义一个),但我们并不推荐这种写法,最好就是一种类型对应一个catch
4 catch中如果没有对应的异常类型,那么此时就会交给jvm去处理( catch 只能处理对应种类的异常)
3 finally语句
finally语句表示的是表示的善后工作,释放资源
public class winning { public static void main(String[] args) { try { int[] array = null; System.out.println(array[0]); System.out.println("abc"); }catch(NullPointerException e){ e.printStackTrace(); System.out.println("捕获到空指针异常了"); }finally { System.out.println("释放资源"); } } }
1 其实无论是否存在异常, finally 中的代码一定都会执行到,确保资源可以释放
2 finally语句是按情况写与不写,不是一定要有才能处理异常
3 使用的过程中,要按照try-catch-finally的顺序
利用try负责回收资源(了解)
此时我们可以把鼠标放到try这个关键字上,按下alt + enter,此时就有
这样子就相当于交由try来负责回收了,但这并不代表每一个异常都可以,只要是try在IDEA中报出了警告,我们可以尝试利用这样的一种快捷键让try去负责回收
finally注意事项
public class winning { public static void main(String[] args) { System.out.println(func()); } public static int func(){ try { return 20; }catch (NullPointerException e){ e.printStackTrace(); }finally { return 30; } } }
运行结果:
30
如果try语句中有返回值,以及finally语句中也有返回值,那么此时将会返回finally语句中的返回值,我们写代码的时候,不要使用这种写法(try与finally中同时拥有返回值)。
4 异常的传递
异常是会随着调用栈的调用而传递
public class winning { public static void main(String[] args) { try { func(); }catch (ArrayIndexOutOfBoundsException e){ e.printStackTrace(); } } public static void func(){ int[] array = {1,2,3,4}; System.out.println(array[29]); } }
运行结果:
如果向上传递的没有合适的方法处理异常,那么就会返回看上一个调用它的有没有合适的方法处理异常,一直到main中也没有合适的处理异常的方法,那么就只能由jvm来处理了
5 throw与throws关键字
对于throw关键字,我们可以通过这个关键字手动抛出异常
public class winning { public static void main(String[] args) { try { func(0); }catch (ArrayIndexOutOfBoundsException e){ e.printStackTrace(); } } public static void func(int a){ if (a==0){ throw new NullPointerException("空指针异常了"); } } }
throws 主要是用来提醒调用者,调用该方法可能会出现那些异常,需要进行处理
四 自定义异常
Java 中虽然已经内置了丰富的异常类, 但是我们实际场景中可能还有一些情况需要我们对异常类进行扩展, 创建符合我们实际情况的异常.
我们可以通过一个例子来说明一下:模拟用户登录,此时就可能抛出两种异常,一种是用户名错误异常,一种是密码错误异常:
我们先写出一段模拟登录的代码
public class winning { private static final String ID ="java"; private static final String Password = "666"; public static void main(String[] args) { System.out.println("请输入你的用户名"); Scanner scanner=new Scanner(System.in); String name = scanner.nextLine(); System.out.println("请输入你的密码"); String password = scanner.nextLine(); } }
定义抛出用户名错误的异常类
//定义一个用户名异常 class NameException extends RuntimeException{ public NameException(String name){ super(name); } }
定义抛出密码错误的异常
//定义一个密码异常 class PasswordException extends RuntimeException{ public PasswordException(String password){ super(password); } }
我们在进一步完善我们异常处理机制:
public class winning { private static final String ID ="java"; private static final String Password = "666"; public static void main(String[] args) { System.out.println("请输入你的用户名"); Scanner scanner=new Scanner(System.in); String name = scanner.nextLine(); System.out.println("请输入你的密码"); String password = scanner.nextLine(); if (!ID.equals(name)){ throw new NameException("用户名错了"); } if (!Password.equals(password)){ throw new PasswordException("密码有误"); } } }
通过这个例子,让我们了解什么是自定义异常类,如何使用异常类,当然以上代码可以进行优化,可以利用设置一个login登录函数,在利用try-catch进行捕获异常。
注意事项
对于自定义异常类:
1 一定要继承一个异常类(通常为Exception或者RunException)
2 继承Exception说明该类是可受查的
3 继承RunException说明该类是非受查类
结语
关于异常的认识,其实并没有像其他语法一样难理解,如果对你理解异常这一块也有帮助,别忘了给博主点个👍👍哦,之后的学习将会更新一些数据结构的知识!!