【刨根问底】java异常

Java异常对于开发人员来说接触是非常频繁,处理好程序的异常也是一门艺术或者说是技术,发现身边很多人其实根本没有搞清楚Java异常。想想自己也当做巩固基础,今天就来把java异常模块总结一下。

本文主要内容:

  • 异常的定义
  • 异常的分类
  • java异常关键字
  • 异常常用代码模板
  • 自定义异常

定义

在计算机的世界里,在运行程序时,发生了意料之外的事件,阻止了程序的正常执行,这种情况被称之为异常。

异常的分类

JDK中有一套完整异常机制,所有异常都是Throwable的子类,分为Error(知名异常)和Exception(非致命异常)。

Error

Error是一种特殊的异常,它出现标识着系统发生了不可控制的错误,比如:常见的OutOfMemoryError(内存溢出),StackOverflowError栈溢出。

Exception

Exception又分为checked(受检查)和unchecked(非受检查)异常。

checked受检查的异常是需要在程序中显示处理的异常,否则编译失败。在开发过程中遇到这种异常的时候,一般是要么处理掉该异常,要么直接往上抛。常见的checked异常有:SQLExceptionClassNotFoundException等。

checked异常还可以分为以下两类异常:

  1. 无能为力、引起注意型:针对此类型异常,程序无法处理,如果字段超过表字段长度,数据库表字段不存在等造成的SQLException,这时候最好的方式就是打印出异常错误信息,供开发人员排查问题。
  2. 力所能及,坦然处理型:发生未授权异常UnAuthorizedException,程序可以跳转至权限申请页面。
  3. 可预测异常:就是开发人员可以根据自己的程序大致能猜到的异常。比如:数组越界,IndexOutOfBoundsExceptionNullPointerException等,面对此等异常,最好解决办法就是开发人员做好相应的边界值校验,或者捕获对应异常就行处理。
  4. 需要捕捉异常:比如在使用Dubbo框架进行RPC调用时,容易产生timeout异常DubboTmieoutException,此类异常也是最好显示低捕获,当捕获到相应的异常后可以做一些重试、熔断等操作。

异常关键字

try catch finally throws throw

以上关键字的解释

throws:使用在方法签名参数后 ,向调用此方法的地方抛一个异常。

throw:使用在方法里面,由于某某原因,需要往外跑一个异常,或者是针对某种异常进行转换成自定义异常,然后往外抛自定义异常。

try:不能单独使用,只能结合catch,finally一起使用,try代码块起到见识程序执行过程,如果一旦程序中发生异常则直接跳到catch模块中,如果没有异常发生则直接跳到finally模块中(前提是try+catch+finally)。

catch:结合try一起使用,可以加入finally模块,也可以是多个catch组合.如果try模块中发生异常并且catch(异常类型)刚刚是对应的异常或者范围更大的时候,就会进入catch模块。

finally:结合try使用,或者结合try+catch一起使用。finally模块表示必须执行的模块。不管程序是否发生异常,都会执行finally模块。注意:没有进入finally的情况有:程序执行没有进入try模块、进入try模块,但是程序中出现死循环了或者死锁状态、进入try模块,但是执行了System.exit();

常见代码模板

public class MyException {
    //模板1,方法签名参数后向外抛异常
    public void test() throws Exception {
    }
    //模板2,方法里向外抛异常
    public void test1() {
        throw new Exception();
    }
    //模板3,处理程序异常的三部曲try--catch--finally
    public void test2() {
        try {
            //doSomething
        } catch (Exception ex) {
            
        } finally {
         //最后在处理点事情
        }
    }
    //模板4,发现异常,捕获异常,try--catch
    public void test3() {
        try {
            //doSomething
        } catch (Exception ex) {
            
        }
    }
    //模板 4,发现异常,捕获异常,先捕获范围小的,再捕获范围大的
    public void test4() {
        try {
            //doSomething
        } catch (NullPointerException ex) {
            
        }catch (Exception ex){

        }
    }
    //模板 5,发现异常,捕获异常,先捕获范围小的,再捕获范围大的,最后在处理点事情
    public void test5() {
        try {
            //doSomething
        } catch (NullPointerException ex) {
            
        }catch (Exception ex){
            
        }finally {
          //最后在处理点事情
        }
    }
    //模板6,不管有没有捕获到异常,
    public void test6() {
        try {
            //doSomething
        }  finally {
        //最后在处理点事情
        }
    }
}

自定义异常

在开发过程中难免会想自定义异常,比如说针对某些业务的操作失败,我们如果用其他异常类可能会有歧义,所以使用自定义的异常来和其他异常的区分,也有的时候是针对系统级的,Pay支付模块的异常可以定义成PayException。但是怎么定义呢?Throwable分为Error和Exception,所以如果自定义的异常继承于Error的话行么?因为Error是不可控的,所以通常不会继承与它。通常都是自定义异常继承于Exception或者RuntimeException。如果希望写一个检查性异常类,则需要继承 Exception 类。如果你想写一个运行时异常类,那么需要继承 RuntimeException类。

//自定义异常,继承于Exception
public class CustomException extends Exception {
    public CustomException(String message) {
        super(message);
    }
}
public class CustomExceptionDemo {
    public static void main(String[] args) {
        try {
            test(22);
        } catch (CustomException e) {
     System.out.println("test方法报异常," +         e.getLocalizedMessage());
        }
    }

 private static void test(int age) throws CustomException {
        if (age == 22) {
            throw new CustomException("这是我的自定义异常");
        } else {
            System.out.println("不是自定义异常");
        }

   }
}

运行结果:

test方法报异常,这是我的自定义异常

在工作中使用比较多的自定义方式,把上面的自定义进行改造:

//自定义
public class CustomException extends Exception {
     //错误码
     private String errorCode;
     //错误信息
     private String errorMsg;

    public CustomException(String errorCode, String errorMsg) {
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }
   //省略调 get set toString
}
public class CustomExceptionDemo {
    public static void main(String[] args) {
        try {
            test(2);
        } catch (CustomException e) {
            System.out.println("test方法报异常,异常信息:" + e);
        }
    }
    private static void test(int age) throws CustomException {
        if (age == 2) {
            throw new CustomException("300001", "这是我的自定义异常");
        } else {
            System.out.println("不是自定义异常");
        }
    }
}

运行输出结果:

test方法报异常,异常信息:CustomException{errorCode='300001', errorMsg='这是我的自定义异常'}

注意:异常堆栈信息,不是有多少就打多少,这方面也要悠着点,过多地打印错误日志也是会拖累系统的,能表达清楚就OK了。

异常就说到这里,期待下一期的异常面试题。

原文发布于微信公众号 - Java后端技术栈(t-j20120622)

原文发表时间:2019-08-15

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券