学习笔记之JavaSE(20)--面向对象编程11

来源:互联网 发布:决战武林进阶数据地煞8 编辑:程序博客网 时间:2024/05/18 14:27

今天学习的内容是异常


在程序中,错误可能产生于程序员没有预料到的各种情况,或者是超出程序员可控范围的环境因素,比如用户的坏数据、试图打开一个根本不存在的文件等等。在Java中这种在程序运行时可能出现的一些问题称为异常,它中断了程序的继续运行。其实异常就是Java通过面向对象的思想将问题封装成对象,用异常类对其进行描述。异常的知识点如下:

  • Java异常体系中的顶级父类是Throwable类,该类和该类的所有子类都具有可抛性
  • Throwable类的两个子类分别是Error类和Exception类
  • Error类及其子类描述的是系统内部错误以及资源耗尽错误,这种问题无法在程序中处理,必须直接修改程序
  • Exception类及其子类描述的是可处理的问题,程序员通常关心的是Exception
  • 所有标准Exception类都有两个构造函数:一个是无参构造函数;另一个是接受字符串作为参数的构造函数,用于初始化本类中继承于Throwable类的detailMessage字符串变量,并可以通过getMessage()方法获取
  • Exception类的子类可以根据问题发生的原因分为运行时异常(RuntimeException类及其子类)被检查异常(除了RuntimeException的异常类)
  • 被检查异常会被编译器检测到,并要求在程序中对此异常进行针对性处理,否则编译失败
  • 运行时异常不会被编译器检测到,这种问题实际上属于编程错误,更多是因为调用者的原因导致的,或者引发了内部状态的改变导致的。这种问题一般不做处理当然也可以对运行时异常进行处理,不过声明抛出没有必要,捕获处理则会造成隐患
  • 如果遇到标准Exception类没有描述的问题,可以自定义异常。自定义异常的方法就是继承Exception类或RuntimeException类,自定义异常同样也分为被检查异常和运行时异常
  • 处理异常的方法:声明抛出捕获处理
  • 声明抛出:使用throw关键字将异常对象抛给调用方,并在方法的参数列表后面使用throws关键字声明要抛出的异常。从效果上看,抛出异常类似返回异常,抛出异常之后方法弹栈,throw语句之后的代码不再执行
  • 除非要抛出自定义异常或者想要通过有参构造函数自定义异常信息,否则不用显式地throw异常
  • 运行时异常不需要声明抛出,而被检查异常如果没有进行捕获处理,就必须声明抛出
  • 如果一直向调用方抛异常对象而没有进行捕获处理,那么最终会由main()方法将异常对象抛给JVM,JVM会强行终止程序并调用异常对象的printStackTrace()方法,异常的详细信息会被输出到标准错误流RuntimeException的默认处理方式
  • 异常对象的printStackTrace()方法有三种重载版本,无参版本默认输出到标准错误流,另外两种版本允许选择要输出的流
  • 捕获处理:try块放置需要被检测是否发生异常的代码,如果try块中抛出了异常对象,会被catch块捕获并进行针对性处理,此时认为异常已经得到了处理,程序可以继续运行。如果try块中的代码没有抛出异常,则不会执行catch块;如果try块中抛出异常,则会跳过try块中的剩余语句,转而执行catch块
  • 异常声明和catch块的异常参数都是多态的,注意不同异常参数的catch块的定义顺序必须是子类上,父类下
  • 可以在try/catch块后面添加finally块,无论try块中是否会发生异常,finally块中的代码都会被执行。finally的作用就是关闭释放除内存之外的资源,比如关闭数据库连接(增删查改时出现SQLException)
  • 如果try/catch块中存在return指令,程序流程也会先跳到finally再执行return
  • 如果try块和catch块中都添加相同的代码,那还要finally块干嘛?一是由于finally可以使代码更加简洁;二是因为如果try块中发生的某种RuntimeException并没有对应的catch块进行捕获处理,那么关闭释放资源的代码就会被跳过,必须使用finally块确保资源的关闭释放
  • 以下特殊情况finally不会被执行:finally块中发生了异常;在之前的代码中使用了System.exit(0)退出JVM;程序所在的线程死亡;关闭CPU
  • try/catch/finally的三种组合方式:try/catch/finally 需要捕获异常和关闭释放资源;try/catch 当没有资源需要被关闭释放时,不用定义finally块;try/finally  当异常无法直接被捕获处理,且资源需要关闭释放时,不用定义catch块,但是必须在方法声明异常
  • 注意:catch和finally不能没有try;try块和catch块中间不能有代码
  • 异常处理原则:方法内部如果抛出被检查异常,必须声明抛出或捕获处理(最好声明抛出,只进行捕获处理会存在隐患);如果调用声明异常的方法,也必须声明抛出或捕获处理,能捕获就捕获,不能捕获就接着往上抛(被检查异常对象要在被抛给JVM之前被捕获处理掉)
  • 异常的限制:子类在覆盖父类方法时,父类方法如果声明抛出了异常,那么子类方法只能声明抛出父类的异常或该异常的子类(接口同理);如果父类声明抛出多个异常,子类只能抛出父类异常的子集,不能抛出新异常;如果父类没有声明异常,子类绝对不能声明异常。所以一般来说,在设计接口时,方法最好加上throws Exception
  • 如果在方法内部使用捕获处理异常,就会发生异常隐藏。比如,用户调用数据库添加数据的方法时,在该方法内部发生了SQLException,却在方法内部被捕获处理了,那么用户会发现:并没有发生异常,但功能却没有实现!而直接抛出SQLException的话,用户又不知该如何处理它。这时候就要用到异常转换:在方法内部使用try/catch处理掉SQLException,并在catch块继续抛出异常(比如显而易见的NoIdException)
示例程序:
public class Test35 {public static void main(String[] args) {//运行时异常不需要声明抛出,因为没有必要/* * Error类及其子类描述的是系统内部错误以及资源耗尽错误,这种问题无法在程序中处理,必须直接修改程序 * int[] arr = new int[1024*1024*800*1021];  本语句编译通过,但运行时会发生Error:java.lang.OutOfMemoryError: Java heap space *///测试运行时异常int[] arr_1 = new int[]{1,2,3};int[] arr_2 = null;int index_true = 1;int index_out = 3;int index_negative = -1;//main()方法会把接收到的异常对象再抛给JVM,JVM拿到异常对象就会执行异常处理机制,将异常信息打印在控制台arrayExceptionThrow(arr_1, index_true);//如果参数选择index_out,会抛出有自定义异常信息的ArrayIndexOutOfBoundsExceptionarrayExceptionNotThrow(arr_1, index_true);//如果参数选择index_out,会抛出JVM创建的ArrayIndexOutOfBoundsExceptionarrayExceptionThrow(arr_1, index_true);//如果参数选择arr_2,会抛出有自定义异常信息的NullPointerExceptionarrayExceptionNotThrow(arr_1, index_true);//如果参数选择arr_2,会抛出JVM创建的NullPointerExceptionarrayExceptionThrow(arr_1, index_true);//如果参数选择index_negative,会抛出自定义的NegativeIndexExceptionarrayExceptionNotThrow(arr_1, index_negative);//如果参数选择index_negative,会抛出JVM创建的ArrayIndexOutOfBoundsException(Java没有数组下标为负异常)System.out.println("abc in main");//如果抛出异常main()方法弹栈,此语句不会执行}//当要抛出自定义异常或者想要通过有参构造函数自定义异常信息,可以显式地throw异常public static void arrayExceptionThrow(int[] arr,int index){//运行时异常不需要声明抛出,因为没有必要if(arr==null){throw new NullPointerException("无法操作null对象");//显式地throw异常可以介入异常对象的初始化过程(自定义异常信息)//!System.out.println("abc"); 如果抛出异常arrayExceptionThrow()方法弹栈,此语句不会执行(此语句永远不会被执行,所以编译不通过)}if(index>=arr.length){throw new ArrayIndexOutOfBoundsException("数组下标不能越界");//!System.out.println("abc");}if(index<0){throw new NegativeIndexException("数组下标不能为负数");//!System.out.println("abc");}System.out.println(arr[index]);//如果发生异常此语句不会执行System.out.println("abc in arrayExceptionThrow");//如果发生异常此语句不会执行}//除非要抛出自定义异常或者想要通过有参构造函数自定义异常信息,否则不用显式地throw异常public static void arrayExceptionNotThrow(int[] arr,int index){System.out.println(arr[index]);System.out.println("abc in arrayExceptionNotThrow");}}//自定义运行时异常(数组下标为负异常)class NegativeIndexException extends RuntimeException{/** *  */private static final long serialVersionUID = -1446907878404353058L;public NegativeIndexException(){}public NegativeIndexException(String message){super(message);}}

public class Test36 {public static void main(String[] args) {BufferedReader in = new BufferedReader(new InputStreamReader(System.in));System.out.print("请输入数组下标:");int index;//try块放置需要被检测是否发生异常的代码try {index = Integer.parseInt(in.readLine());//有可能产生NumberFormatException或IOExceptiongo(index);//有可能产生NegativeIndexExceptionSystem.out.println("index="+index);//如果发生异常,这条语句将不会执行,转而执行对应的catch块} catch (NumberFormatException | IOException e) {e.printStackTrace();System.out.println("捕捉到NumberFormatException或IOException");} catch (NegativeIndexException e){System.out.println("捕捉到NegativeIndexException");//JVM的默认异常处理机制就是调用异常对象的printStackTrace()方法e.printStackTrace();//com.grc.NegativeIndexException: 数组角标为负异常//at com.grc.Test36.main(Test36.java:23)System.out.println("getStackTrace:"+e.getStackTrace());//[Ljava.lang.StackTraceElement;@1f33b16aSystem.out.println("getMessage:"+e.getMessage());//getMessage:数组角标为负异常System.out.println("toString:"+e);//toString:com.grc.NegativeIndexException: 数组角标为负异常return;//如果本catch块捕捉到了异常,会先执行finally块,然后再返回来执行return//System.exit(0); 退出JVM 这种情况不会执行finally块} catch (Exception e){e.printStackTrace();System.out.println("捕捉到其他异常");}finally{System.out.println("finally");}}public static void go(int index) throws NegativeIndexException{//被检查异常如果没有进行捕获处理,就必须声明抛出if(index < 0){throw new NegativeIndexException("数组角标为负异常");}}}//自定义被检查异常(数组下标为负异常)class NegativeIndexException extends Exception{/** *  */private static final long serialVersionUID = -4618617674002460321L;public NegativeIndexException(){}public NegativeIndexException(String message){super(message);}}


0 0