异常,自定义异常,声明与捕获,finally代码块

    科技2025-12-30  9

    Java学习笔记之--------异常

    异常的产生异常的种类声明问题(throws和throw)异常的原则异常的处理自定义异常finally代码块处理异常代码块组合方式覆盖中异常的使用

    异常的产生

    异常是Java程序在运行时期发生的不正常情况(问题)。 Java按照面向对象的思想对不正常的情况进行描述和对象的封装。

    异常的种类

    Error:在Java底层发生,告诉JVM,JVM告诉执行者,不做针对性处理,直接修改代码。Exception:JVM发生,并告诉给使用者,可以进行针对性的处理。

    代码如下:

    Exception异常

    public class ThrowTest{ public static void main(String args[]){ int[] arr = new int[1]; //ArrayIndexOutOfBoundsException System.out.println(arr[1]); } }

    Error异常

    public class ThrowTest{ public static void main(String args[]){ int[] arr = new int[1024*1024*1024]; //OutOfMemoryError System.out.println(arr[1]); } }

    当输出语句发生错误时,JVM会将这个已知的问题,封装成对象,将问题抛给调用者main函数,main函数没有针对性的处理方式,就继续往外抛给调用者JVM,JVM会使用默认的处理方式,将问题的名称+信息+位置在控制台输出,让调用者看到并结束程序。

    声明问题(throws和throw)

    在编写功能时,编写者猜测或者知道该功能可能发生问题,且问题的根源很可能来自调用者传递的参数,会导致功能无法运行,这时发生的问题就应该让调用者知道,并最好让调用者有预先的处理方式。这就是声明的目的。所以在定义功能时,需要在功能上对有可能发生的问题进行声明声明问题需要使用关键字throws 异常类或throw 异常类

    throws和throw的区别 位置上:

    throws:用在函数上,后面跟异常类,可跟多个。throw:用在函数内,后面跟异常对象,只能一个。

    功能上:

    throws用来声明异常,让调用者知道该功能有可能出现的问题,并由调用者可以给出预先的处理方式throw抛出具体问题对象,执行到throw时功能就已经结束了,跳转到调用者,并将具体的问题对象也抛给调用者。也就是说,throw语句独立存在时,不要在下面定义其他语句,因为执行不到。

    异常的原则

    异常体系的最大特点就是体系中的类以及类产生的对象,都具备可抛性,可抛性就是指可以被throws和throw所操作。

    原则:

    功能内部有throw抛出,功能上一定要throws声明。内部抛什么,功能上就声明什么。声明的目的是为了让调用者处理,若调用者不处理,则编译失败。

    特殊情况:

    当函数内通过throw抛出了RuntimeException及其子类的异常对象时,函数上可以不用throws声明。不声明的目的是为了不让调用者处理,让程序停止,对代码进行修改。Exception分为两类:编译时异常以及运行时异常。

    异常的处理

    1.遇到问题不进行具体的处理,而是继续抛出给使用者。其实就是在函数上通过throws关键字声明异常,告诉调用者处理。

    代码示例

    //异常处理方式1----抛出 class Test{ int div(int a,int b)throws Exception{//抛出异常 return a/b; } } public class ThrowTest1{ public static void main(String args[])throws Exception{//抛出异常 Test t = new Test(); int num = t.div(4,0);//ArithmeticException System.out.println(num); } }

    2.针对性的处理方式:捕获

    /* try{ //有可能发生异常的代码 } catch(异常类 变量){ //捕获,处理异常的代码 } finally{ //一定会被执行的代码 } */

    代码示例

    class Demo{ //创建方法,得到两数相除的值。有参数,有返回值 int method(int x,int y) throws Exception{ return x/y; } } public class ThrowTest2{ public static void main(String args[]){ Demo d = new Demo(); //捕获 try{ int num = d.method(4,0); System.out.print("num="+num); }catch(Exception e){ System.out.println("ERROE!"); } System.out.print("异常处理,程序继续运行"); } }

    可以看到,通过对异常进行捕获和处理,程序可以继续向下运行 几种打印异常的常用方法

    getMessage():打印异常信息 toString():打印异常信息和异常位置 printStackTrace:打印名字,异常信息和异常位置,JVM默认收到异常时调用的就是该方法。

    class Demo{ //创建方法,得到两数相除的值。有参数,有返回值 int method(int x,int y) throws Exception{ return x/y; } } public class ThrowTest2{ public static void main(String args[]){ Demo d = new Demo(); //捕获 try{ int num = d.method(4,0); System.out.print("num="+num); }catch(Exception e){ //System.out.println("ERROE!"); System.out.println("第一种"); System.out.println(e.getMessage());//异常信息 System.out.println("第二种"); System.out.println(e.toString());//异常位置+异常信息 System.out.println("第三种"); e.printStackTrace();//名字+异常位置+异常信息,JVM默认在收到异常时调用此方法 } //System.out.print("异常处理,程序继续运行"); } }

    一枚小栗子~

    package com.rqy.hello; //给定一个数组,返回指定的索引值 class Demo{ //创建一个方法,有返回值,参数为数组和索引 public static int method(int[] arr,int num){ //对调用者传入的值做判断 if(arr == null) throw new NullPointerException("数组不存在"); if(num < 0 || num >arr.length){ throw new ArrayIndexOutOfBoundsException(arr[num]+"数组索引不存在"); } int x = arr[num]; return x; } } public class ThrowDemo{ public static void main(String args[]){ Demo d = new Demo(); int[] arr = {1,2,3,4,5,6}; arr = null; int x = d.method(arr,2); System.out.print(x); } }

    自定义异常

    在自定义的程序中,如果存在问题,也可以像Java中的异常一样,对问题进行描述 步骤如下

    /*自定义异常 */ //定义一个功能实现除法运算,但除数不可以为负数 //创建自定义的异常类,并继承父类异常,RuntimeException可不抛 class FushuException extends RuntimeException{ //构造函数,super指向父类 FushuException(){ super(); } FushuException(String message){ super(message); } } class Test{ //定义一个方法,有返回值,有参数 int method(int x,int y){ if(x==0 || y== 0) { throw new ArithmeticException("除数或被除数为0"); } if(x<0) { throw new FushuException("负数不可以作为除数"); } return x/y; } } public class ThrowDemo1 { public static void main(String args[]){ Test d = new Test(); //也可以进行捕获 try { int x = d.method(-2, 4); System.out.print(x); }catch(Exception e) { //System.out.print(e.toString()); e.printStackTrace(); } System.out.println("OVER!"); } }

    finally代码块

    作用:无论是否有异常发生,都对资源进行释放,资源释放动作就定义在finally代码块中

    /* //连接数据库 try{ //数据操作,throw new SQLException } catch(SQLException e){ //解决数据库异常 } finally{ //关闭数据库 } */

    处理异常代码块组合方式

    1.没有资源释放,仅仅处理异常

    /* try{ //有可能发生异常的代码 } catch(异常类 变量){ //捕获,处理异常的代码 } */

    2.一个try多个catch,一般对应的是被调用的函数,抛出多个异常的情况,分别处理。

    注意:在多catch时,若catch中的异常存在子父类异常(一般不常见),父类的catch一定要放在子类下面,否则会编译失败

    /* try{ //有可能发生异常的代码 } catch(异常类 变量){ //捕获,处理异常的代码 } catch(异常类 变量){ //捕获,处理异常的代码 } catch(异常类 变量){ //捕获,处理异常的代码 } */

    3.不一定要处理异常,但有资源需要释放。(掌握)

    /* try{ //有可能发生异常的代码 } finally{ //一定会被执行的代码 } */

    覆盖中异常的使用

    原则:子类的异常必须要在父类的异常处理控制中

    覆盖时,子类方法覆盖父类方法只能抛出父类方法异常或该异常的子类如果父类方法抛出多个异常,子类只能抛出父类异常的子集

    代码示例

    //AException,BException继承Exception //AAException继承AException class AException extends Exception{ } class BException extends Exception{ } class AAException extends AException{ } class Father { void show() throws AException{ System.out.println("father show"); } } //子类可以抛出AException或AAException,都可以编译成功 class Son extends Father{ void show()throws AAException { System.out.println("son show"); } } class Tool{ void method(Father f) { try{ f.show(); } catch(AException e){ } } } public class ThrowOverload { public static void main(String args[]) { Tool t = new Tool(); t.method(new Father()); } } 注意:有一种情况只能try不能throws—被覆盖的方法没有抛出异常,那么子类在覆盖时,子类方法中发生了异常,只能try,无法throws声明

    代码示例

    如果在catch中无法处理捕获的异常,可以将编译时异常转换成运行时异常抛给调用者,对代码进行修改(开发小技巧)

    该文章为学习笔记,如有不足之处还请指正

    Processed: 0.029, SQL: 9