Exception异常

Java具有健壮性:

  1. GC垃圾回收
  2. 异常处理机制

throwable是所有异常和错误的父类

错误error:

是一个类

public class Error extends Throwable

错误是无法处理的,只能终止,一般这些错误是与虚拟机内存/内核有关。

异常Exception:

所有异常的父类,所有的异常是可以处理的。

常见异常:

ArithmeticException

NullPointerException

ArrayIndexOutOfBoundsException

ClassCastException
  1. 运行时的异常:(Runtime Exception)

编译的时候没有出现问题,用户提交数据运行时会引发的异常。

  1. 编译时的异常(checked exception) 大类Exception也是编译时异常

在编译的时候就出现问题的异常。

除了runtime exception其他都是checked exception

代码里面出现异常如果不处理,当前main线程终止

异常处理:

tips:不允许在代码里面对任意一个运行时异常处理,提前预判

1.捕获

try catch finally【快捷键Ctrl+Alt+T】,真正处理异常的方法

语法:

try{
    //可能出现异常的代码块
}catch(异常类型 对象名称){
    //处理异常对象方法
}finally{
    //不管程序里面是否出现异常,finally代码块的功能肯定会被执行
    //资源释放
}

ctrl+alt+t快捷键

try{
    //可能会出现的异常代码块
}catch(异常种类 异常对象){
    //异常处理方法
}finally{
    //资源回收,一定会被执行
}

jdk1.8之后推出自动回收:

try(需要回收的资源){
    
}catch(异常种类 异常对象){
    //异常处理方法
}

catch里面常用的异常处理方法:

catch(异常类 异常对象){
    /*
    1.system.out.println;
    2.异常对象.printStackTrace();这里面打印的顺序是随机的,底层是system.err,不是system.out
    3.system.out.print(异常对象.getMessage());
    4.return 数据;
    5.异常+日志:将异常信息存储到不同级别的日志文件中 info warn error debug
    6. 异常信息的传递throw(将低级别的异常对象传递到高级别的异常对象中 casued by:)
     */
}
int[] array=new int[3];
System.out.println(array[2]);
try{
System.out.println(array[3]);}
catch (ArrayIndexOutOfBoundsException a){
    System.out.println("数组越界");
}
finally{
    
}

try里面异常之后的代码不会被执行,里面有多个异常时候我们选用多个catch,可以用||简化很多的异常,但是要注意异常的等级关系,如果写了子类异常,在||后面不可以加父类,可以写多个catch,虽然有多个catch,但只执行一个catch,要注意前后catch的异常范围,如果前面异常范围过大,后面的异常不会处理,因此放在前面的catch异常范围会小于后面的范围,要将异常的代码try住,正常代码不用try

try {
    if(str.equals(s)) System.out.println("true");
    else System.out.println("false");
    System.out.println(3/0);
} catch (NullPointerException e) {
    e.printStackTrace();
}
catch (ArithmeticException a){
    a.printStackTrace();
}
finally {input.close();
}

一个异常可能会导致多个异常,此时需要看casued by。

对于编译时异常:也是一样的try...catch

public static final String PATTAN="yyyy-mm-dd";
//这里格式需要跟下面字符串里面time格式一致或者少于string的
public static void main(String[] args) {
    //将string转date,格式化字符串的时间
    String renttime="2022-10-24";
    String backtime="2023-10-18";
    System.out.println(gettime(renttime, backtime)/1000/3600/24);
    //转化成天数输出
}
private static long gettime(String renttime,String backtime){
    SimpleDateFormat simpleDateFormat=new SimpleDateFormat(PATTAN);
    Date backdate=null;
    Date rentdate=null;//先赋值,扩大变量作用域
    try{
        rentdate= simpleDateFormat.parse(renttime);
        backdate= simpleDateFormat.parse(backtime);
        //出现编译时异常parseException,,需要try...catch,
    }catch(ParseException e){
        e.printStackTrace();
    }
    //将date转换成数值类型
    long rent=rentdate.getTime();//gettime只能得到当前日期毫秒数
    long back=backdate.getTime();
    return Math.abs((rent-back));
}

2.抛出

throws

把异常抛出给调用者,表示没有能力处理(消极处理),不处理运行时异常

语法:

在方法的签名后面,使用throws抛出具体异常类
public static void fun() throws ClassNotFoundException {
    Class.forName("abd");
}

但是没有做处理,而且该方法在main中调用的话仍然需要try...catch,做出异常提示

tips:throw和throws不一样的

throws是处理异常的一种方式,在方法后面抛出多个异常类,自己没有能力处理异常。

throw:

控制代码执行流程,catch里面经常用,遇见throw关键字,程序结束,语法:抛出一个异常对象

private static double divide(int num1,int num2){
    //提前预判数据,除数不能为零
    if(num2==0){
        //System.exit(-1);这个不会展示异常日志,throw可以展示异常日志
        // 只在Java程序中意义无法停止其他web或者其他项目
        // 因此此时可以用throw控制流程
        throw new ArithmeticException();
        //或者返回具体信息throw new ArithmeticException("除数不能为零");
    }
    return num1/num2;
}

由此可以改进用户登录的方法:

private boolean login(String name,String pass){
    if(name==null||pass==null){
        throw new NullPointerException("用户名或密码不能为空");
    }
    //与下面方法是一样的,只是下面是分开确认
    Objects.requireNonNull(name,"用户名不能为空");
    Objects.requireNonNull(pass,"密码不能为空");
    
    return true;
}

前面我们说过了可以在catch里面加上throw来实现异常信息的传递,此时throw是由低级异常传到高级异常,所以在catch里面的throw需要抛出catch异常类型的父类异常,

try{
    
}catch(ParseException e){
        throw new Exception("错误信息", e);
}

但是此时子类异常创建父类异常对象,会发生错误,也就是处理类型转换异常一样的,再次try...catch

try{
    
}catch(ParseException e){
    try {
        throw new Exception("错误信息", e);
    } catch (Exception e1) {
        e1.printStackTrace();
    }
}

自定义异常类

自己定义的异常原因和反馈,一般都是与throw结合使用,为了满足需求而自定义的一个异常,一般类里面只有重载方法:

//编写一个银行取钱的项目:
//存款为1000,取钱的时候想取2000
public static void main(String[] args) {
        double money=1000;
        double getmoney=2000;
        get$(money,getmoney);
    }
private static void get$(double money,double getmoney){
        if(money<getmoney){
           // 取不出来,抛出异常,该方法结束
        }
    money-=getmoney;
    }
/*很显然取不出来,这时候可以抛出自定义的异常来展示错误信息“账户余额不足”,并且继承我们的异常父类(记得重写方法),继承编译时异常父类exception,或者继承运行时异常父类runtime exception*/
private static void get$(double money,double getmoney){
        if(money<getmoney){
            throw new BalanceException("账户余额不足");
        }
    }

上面是自定义一个继承RuntimeException的异常类,但是如果我换成继承Exception父类的话呢?由于Exception类是一个编译时异常类,对于编译时异常,我们一般在方法签名后面加上throws某某类异常,并且在调用该方法时仍需要try...catch

public static void main(String[] args) {
    double money=1000;
    double getmoney=2000;
    try {
        get$(money,getmoney);
    } catch (BalanceException e) {
        e.printStackTrace();
    }
}
private static void get$(double money,double getmoney)throws BalanceException{
    if(money<getmoney){
        throw new BalanceException("账户余额不足");
    }
    money-=getmoney;
}

tips:某些异常对应某些code,例如:账户余额不足对应-->1001,所以在自定义异常类中会有属性code,用于给程序员反馈异常信息。

posted @ 2022-10-24 17:33  Liku007  阅读(82)  评论(0编辑  收藏  举报