JAVA异常处理

1.what?异常

在程序的运行中总会遇到些问题导致不能顺利的运行下去,例如:内存耗尽,程序崩溃了,机房起火异常断电,打代码太激动踢到网线断开服务这种无法救治的问题。这种问题总是少数 更多的是我们开发时疏忽或者运行过程的特定场景引发的 例如:

类型 Obj obj = test.getObj(); 如果 test为空的话将会出现nullPointException异常,总的来说异常就是在我们预期范围之外的非正常的情况。

2.异常的类型

在java中异常主要分为两大类,程序可以处理(Exception)的和程序无能为力的(Error)。

  1. java的异常模型:
  1. ┌───────────┐
  2. Object
  3. └───────────┘
  4. ┌───────────┐
  5. Throwable
  6. └───────────┘
  7. ┌─────────┴─────────┐
  8. ┌───────────┐ ┌───────────┐
  9. Error Exception
  10. └───────────┘ └───────────┘
  11. ┌───────┘ ┌────┴──────────┐
  12. ┌─────────────────┐ ┌─────────────────┐┌───────────┐
  13. OutOfMemoryError │... RuntimeException ││IOException│...
  14. └─────────────────┘ └─────────────────┘└───────────┘
  15. ┌───────────┴─────────────┐
  16. ┌─────────────────────┐ ┌─────────────────────────┐
  17. NullPointerException IllegalArgumentException │...
  18. └─────────────────────┘ └─────────────────────────┘

java无能为力的(Error)

OutOfMemoryError内存耗尽

NoClassDefFoundError无法加载某个Class

StackOverflowError栈溢出

java本身可以处理的(Exception)

exception作为代码运行时的错误,该异常可以捕获并处理。

例如:IoException异常。

3.异常的处理

简单异常的捕获

捕获异常通常使用 try…cathch语句来处理异常,把可能出现异常的代码写在try{ … }代码块中,然后使用catch来捕获相对应的异常(Exception 及其 子类)。

e.g.

  1. File file = new File("D:\\DeskTop\\1.txt");
  2. try {
  3. InputStream inputStream = new FileInputStream(file);
  4. } catch (FileNotFoundException e) {
  5. e.printStackTrace();
  6. } finally {
  7. System.out.println("Hello word");
  8. }
  1. 我们在读取文件的时候存在文件找不到的问题,所以我们需要对该问题进行解决,当出现找不到文件(FileNotFoundException)的时候将会执行 catch中的代码来代替正常运行的代码。其中finally关键字后面的代码块在 try 或者 catch 后执行。那么问题来了 如果 try 或者 catch 代码夸中 出现了 return; 关键字时会怎么样呢?

答案是:当finally 前面的代码块中如果出现了 return 关键字时 try 或者 catch 中的代码会停止 直接进入finally代码块中,finally中的代码执行完毕后再执行 try 或者 catch 中的return关键字。

java规范 我们必须捕获或者继续抛出 除 Error 异常 或者 RunTimeException 及其 子类的异常。这句话的意思是如果我们的代码可能会出现 Error或者RunTimeException 他们的异常我们可以不用处理 ,但其他异常我们必须处理否则会出现编译代码失败。

多重异常捕获

捕获

在 try catch finally 中 catch 可以有多个 分别捕获不同的异常 但是按顺序来说异常必须是从小到大的出现。

当try 代码中需要处理 FileNotFoundException 或者UnsupportedEncodingException异常时我们可以使用两个 catch 代码块来分别处理,以此类推try中需要处理几个就可以有几个catch代码块。

  1. try {
  2. InputStream inputStream = new FileInputStream(new File("d//1.txt"));
  3. } catch (IOException e) {
  4. System.out.println("IO error");
  5. } catch (UnsupportedEncodingException e) { // 永远捕获不到
  6. System.out.println("Bad encoding");
  7. }

上面代码中 IOException 包含了UnsupportedEncodingException 所以IOException 抛出后UnsupportedEncodingException 已经没有机会抛出。

简化

  1. try {
  2. InputStream inputStream = new FileInputStream(new File("d//1.txt"));
  3. } catch (IOException e) {
  4. System.out.println("IO error");
  5. } catch (UnsupportedEncodingException e) { // 永远捕获不到
  6. System.out.println("Bad encoding");
  7. }

可以简化为:

  1. try {
  2. InputStream inputStream = new FileInputStream(new File("d//1.txt"));
  3. } catch (IOException e | UnsupportedEncodingException ue) {
  4. System.out.println("IO error");
  5. }

异常的抛出

我们有时候不想对代码里的异常处理想扔给会面调用自己的代码来处理时,我们可以使用 throws 来声明后续代码来处理

  1. public static void test(File file) throws FileNotFoundException {
  2. InputStream inputStream = new FileInputStream(file);
  3. }

这样的话 在后者调用 test(File file) 方法时,会提示处理 throws 后面的 FileNotFoundException 异常。

4.自定义异常

异常类

上面我们已经知道了 , 异常为 Exception 的子类 所以我们需要 一个 继承自 Exception的类。

  1. /**
  2. * 通缉令
  3. * @author zhanghsun
  4. * @date 2020/05/13 11:30:12
  5. */
  6. public class MyException extends Exception {
  7. /**
  8. * 重写 父类的 构造方法
  9. * @param message 错误信息
  10. */
  11. public MyException(String message) {
  12. super(message + ":呀被发现了!");
  13. }
  14. }

异常的使用

  1. /**
  2. * 异常测试
  3. * @author zhangshun
  4. * @date 2020/05/13 11:33:02
  5. */
  6. public class TestMyException {
  7. public static void main(String[] args) {
  8. String name = "zhangsan";
  9. try {
  10. System.out.println(validZhangSan(name));
  11. } catch (MyException e) {
  12. // 获取错误信息
  13. System.out.println("抛出问题:" + e.getMessage());
  14. }
  15. // 换成李四
  16. name = "lisi";
  17. try {
  18. System.out.println(validZhangSan(name));
  19. } catch (MyException e) {
  20. // 获取错误信息
  21. System.out.println("抛出问题:" + e.getMessage());
  22. }
  23. }
  24. /**
  25. * 验证张三
  26. * @param name 名字
  27. */
  28. public static String validZhangSan(String name) throws MyException {
  29. if ("zhangsan".equals(name)) {
  30. throw new MyException(name);
  31. }
  32. return "你通过了检验:" + name;
  33. }
  34. }

总结

其实在java自带的异常的使用和我们自定义的使用一样的我们可以看下

这个是 FileInputStream 类的源码

  1. public FileInputStream(File file) throws FileNotFoundException {
  2. String name = (file != null ? file.getPath() : null);
  3. SecurityManager security = System.getSecurityManager();
  4. if (security != null) {
  5. security.checkRead(name);
  6. }
  7. if (name == null) {
  8. throw new NullPointerException();
  9. }
  10. if (file.isInvalid()) {
  11. throw new FileNotFoundException("Invalid file path");
  12. }
  13. fd = new FileDescriptor();
  14. fd.attach(this);
  15. path = name;
  16. open(name);
  17. }

他们的使用 也是通过 throw 来抛出。。

其中:thow 和 trows 的区别

throw 表示我们要抛出一个异常,该行为出现了问题

thows 表示该方法可能会出现异常,需要调用者来处理,throws 可以声明读个异常