Java异常处理| 青训营笔记

88 阅读6分钟

这是我参与「第四届青训营 」笔记创作活动的的第1天

异常处理| 青训营笔记

异常的概述

定义:开发过程中,程序执行中的不正常情况叫“异常”。

ERROR:一般不编写针对性代码处理

Exception:其他因编程错误或偶然的外在因素导致的一般性问题,可以用针对性的代码进行处理。例如:

  • 空指针访问
  • 试图读取不存在的文件
  • 网络连接中断
  • 数组角标越界

解决方法:

  • 遇到错误终止程序
  • 考虑错误检测,错误信息提示和错误处理

异常的分类

  • 编译时:受检异常
  • 运行时:非受检异常

常见异常

checked

  • IOException:FileNotFoundException
File file = new File("hello.txt");
FileInputStream fileInputStream = new FileInputStream(file);
int data = fileInputStream.read();
while (data!=-1){
    System.out.println((char) data);
    data= fileInputStream.read();
}
fileInputStream.close();
  • ClassNotFoundException:找不到某个类

unchecked

  • NullPointerException:空指针
int[] arr=null;
System.out.println(arr[3]);
  • ArrayIndexOutOfBoundsException:数组下标溢出
String str="abc";//数组下标范围0-2
System.out.println(str.charAt(3));//charAt()返回指定索引的 char价值
  • ClassCastException:类型转换异常
Object obj= new Date();
String str=(String) obj;//不是所有类之间都能相互转换
  • NumberFormatException:应用程序试图将一个字符串转换为数字类型的一个,但该字符串没有适当的格式。
String str="a";
int i = Integer.parseInt(str);//将字符串参数作为带符号的十进制整数。
  • InputMismatchException:输入类型错误
Scanner scanner = new Scanner(System.in);
int score = scanner.nextInt();//扫描为Int那输入流只能为int,否则就会报输入错误
System.out.println(score);
scanner.close();
  • ArithmeticException:算术错误
int a=100;
int b=0;
System.out.println(a/b);

异常的处理

抛抓模型

  • 过程一 "抛":程序在正常执行的过程中,一旦出现异常,就会生成对应的异常类对象,并将此对象抛出。一旦程序出现异常,下面代 码将不再被执行。
  • 过程二 "抓":可以理解为异常的处理方式:①try-catch-finally ②throws

try-catch-finally的使用

try{
    //可能发生异常的代码
}catch(异常类型1 变量名1){
    //处理异常的方法1
}catch(异常类型2 变量名2){
    //处理异常的方法2
}catch(异常类型3 变量名3){
    //处理异常的方法3
}finally{
    //一定会执行的代码
}

说明:

  1. Finally是可选的
  2. 使用try将可能出现异常的代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应的异常类对象,根据此对象的类型,会与catch中的条件进行匹配
  3. 一旦try中的异常对象进入ctach并且完成处理之后,就退出当前的try-ctach结构,继续执行后续代码
  4. catch中的异常类没有父子类关系,则声明顺序不规定,如果满足父子类关系,则子类要在父类之上
  5. 常用的异常对象处理方式:①String getMessage() ②printStackTrace() ②(常用)包含①
  6. try结构中声明的变量,出了try就无法使用了

体会1:try-catch-finally处理编译时错误,是让程序在编译时不报错,如果该编译时错误会导致运行时错误,则在运行时仍可能报错。相当于我们把一个编译时错误延迟到了运行时发生

体会2:只用try-catch-finally处理编译时异常,而不处理运行时异常

finally

情况一:异常处理里面还有异常(避免忽略物理连接关闭)

 /** * Created with IntelliJ IDEA. * * @Author: 谭铭豪 * @Date: 2022/07/16/9:28 * @Description:JDK8后的注解使用位置 */class Generic<@MyAnnotation T>{    public void show()throws @MyAnnotation RuntimeException{        ArrayList<@MyAnnotation String> list = new ArrayList();        int num=(@MyAnnotation int)10L;   }}java

    //Finally一定会被执行
    //情况一:异常处理里面还有异常(避免忽略物理连接关闭)
    FileInputStream fileInputStream=null;
    try {
        File file = new File("hello.txt");
        fileInputStream = new FileInputStream(file);
        int data = fileInputStream.read();
        while (data!=-1){
            System.out.println((char) data);
            data= fileInputStream.read();
        }
​
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        if(fileInputStream!=null)
            try {
                fileInputStream.close();    //JVM不能关闭物理连接:数据库连接,输入输出流连接,Socket连接
            } catch (IOException e) {       //防止异常里面还有异常
                e.printStackTrace();
            }
    }

情况二:异常代码里有返回值(避免忽略代码)

//情况二:异常代码里有返回值(避免忽略代码)
先执行finally,再return x;
@Test
void Method()
{
    this.test01();
}
int test01()  {
    try {
        Object obj= new Date();
        String str=(String) obj;//不是所有类之间都能相互转换
        return 1;
    } catch (Exception e) {
        e.printStackTrace();
        return 2;
    }finally {
        System.out.println("我一定会被执行");
    }
}

throws的使用

说明:

  1. 把下层结构的编译时错误提到调用该方法的方法处再解决
  2. 但最迟只能到main()解决,不然虚拟机JVM也解决不了时,会出大问题
@Test
void test02(){
    try {
        test01();//此处调用了throws错误的结构,所以此处要解决或继续向上抛出错误,但最迟只能到main()解决,不然虚拟机会坏
    } catch (Exception e) {
        e.printStackTrace();
    }
}
​
void test01() throws IOException {  //把下层结构的编译时错误提到调用该方法的方法处再解决
    File file = new File("hello.txt");
    FileInputStream fileInputStream = new FileInputStream(file);
    int data = fileInputStream.read();
    while (data!=-1){
        System.out.println((char) data);
        data= fileInputStream.read();
    }
    fileInputStream.close();
}

方法重写处理异常的注意事项

子类重写父类的方法抛出的异常类型不大于父类被重写方法的异常类型

public class ExceptionTest2 {
    public void display(SuperClass s){
        try {
            s.method();
        } catch (Exception e) {
            //由于多态,可能传入子类对象作为特殊父类而报错,子类抛出异常时就要考虑父类处理异常使用否包含得住子类的异常,
            // 处理的方案就是让子类的异常类型小于父类的异常类型
            e.getMessage();
        }
    }
}
​
class SuperClass{
    void method() throws Exception {
        //父类操作
    }
}
​
class SubClass extends SuperClass{
    @Override
    void method() throws IOException {
        //子类操作
    }
}

开发中如何选择处理异常的方法

  1. 由于上述限制,父类没有抛出异常(throws)时,子类也不能throws,言下之意就是此时的子类只能通过try-catch-finally来处理对象
  2. 如果有递进关系,则用throws向上抛至包含递进关系的上一层方法(最典型的main方法就包含了大多数的其他方法)用try-catch处理,因为这样就可以一次处理掉整个递进关系中的异常,且不影响递进关系的运行
  3. 手动抛出异常(throw)
  4. try-catch-finally和throws都是为了展示友好的错误提示或提供给用户的错误界面,实际解决异常的方式还是要修改代码

手动抛出异常(throw)

  1. 限制非法操作,当出现非法操作时,阻止程序继续进行
  2. 对需要返回值但是会出异常的情况
public class ExceptionTest2 {
    public static void main(String[] args) {
        try {
            Student s=new Student();
            s.regist(-1001);
            System.out.println(s.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
​
class Student{
    private int id;
    public void regist(int id) throws Exception {
        if(id>0){
            this.id=id;
        }
        else {
            //System.out.println("您的输入的非法!");
            //利用这种方法时,System.out.println(s.toString());仍然会执行,这是非法操作不应该有的
            throw new RuntimeException("您的输入非法!");
        }
    }
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                '}';
    }
}

自定义异常类

  1. 继承Exception
  2. 重写序列号
  3. 重写有参和无参构造器
public class TeamException extends Exception{
    static final long serialVersionUID = -3387229948L;//用于字节流作判断
​
    public TeamException() {
        super();
    }
​
    public TeamException(String message) {
        super(message);
    }
}

\