Java程序基础——异常

目录

目录

1、异常

2、异常的继承体系

3、异常与错误的区别

4、异常对象的产生原因及处理方式

5、抛出异常thorw

6、声明异常throws

7、 捕获异常 try ..catch...finally

8、异常处理的组合方式

9、finally代码块

10、调用抛出异常方法

11、运行期异常

12、方法重写时异常的处理

13、异常中常用方法

14、自定义异常类的定义

15、自定义异常的练习


1、异常

什么是异常?

  • Java代码在运行时期发生的问题就是异常
  • 异常类:在Java中,把异常信息封装成了一个类,当出现了问题时,就会胡藏剑异常对象,并抛出异常相关的信息(如异常出现的位置、原因等)
  • 比如:ArrayIndedOutOfBoundsException

2、异常的继承体系

  • 在Java中,使用Exception类来描述异常。通过查询API,发现Exception其实时Throwable的子类。Throwable是Java语言中所有错误或异常的父类。
  • RuntimeException及其子类、只能在java程序运行中出现
  • Error是Throwable的子类,它与Exception平级,它用来表示Java程序中可能会产生的严重错误。解决办法只有一个,就是修改代码避免Error的产生。
Throwable :所有错误与异常的超类
   |--Error  错误
   |--Exception  编译期异常,进行编译java程序时出现的问题
        |--RuntimeException  运行期异常,java程序运行过程中出现的问题

3、异常与错误的区别

  •  异常:表示程序在编译、运行期间发生的某种异常(XXXException),我们可以对异常进行具体的处理。若不处理异常,程序将结束运行。
    public static void main(String[] args) {
        int[] arr = new int[3];
        System.out.println(arr[3]); 
        // 该句运行时,发生了ArrayIndexOutOfBoundsException,
        // 由于没有处理异常,导致程序无法运行,程序结束
    }
  • 错误:指程序在运行期间发生了某种错误(XxxError),Error错误通常没有具体的处理方式,程序将会结束运行。Error错误的发生往往都是系统级别的问题,我们无法针对处理,只能修改代码。
    public static void main(String[] args) {
        int[] arr = new int[100 * 1024 * 1024];
        // 该句运行时会发生内存溢出错误OutOfMemoryError,由于开辟了过大的数组空间
        //导致JVM在分配数组空间时超过了JVM内存空间,直接发生错误
    }

4、异常对象的产生原因及处理方式

class ArrayTools{
  public static int getElement (int[] arr,int index) {
        int element = arr[index];
        return element;
    }
    
public class ExceptionDemo{
  public static void main(String[] args) {
        int[] arr = {1,2,3};
        int element = ArrayTools.getElement(arr,4);
        System.out.println("element="+element);
    }
}

原因分析:

  • 由于没有找到索引【4】,导致运行时发生了异常,这个异常JVM认识:ArrayIndexOutOfBoundsException。这个异常Java本省有描述:异常的名称、异常的内容、异常产生的位置。                                                                                                                       Java将这些信息直接封装到异常对象中:new ArrayIndexOutOfBoundsException(4);
  • throw new ArrayIndexOutOfBoundsException(4) 产生异常对象,JVM将产生的异常抛给调用者main()方法。
  • main()方法接收到了数组索引越界异常对象。由于main()方法并没有进入处理异常,main()方法会继续把异常抛给调用者JVM,当JVM接收到异常后,将异常的名称、异常的内容、异常产生的位置都显示在控制台上,同时让程序立刻终止。

异常的处理方式:

  • JVM的默认处理方式                                                                                                                     将异常对象的名称、原因、位置等信息输出到控制台,同时结束程序。一旦有异常发生,其后面的代码不再执行
  • 解决程序中异常的手动方式
  1. 编写处理代码:try...catch...finally
  2. 抛出throws.

5、抛出异常thorw

在java中,提供了一个throw关键字,用来抛出一个指定的异常对象。

  • 什么时候使用throw关键字?                                                                                                      ——当调用方法使用接受到的参数时,首先需要对参数数据进行合法的判断,数据若不合法,就应该告诉调用者,传递合法的数据进来。这时需要使用抛出异常的方式来告诉调用者。
  • 使用throw关键字具体操作
  1. 创建一个异常对象,封装一些提示信息(信息可以自己编写)
  2. 通过关键字throw将这个异常对象告知给调用者。

throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。

使用格式:

throw new 异常类名(参数);                     

throw new NullPointerException("要访问的数组不存在");
throw new ArrayIndexOutOfBoundsException("该索引在数组中不存在,已超出范围");
public class ArrayTools {
    public static int getElement(int arr[],int index){
        if(arr==null){
            throw new NullPointerException("要访问的数组不存在");
        }
        if(index < 0 || index >= arr.length){
            throw new ArrayIndexOutOfBoundsException("该索引"+index+"在数组中不不存在");
        }
        int element = arr[index];
        return element;
    }
}

public class ExceptionDemo {
    public static void main(String[] args) {
        int[] arr = {1,2,3};
        int element = ArrayTools.getElement(arr,4);
        System.out.println("element="+element);
    }
}

6、声明异常throws

声明:将问题表示出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获异常,那么必须通过throws进行声明,让调用者去处理

声明格式:

修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2..{}

注意事项:

throws用于进行异常类的声明,若该方法可能有多种异常情况产生,那么在throws后面可以写多个异常类,用逗号隔开。

    public void show(int x) throws Exception {
        if(x>0){
            throw new Exception() ;
        }else {
            System.out.println("x="+x);
        }
    }

7、 捕获异常 try ..catch...finally

捕获:java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理

捕获异常格式:

try{
  // 需要被检测的语句
}catch (异常类 变量){
  // 异常的处理语句
}finally {
  // 一定会被执行的语句
}
  • try:该代码块中编写可能产生异常的代码
  • catch:用来进行某种异常的捕获,实现对捕获到的异常进行处理
  • finally:有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句不能执行,而finally就是解决这个问题的。在finally代码块中的代码都是一定会被执行的!
  • try...catch... 处理掉异常后,程序可以继续执行
    public static void main(String[] args) {
        int[] arr = new int[3];
        try {
            System.out.println(arr[4]);
        }catch (ArrayIndexOutOfBoundsException e){
            System.out.println("异常发生了..");
        }finally {
            arr = null;  // 把arr数组指向null,通过垃圾回收器,进行内存垃圾的清除
        }
        System.out.println(arr);
        System.out.println("程序结束运行!");
    }
}

8、异常处理的组合方式

  • try..catch..finally:检测异常,并传递给catch处理,最后在fianlly中进行资源释放。
  • try..catch 组合:对代码进行异常检测,并对检测到的异常传递给catch处理。
  • try..finally 组合:对代码进行异常检测,由于没有catch,一般会被默认的JVM输出。异常没有捕获处理,但是功能所开启的资源需要进行关闭,所以finally的存在是关闭资源。
  • 一个try多个catch组合:对代码快进行异常检测,并对检测到的异常传递给catch处理。对每种异常信息进行不同的捕获处理。
void show() {
  try{ 
     throw new Exception();
  }catch(XxxException e){
     // 处理方式
  }catch(YyyException e){
     // 处理方式
  }catch(ZzzException e){
     // 处理方式
  }   
}

注意事项:
这种异常处理方式,要求多个catch中的异常不能相同。

多个catch处理的细节:

多个catch小括号中,写的是异常类的类名,它是由顺序关系的

  • 平级异常——抛出的异常类之间,没有继承关系,没有顺序
NullPointerException extends RuntimeException
NoSuchException extends RuntimeException
ArrayIndexOutOfBoundsException extends RuntimeException
  • 上下级关系的异常 ——越高级的父类,写在越下面
NullPointerException extends RuntimeException extends Exception


try {
  throw new Exception();
}catch(NullPointerException e){
 
}catch(RuntimeException e){

}catch(Exception e){
}

9、finally代码块

特点:被finally控制的语句体一定会执行

作用:无论程序是否有异常出现,程序必须执行释放资源。如:IO流操作、数据库操作。


10、调用抛出异常方法

有 try...catch 和 throws 两种

在实际开发中使用哪种异常处理方式?

  • 能自己处理的尽量自己处理。(建议使用 try...catch)

11、运行期异常

1、概述:

  • RuntimeException和它的所有子类异常,都属于运行期异常                                             如
  • ArrayIndexOutOfBoundsException,NullPointerException 等都属于运行时期异常

2、特点:

  • 方法中抛出运行时期异常,方法定义中无需throws声明,调用者也无需处理此异常。
  • 运行时期异常一旦发生,需要程序人员修改源代码。
  • 设计原因:运行异常,不能发生,但如果发生了,程序人员要停止程序,修改源代码。运行异常一旦发生,后面的代码没有执行的意义。

12、方法重写时异常的处理

  • 子类覆盖父类方法时,如果父类的方法声明异常,子类只能声明父类异常或该异常的的子类,获取不声明。
class Fu{
   public void method() throws RuntimeException{
    }
}

class Zi extends Fu{
    public void method() throws RuntimeException{}   // 抛出父类一样的异常
    //public void method() throws NullPointerException{}  // 抛出父类异常
    //public void method(){}
}
  • 当父类方法声明多个异常时,子类覆盖时只能声明多个异常的子集
class Fu{
   public void method() throws NullPointerException,ClassCastException{
    }
}

class Zi extends Fu{
    public void method() throws NullPointerException,ClassCastException{}   // 抛出父类一样的异常
    //public void method() throws NullPointerException {}  // 抛出父类异常中的一部分
    //public void method() throws ClassCastException {}  // 抛出父类异常中的一部分
}
  • 当覆盖的方法没有异常声明时,子类覆盖时无法声明异常
class Fu{
   public void method(){}
}

class Zi extends Fu{
    public void method() throws Exception{}   // 错误的方式
}
  •  父类或接口中,没有声明异常,但子类覆盖方法时发生了异常,怎么办?

        无法进行throws声明,只能catch捕获。万一问题处理不了,catch中继续throw抛出,但是只能将异常转换为RuntimeException子类抛出。

interface Inter{
   public abstract void method();
}
public class Zi implements Inter{
    @Override
    public void method() {
        int[] arr = null;
        if (arr == null){
            try {
                throw new Exception("数组不存在!");
            }catch (Exception e){
                System.out.println("父方法中没有声明异常,子类中不能抛出Exception异常");
                throw new RuntimeException(e);
            }
        }
    }
}

13、异常中常用方法

  • getMessage():返回该异常的详细信息字符串,即异常提示信息
  • printStackTrace(): 在控制台输出该异常的名称、详细信息字符串、异常出现的代码位置。
  • toString():返回该异常的名称与详细信息字符串
public class ExceptionDemo {
    public static void main(String[] args) {
       try{
           Demo demo = null;
           if(demo == null){
               throw new NullPointerException("出现空指针异常");
           }
       }catch (NullPointerException e){
           String message = e.getMessage();
           System.out.println("getMessage():"+message);
           String s = e.toString();
           System.out.println("toString():"+s);
           System.out.println("printStackTrace():");
           e.printStackTrace();

       }
    }
}

14、自定义异常类的定义

class 异常名 extends Exception {   // 或者继承RuntimeException
  public MyException(){
      super();
  }   

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

 自定义异常继承RuntimeException:

public class MyRuntimeException extends RuntimeException{
    public MyRuntimeException(){
        super();
    }
    public MyRuntimeException(String message){
        super(message);
    }
}

15、自定义异常的练习

定义Person类,包含name和age两个成员属性

在Person类的有参构造方法中,进行年龄范围的判读,若年龄为负数或者大于100岁,则抛出NoAgeException异常,异常提示信息:“年龄数值非法”

要求:在测试类中,调用有参构造方法,完成Person对象创建,并进行异常处理

(1)自定义异常类NoAgeException 

public class NoAgeException extends Exception{

    public NoAgeException(){
        super();
    }
    public NoAgeException(String message){
        super(message);
    }
}

(2)自定义类Person

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) throws NoAgeException {
        if(age<0 || age>200){
            throw new NoAgeException(age + "年龄数值非法");
        }
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }


}

(3)测试类

public class NoAgeExceptionDemo {
    public static void main(String[] args) {
        try {
            Person person = new Person("小镭", 999);
            System.out.println(person.getAge());
        } catch (NoAgeException e) {
            e.printStackTrace();
        }
    }
}

构造方法抛出的这个NoAgeException到底是继承Exception,还是继承RuntimeException?

  • 继承Exception,必须要throws声明,告知调用者进行捕获,一旦问题处理了,调用者程序会继续执行
  • 继承RuntimeException,不需要throws声明,这时调用是不需要写捕获异常代码,因为调用者根本不知道有问题。一旦发生NoAgeException,调用者的程序会停掉,并由JVM将信息显示到屏幕,让调用者看到问题,修正代码
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值