学习笔记之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
- 学习笔记之JavaSE(20)--面向对象编程11
- 学习笔记之JavaSE(11)--面向对象编程2
- 学习笔记之JavaSE(10)--面向对象编程1
- 学习笔记之JavaSE(12)--面向对象编程3
- 学习笔记之JavaSE(13)--面向对象编程4
- 学习笔记之JavaSE(14)--面向对象编程5
- 学习笔记之JavaSE(15)--面向对象编程6
- 学习笔记之JavaSE(16)--面向对象编程7
- 学习笔记之JavaSE(17)--面向对象编程8
- 学习笔记之JavaSE(18)--面向对象编程9
- 学习笔记之JavaSE(19)--面向对象编程10
- JavaSE学习笔记之-----面向对象
- javaSE学习笔记之面向对象程序设计(一)
- javaSE学习笔记之面向对象程序设计(二)
- 学习笔记之面向对象编程11(二维数组)
- 学习笔记之面向对象编程25(网络编程)
- <JavaSE学习笔记>面向对象(2):Java内存机制
- JavaSE基础学习笔记-面向对象01
- VS2015搭建测试webApi测试环境
- Linux如何手动挂载/卸载u盘
- TestNG系列-第五章 测试方法、测试类和测试分组(续7)-注解变形器和方法拦截器
- Vijos 1790 拓扑编号(拓扑排序+堆优化)
- 升级硬件喽 24GB内存
- 学习笔记之JavaSE(20)--面向对象编程11
- ActiveMQ安装优化
- 深入编译链接
- yii2框架中使用sphinx使用搜索引擎 多条件选择搜索
- android自定义滑动开关
- JS学习42:使用spm@3构建seajs项目
- poj 1088 滑雪 动态规划
- php概率计算
- day01-Linux安装及配置