异常

异常的背景

初识异常

异常是程序的运行过程中出现的一种错误

编译期:在编译过程中,如果编译通过,一定不存在编译错误
运行时:在运行过程中,现在没有错误,不代表后面就没有错误;在自己的机器上没有错误,不代表在别人机器上没有错误…
数学上证明:没有办法证明一段程序是没有 bug 的

异常其实是帮助我们解决问题的一种很好的手段
异常的种类有很多,分别代表不同的含义,一旦出现某个异常,此时这个异常的意义是明确的,明确的表现出出现异常的原因

初以0

数组下标越界

空指针异常

防御式编程

“未言胜先言败”
防御是编程有两种具体代码的具体形式

英雄联盟开局的伪代码

LBYL

Look Before You Leap
操作之前就做充分的检查. 检查完上一步之后,再来做下一步的操作. 如果上一步失败,就不继续执行了

伪代码表现形式:

boolean ret = false;
ret = 登陆游戏();
if (!ret) {
    处理登陆游戏错误;
    return;
}
ret = 开始匹配();
    if (!ret) {
    处理匹配错误;
    return;
}
ret = 游戏确认();
    if (!ret) {
    处理游戏确认错误;
    return;
}
ret = 选择英雄();
    if (!ret) {
    处理选择英雄错误;
    return;
}
ret = 载入游戏画面();
if (!ret) {
    处理载入游戏错误;
    return;
}
..............

EAFP

It’s Easier to Ask Forgiveness than Permission.
事后获取原谅比事前获取许可更加简单(先斩后奏)

伪代码形式:

try {
登陆游戏();
开始匹配();
游戏确认();
选择英雄();
载入游戏画面();
...
} catch (登陆游戏异常) {
处理登陆游戏异常;
} catch (开始匹配异常) {
处理开始匹配异常;
} catch (游戏确认异常) {
处理游戏确认异常;
} catch (选择英雄异常) {
处理选择英雄异常;
} catch (载入游戏画面异常) {
处理载入游戏画面异常;
}
............

异常的基本用法

捕捉异常

异常主要涉及到的几个关键字:

  1. try: try 语句块中放置可能会抛出异常的代码
  2. catch:语句块中放置用来处理异常的代码. try 和 catch 往往要搭配使用,当 try 中出现异常的事后,就会进入 catch 中执行
  3. throw:主动抛出异常对象(Java 的异常本质上就是一个一个的对象)
  4. throws:某个方法可能会抛出某些异常
  5. finally:一般用于异常处理完毕后的收尾工作

基本语法:

try{
有可能出现异常的语句 ;
} catch (异常类型 异常对象) {
} ... 
finally {
异常的出口
}
  • try 代码块中方的是可能出现异常的代码块
  • chtch 代码块中放的是出现异常后的处理行为
  • finally 代码块中的代码块用于处理善后工作,会在最后执行
  • 其中 catch 和 finally 都可以根据实际情况原则加或者不加

例1 :
如果代码中出现了异常,并且没有使用 try catch 异常就会有由JVM 自己来处理,程序就会被直接终止

int[] a = null;
System.out.println(a[0]);

在这里插入图片描述

例2 :
代码中可以使用 try 把可能抛出异常的代码给包裹起来,使用 catch 来处理这样的异常

    public static void main(String[] args) {
        try {
            System.out.println("try 中异常之前代码");
            int[] a = null;
            System.out.println(a[0]);
            System.out.println("catch 中异常之后的代码");
        } catch (NullPointerException e){
            System.out.println("catch 中的代码");
        }
        System.out.println("hello");
    }

在这里插入图片描述

try catch 的执行顺序“

  1. 先执行 try 中的代码块(按顺序执行)
  2. 执行 try 代码的过程,如果出现异常,就会进入到 catch 执行。try 中剩下的代码就不再执行了
  3. 当 catch 也执行完毕之后,就会继续执行后续的代码,程序没有异常终止

常见的 “错误分级” 体系:

  • Fatal :最严重的
  • Error :比较严重的
  • Warning :不太严重的
  • Info / Notice :没啥事的

例3 :

    public static void main(String[] args) {
        try {
            System.out.println("try 中异常之前代码");
            int[] a = {1, 2, 3};
            System.out.println(a[100]);
            System.out.println("catch 中异常之后的代码");
        } catch (NullPointerException e){
            System.out.println("catch 中的代码");
        }
        System.out.println("hello");
    }

在这里插入图片描述

catch 中的异常的类型需要和抛出的异常类型匹配,才能够正确的处理,否则执行不到 catch 中的逻辑
如果 try 中抛出的异常的类型和 catch 中声明的类型不匹配,才是 catch 中代码就不会被执行到
使用 try catch 的时候,必须要非常明确的知道,try 中都会抛出哪些异常

例4 :
如果 try 中可能抛出多种异常的话,也就需要多个 catch 语句来进行处理
1 个 try 可以对应 N 个 catch
多个 catch 之间就好像多分支语句一样

    public static void main(String[] args) {
        try {
            System.out.println("try 中异常之前代码");
            int[] a = {1, 2, 3};
            System.out.println(a[100]);
            System.out.println("catch 中异常之后的代码");
        } catch (NullPointerException e){
            System.out.println("catch 空指针异常");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("catch 下标越界异常");
        }
        System.out.println("hello");
    }

在这里插入图片描述

例5 :
可以使用一个 catch 语句来捕捉多个异常
使用 | 就可以把多好异常的类型并列起来,相当于 “逻辑或”
抛出这若干个异常中的任何一个,都会触发 catch

    public static void main(String[] args) {
        try {
            System.out.println("try 中异常之前代码");
            int[] a = {1, 2, 3};
            System.out.println(a[100]);
            System.out.println("catch 中异常之后的代码");
        } catch (NullPointerException | ArrayIndexOutOfBoundsException e){
            System.out.println("catch 异常");
        }
    }

在这里插入图片描述

或者使用更高级别的父类,空指针异常和数组越界异常都是 Exception 的子类

    public static void main(String[] args) {
        try {
            System.out.println("try 中异常之前代码");
            int[] a = {1, 2, 3};
            System.out.println(a[100]);
            System.out.println("catch 中异常之后的代码");
        } catch (Exception e){
            System.out.println("catch 异常");
        }
    }

在这里插入图片描述

例6 :
使用 finally

    public static void main(String[] args) {
        try {
            System.out.println("try 中异常之前代码");
            int[] a = {1, 2, 3};
            System.out.println(a[100]);
            System.out.println("catch 中异常之后的代码");
        } catch (Exception e){
            System.out.println("catch 异常");
        } finally {
            System.out.println("hello");
        }
    }

在这里插入图片描述
例7 :
使用 finally 回收资源

    public static void main(String[] args) {
        Scanner scanner = null;
        try {
            scanner = new Scanner(System.in);
        } catch (NullPointerException e){
            System.out.println("空指针异常");
        } finally {
            scanner.close();
        }
    }

使用 try with resource 执行回收资源
代码执行完之后会自动释放 Scanner 的空间

    public static void main(String[] args) {
        try (Scanner scanner = new Scanner(System.in)) {
            
        } catch (NullPointerException e) {
            System.out.println("空指针异常");
        }
    }

例8 :
如果当前方法没有适合的 catch ,异常就会沿着调用栈向上传递

    public static void main(String[] args) {
        try {
            func1();
        } catch(ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
        } finally {
            System.out.println("finally");
        }
        System.out.println("hello");
    }

    public static void func1() {
        func2();
    }

    public static void func2() {
        int[] a = {1, 2, 3};
        System.out.println(a[100]);
    }

如果异常向上传递的过程中,移植到了最上面之后还是没有遇到 catch ,此时异常就会由 JVM 自己来处理,程序就会直接终止

例9 :
在 final 代码块中谨慎使用 return

  public static void main(String[] args) {
  System.out.println(func());
  }
  
  public static int func() {
  try {
      return 10;
      } final {
      return 20;
      }
 }

在这里插入图片描述

Java 异常体系

在这里插入图片描述

  • 顶层类 Throwable 派生出两个重要的子类, Error 和 Exception
  • 其中 Error 指的是 Java 运行时内部错误和资源耗尽错误. 应用程序不抛出此类异常. 这种内部错误,一旦出现,除了告知用户并使程序终止之外, 再无能无力. 这种情况很少出现
  • Exception 是我们程序猿所使用的异常类的父类
  • 其中 Exception 有一个子类称为 RuntimeException , 这里面又派生出很多我们常见的异常类NullPointerException , IndexOutOfBoundsException 等

Java 语言规范将派生于Error 类或 RuntimeException 类的所有异常称为 非受查异常, 所有的其他异常称为 受查异常

如果是 受查异常,就必须显式处理

使用try catch 包裹起来

public static void main(String[] args) {
     System.out.println(readFile());
     }
     
public static String readFile() {
     File file = new File("d:/test.txt");
     Scanner sc = null;
     try {
         sc = new Scanner(file);
         } catch (FileNotFoundException e) {
             e.printStackTrace();
             }
    return sc.nextLine();
}

在方法上加上异常说明,相当于将处理动作交给上级调用者

public static void main(String[] args) {
    try {
       System.out.println(readFile());
       } catch (FileNotFoundException e) {
            e.printStackTrace();
            }
}

public static String readFile() throws FileNotFoundException {
    File file = new File("d:/test.txt");
    Scanner sc = new Scanner(file);
    return sc.nextLine();
}

自定义异常类

public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String name = scanner.next();
        try {
            name(name);
        } catch (NameException e) {
            e.printStackTrace();
        }
        boolean result = !name.equals("admin");
        //判断输入的用户名是否正确,如果不正确抛出异常且结束运行
        if(result) {
            return;
        }
        System.out.println("请输入密码:");
        String password = scanner.next();
        try {
            password(password);
        } catch (PasswordException e) {
            e.printStackTrace();
        }
}

    public static void name(String name) throws NameException {
        if (!name.equals("admin")) {
            throw new NameException("用户名错误");
        }
    }

    public static void password(String password) throws PasswordException {
        if (!password.equals("123456")) {
            throw new PasswordException("密码错误");
        }
    }

注:

  • 自定义异常通常会继承自 Exception 或者 RuntimeException
  • 继承自 Exception 的异常默认是受查异常
  • 继承 RuntimeException 的异常默认是非受查异常
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值