异常处理目录

  • 1.异常概述
  • 1.1概念
  • 1.2异常的体系结构
  • 1.3异常的分类
  • 2.异常的处理
  • 2.1异常处理的“抓抛模型”
  • 2.2异常处理的方式一:try-catch-finally
  • 2.3异常处理的方式二:throws + 异常类型
  • 2.4如何选择异常处理方式
  • 3.手动处理异常
  • 3.1throw和throws之间的区别
  • 3.2throw典型例题
  • 3.3自定义异常类的实现


1.异常概述

1.1概念

   在Java语言中,将程序执行中发生的不正常情况称为“异常”。 (开发过程中的语法错误和逻辑错误不是异常)

1.2异常的体系结构

异常主要分为编译时异常和运行时异常

java.lang.Throwable
   |-----java.lang.Error:一般不编写针对性的代码进行处理。
   |-----java.lang.Exception:可以进行异常的处理
       |------编译时异常(checked)
            |-----IOException
               |-----FileNotFoundException
            |-----ClassNotFoundException
       |------运行时异常(unchecked,RuntimeException)
            |-----NullPointerException
            |-----ArrayIndexOutOfBoundsException
            |-----ClassCastException
            |-----NumberFormatException
            |-----InputMismatchException
            |-----ArithmeticException

1.3异常的分类

     运行时异常:是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常,对于此类异常一般不做处理
     编译时异常:是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一般性异常。

2.异常的处理

2.1异常处理的“抓抛模型”

过程一:“抛”:程序正在执行的过程中,一旦抛出异常,就会在异常代码处生成一个对应的异常类对象 并将此对象抛出。
     一旦抛出对象以后,其后的代码就不再执行。

关于异常对象的产生:
①系统自动生成一个异常对象
②手动的生成一个异常对象,并抛出throw

过程二:“抓”:可以理解为异常的处理方式:①try-catch-finally ② throws

2.2异常处理的方式一:try-catch-finally

使用的方式:

java中编译时异常的含义 java编译时异常的处理方案_java


说明(理解很重要):

 1.finally是可选的
 2.使用try将可能出现的异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个异常类的对象,根据此对象的类型,去catch中进行匹配
 3.一旦try中的异常对象对象匹配到某一个catch时,就会进入catch中进行异常处理,一旦处理完成,就跳出try-catch结构,继续执行其后的代码
 4.catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓catch中的异常类型如果有子父类关系,则子类要声明在父类上面
 5.常见的异常处理方式:
    ①getMessage() ②e.printStackTrace();
 6.使用try-catch处理编译异常时,使得程序在编译时不报错,运行时还可能会报错, 相当于将一个编译时出现的错误,延时到运行时出现
 7.try-catch-finally结构可以再次嵌套try-catch
  在开发中,针对运行时异常一般不做处理,对于编译时异常使用try-catch-finally进行处理

使用样例:

public class ExceptionTest1 {

    public static void main(String[] args) {

    }

	//ArithmeticException 算术运算异常
    @Test
    public void Test6() {
        try {
            int a = 10;
            int b = 0;
            System.out.println(a / b);
        }catch (ArithmeticException e){
            e.printStackTrace();
        }

    }


   @Test
   public void Test2(){
        try{
            File file = new File("hello.txt");
            FileInputStream fis = new FileInputStream(file);

            int data = fis.read();
            while(data != -1){
                System.out.print((char) data);
                data = fis.read();
            }
            fis.close();
        }catch (FileNotFoundException e){
            e.printStackTrace();
        }catch (IOException e){
            e.printStackTrace();
        }

   }

    //NumberFormatException数据格式异常
    @Test
    public void Test4() {
        String str = "123";
        str = "abc";
        try {
            int number = Integer.parseInt(str);//把字符串转为整型
        }catch (NumberFormatException e){
           // System.out.println("出现数值转换异常了");
            e.printStackTrace();
            System.out.println(e.getMessage());//获取异常信息
        }catch (NullPointerException e){
            System.out.println("出现空指针异常了");
        }catch (Exception e){
            System.out.println("出现异常了");
        }

    }
}

🍀finally的使用
说明:

1.finally是可以选择写,也可以选择不写的,具体情况具体分析,如果有必须要执行的就需要写
2.finally中声明的是一定会被执行的代码,即使catch中又出现异常了,try中有return语句,catch中有return语句等情况。
3.像数据库连接、数据输入输出流、网络编程Socket等资源,JVM是不能进行自动回收的,我们需要自己手动的进行资源的释放。此时的资源释放,就需要声明在finally中。

使用样例一:

public int test2() {
        try {
            int[] arr = new int[10];
            System.out.println(arr[10]);
            return 1;
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
            return 2;
        } finally {
            System.out.println("一定会被执行");
        }
    }

使用样例二:

@Test
    public void test3() {
        FileInputStream fis = null;//需要初始化
        try {
            File file = new File("C:\\Users\\Administrator\\Desktop\\com.java.li\\src\\day10\\com\\it\\java0\\hello.txt");
            fis = new FileInputStream(file);
            //可能此处出现异常,所以他会直接到第一个异常处理机制里面,因此fis.close()可能不会被关闭
            //--》fis.close()放在while下面显然有些不合适,他是一定会执行的语句,所以放在finally里比较好
            //异常套异常

            int data = fis.read();
            while (data != -1) {
                System.out.print((char) data);
                data = fis.read();
            }
            //fis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fis != null){
                    fis.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

2.3异常处理的方式二:throws + 异常类型

1.概述:

“throws + 异常类型”写在方法的声明处,指明此方法在执行时可能会出现的异常类型。
    当方法体执行出现异常时,仍会在异常代码处生成一个一场类的对象,此时对象满足throws后的异常类型时,就会被抛出,异常代码的后续代码就不会被执行!

2.两种方式之间的区别:

“try-catch-finally”真正的将异常处理掉了
“throws + 异常类型”只是将异常抛出给方法的调用者,并没有将异常真正处理掉

注意:子类的异常类型不大于父类的异常类型

throws使用样例:

public class ExceptionTest2 {
    public static void main(String[] args) {

        try {
            method2();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void method2()throws IOException{
        method1();
    }

    public static void method1()throws  IOException {
        File file = new File("C:\\Users\\Administrator\\Desktop\\com.java.li\\src\\day10\\com\\it\\java0\\hello.txt");
        FileInputStream fis = new FileInputStream(file);

        int data = fis.read();
        while(data != -1){
            System.out.print((char) data);
            data = fis.read();
        }
        fis.close();
    }
}

2.4如何选择异常处理方式

方式一:

     如果父类中被重写的方法没有throws的方式处理异常,则子类被重写的方法也不能使用throws的方式,意味着子类重写方法的异常必须使用try-catch-finally的方式处理异常

方式二:

    执行的方法a中,先后又调用了另外几个方法,这几个方法是递进的关系,(方法一的结果传递给方法二,方法二的结果传递给方法三),建议这几个方法使用throws的方式进行处理。而执行的方法a可以考虑使用try-catch-finally的方式处理异常

3.手动处理异常

1.概述:

    在程序执行的过程中,除了自动抛出异常对象的情况之外,我们还可以手动的throw一个异常对象。

3.1throw和throws之间的区别

throw:表示抛出一个异常类的对象,生成异常类的对象的过程;声明在方法体内

throws属于异常处理方式的一种,声明在方法体外。

3.2throw典型例题

测试类:

public class StudentTest {

    public static void main(String[] args) {

        try {
            Student student = new Student();
            student.regist(-100);
            System.out.println(student);
        } catch (Exception e) {
            e.printStackTrace();
            e.getMessage();
        }

    }
}

Student类:

class Student {

    private int id;

    public void regist(int id)  throws Exception{//处理方法二抛出一个异常
        if (id > 0) {
            this.id = id;
        } else {//手动抛出一个异常处理方法1
            //throw new RuntimeException("输入的数据有误");

            //方式二
            //throw new Exception("输入的数据有误");

            //方式三,使用自定义异常
            throw new MyException("输入的数据为负数");
        }
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                '}';
    }
}

手写异常类:

public class MyException extends RuntimeException{

    static final long serialVersionUID = 7034897101145766939L;

    public MyException(){
    }

    public MyException(String msg){
        super(msg);
    }
}

3.3自定义异常类的实现

实现自定义异常类的步骤:

1.继承于现有的异常结构,RuntimeException,Exception
2.提供全局常量:serialVersionUID
3.提供重载的构造器

样例:

public class MyException extends RuntimeException{

    static final long serialVersionUID = 7034897101145766939L;

    public MyException(){
    }

    public MyException(String msg){
        super(msg);
    }
}