java 异常机制详细说明

java异常机制详细说明

基本概念

  • 异常就是"不正常"的含义,在Java语言中主要指程序执行中发生的不正常情况
  • java.lang.Throwable类是Java语言中错误(Error)和异常(Exception)的超类
  • 其中Error类主要用于描述Java虚拟机无法解决的严重错误,通常无法编码解决,如:JVM挂掉了 等
  • 其中Exception类主要用于描述因编程错误或偶然外在因素导致的轻微错误,通常可以编码解决, 如:0作为除数等。

异常的分类

  • java.lang.Exception类是所有异常的超类,主要分为以下两种:

    1. RuntimeException - 运行时异常,也叫作非检测性异常
    2. IOException- 输入输出异常和其它异常 - 其它异常,也叫作检测性异常,所谓检测性异常就是指在编译阶段都能 被编译器检测出来的异常
  • 其中RuntimeException类的主要子类

    1. ArithmeticException类 - 算术异常
    2. ArrayIndexOutOfBoundsException类 - 数组下标越界异常
    3. NullPointerException - 空指针异常
    4. ClassCastException - 类型转换异常
    5. NumberFormatException - 数字格式异常
  • 注意:

    当程序执行过程中发生异常但又没有手动处理时,则由Java虚拟机采用默认方式处理异常,而默认处理方式就是:打印异常的名称、异常发生的原因、异常发生的位置以及终止程序。

异常的机构图
请添加图片描述

异常的避免

  • 在以后的开发中尽量使用if条件判断来避免异常的发生

            // 算术异常
            int ia = 10;
            int ib = 0;
            if (0 != ib){
          
           // 判断除数不为0 执行下面代码
                System.out.println(ia / ib);
            }
            // 数组越界异常
            int[] arr = new int[10];
            int pos = 10;
            if (pos >= 0 && pos < arr.length){
          
           // 判断数组索引值是否合法
                System.out.println(arr[pos]);
            }
    
  • 但是过多的if条件判断会导致程序的代码加长、臃肿,可读性差

异常的捕获

  • 语法格式

    try {
          
          
     	编写可能发生异常的代码;
    }catch(异常类型 引用变量名) {
          
          
     	编写针对该类异常的处理代码;
    }...
    finally {
          
          
     	编写无论是否发生异常都要执行的代码;
    }
    
  • 注意事项

    1. .当需要编写多个catch分支时,切记小类型应该放在大类型的前面子类在父类的前面

    2. 懒人的写法:

      catch(Exception e) {} 不建议 因为代码的可读性差

    3. finally通常用于进行善后处理,如:关闭已经打开的文件等

  • 执行流程

    try {
          
          
    	a;
     	b; - 可能发生异常的语句
     	c;
    }catch(Exception ex) {
          
          
     	d;
    }finally {
          
          
     	e;
    }
    // 当没有发生异常时的执行流程:a b c e;
    // 当发生异常时的执行流程:a b d e;
    
  • 关于finally类的笔试考点

    private static int test() {
          
          
            try {
          
          
                String str = null; // 定义一个空字符串
                // 将字符串信息转大写操作 由于字符串是空 所以会发生空指针异常 异常发生后 return 0 不会执行
                System.out.println(str.toLowerCase()); 
                return 0;
            }catch (NullPointerException e){
          
          
            // 进行异常处理 打印异常信息 打印完之后将结束方法的执行 但是finally未执行 所以执行finally之后 返回 
                e.printStackTrace();
                return 1;
            }finally {
          
          
            // 提前结束方法
                return 2;
            }
        }
    

    注意事项 如果finally 未结束方法的执行 先执行finally内部的代码块 然后执行return 1

异常的抛出

  • 基本概念

    在某些特殊情况下有些异常不能处理或者不便于处理时,就可以将该异常转移给该方法的调用者, 这种方法就叫异常的抛出。当方法执行时出现异常,则底层生成一个异常类对象抛出,此时异常代 码后续的代码就不再执行

  • 语法格式

    访问权限 返回值类型 方法名称(形参列表) throws 异常类型1,异常类型2,...{
          
           
    	方法体; 
    }
    
  • 代码演示

    1. 方法throws异常

      private static void test() throws IOException {
              
              
              FileInputStream fi = new FileInputStream("e:/a.txt");  // 此处会发生 IOException
              fi.close();
          }
      
    2. 调用发法依旧 throws 且发生异常位置不会进行

      public static void main(String[] args) throws IOException {
              
              
              test();  // 此处会发生 IOException
              System.out.println("------"); // 因为交给虚拟机处理 所以中断处理 所以此处及之后的代码不会执行
          }
      
  • 注意事项

    main方法 不建议把异常throws 因为交给虚拟机处理 所以中断处理

  • 方法重写的原则

    1. 要求方法名相同、参数列表相同以及返回值类型相同,从jdk1.5开始支持返回子类类型

    2. 要求方法的访问权限不能变小,可以相同或者变大;

      public > default > protected > private

    3. 要求方法不能抛出更大的异常;

  • 注意:

    子类重写的方法不能抛出更大的异常、不能抛出平级不一样的异常,但可以抛出一样的异常、更小 的异常以及不抛出异常

  • 经验分享

    • 若父类中被重写的方法没有抛出异常时,则子类中重写的方法只能进行异常的捕获处理
    • 若一个方法内部又以递进方式分别调用了好几个其它方法,则建议这些方法内可以使用抛出 的方法处理到最后一层进行捕获方式处理

自定义异常

  • 基本概念

    当需要在程序中表达年龄不合理的情况时,而Java官方又没有提供这种针对性的异常,此时就需要 程序员自定义异常加以描述

  • 实现流程

    1. 自定义xxxException异常类继承Exception类或者其子类。

    2. 提供两个版本的构造方法,一个是无参构造方法,另外一个是字符串作为参数的构造方法。

    3. 代码实现

      public class NameException extends Exception{
              
              
          static final long serialVersionUID = -3387516993124229948L; // 序列化版本号 有序列化操作有关
      
          public NameException() {
              
              
          }
      
          public NameException(String message) {
              
              
              super(message);
          }
      }
      
  • 异常的产生

    throw new 异常类型(实参);

    代码演示

    public class Student {
          
          
        private String name;
    
        public Student() {
          
          
        }
    
        public Student(String name) throws NameException {
          
          
            setName(name);
        }
    
        public void setName(String name) throws NameException {
          
          
            if (name.matches(".{2,8}")){
          
           // 判断用字输入 2 - 8个字符
                this.name = name;
            }else throw new NameException("请输入2-8位的汉字或英语字符");
    
        }
    
        @Override
        public String toString() {
          
          
            return "Student{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    

    创建之后的调用

    public class StudentTest {
          
          
        public static void main(String[] args) {
          
          
            Student s = null;
            try {
          
          
                s =  new Student("张三三三三三三三三");
            } catch (NameException e) {
          
          
                e.printStackTrace();
            }
            System.out.println(s); // null
        }
    }
    
    

Guess you like

Origin blog.csdn.net/Junsunnyl/article/details/119973026