java 异常(Exception)概述及基本处理

简介: java 异常(Exception)概述及基本处理

异常的介绍

异常的概念

异常 :指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。

在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的方式是中断处理(停止java虚拟机JVM)。

异常的体系

java.lang.Throwable类:是异常和错误的最顶层的父类

  • 异常:在程序出现了异常,是可以解决的,程序解决了异常可以继续执行

    -- java.lang.Exception extends Throwable:编译期异常:写代码的时候(编译)出现的异常

    -- java.lang.RuntimeException extends Exception:运行期(时)异常:程序运行的时候出现的异常

  • 错误:在程序中出了错误,是不能解决的,必须的修改代码,把错误去掉,才能让程序执行

    -- java.lang.Error extends Throwable:错误

异常的产生过程解析

1593401387605-1619579371091.png

throw 创建异常抛出

throw关键字(重点)

作用:可以[在方法中]抛出指定的异常对象

格式:

修饰符 返回值类型 方法名(参数列表){
    throw new Exception("异常信息");
    throw new RuntimeException("异常信息");
    throw new XxxxException("异常信息");
 }

注意:

1,throw关键字必须写在方法中使用

2,throw关键字后边创建的对象,必须是Exception或者RuntimeException或者他们的子类对象

3,抛出了编译期异常,就必须处理这个编译异常

​ 抛出了运行期异常,可以不用处理这个异常,最终交给JVM处理(中断)

异常的处理

throws 抛给调用者处理

异常处理的第一种方式,建议练习的时候使用,工作使用不要使用

作用:

​ 方法的内部抛出了异常对象,是一个编译期异常,就必须的处理这个编译期异常对象。可以使用throws关键字把异常对象抛出给方法的调用者来处理,最终可以抛出给JVM处理:JVM会以红色的字体把异常对象相关的信息打印在控制台,中断当前正在执行的程序

弊端:程序产生异常,抛出异常对象给JVM,JVM终止程序,产生异常之后的代码就执行不到了

格式:

修饰符 返回值类型 方法名(参数列表) throws xxxException,...,yyyException {
    throw new xxxException("异常信息");
}

注意:

1,throws关键字必须写在方法声明处

2,一般在方法内部抛出了什么异常对象,就使用throws关键字在方法上声明抛出什么异常对象给方法的调用者处理

​ a.在方法内部抛出了多个异常对象,就需要使用throws关键字在方法上声明多个异常对象

​ b.在方法内部抛出了多个异常对象,有子父类关系,在方法上声明父类异常即可

3,调用一个使用throws关键字声明抛出异常的方法,就必须的处理这个异常对象

​ a.可以使用throws关键字继续声明抛出这个异常对象,最终抛出给JVM处理

​ b.可以使用try...catch自己手动处理异常

try...catch 手动处理

异常处理的第二种方式,自己手动处理异常,建议工作中使用

作用:

​ 方法的内部抛出了异常对象,是一个编译期异常,我们就必须的处理这个编译期异常对象。调用的方法上声明抛出了异常对象,我们需要处理这个异常对象。可以使用try catch 关键字捕获处理异常,自己定义异常的处理方式

好处:处理了异常之后,程序后续如果有代码,可以继续执行

格式:

        try{
            可能产生异常的代码
        }catch (定义一个异常相关的变量){ 变量的作用就是用来接收程序产生的异常对象
            异常的处理逻辑(想怎么写就怎么写)
        }
        ...
        catch (定义一个异常相关的变量){ 变量的作用就是用来接收程序产生的异常对象
            异常的处理逻辑(想怎么写就怎么写)
        }

注意:

1.try中可能产生什么异常对象,catch中就要定义什么异常变量来接收这个异常对象

2.如果try中产生了异常对象,就会执行catch中异常的处理逻辑,执行完catch中的代码,继续执行try catch后边的代码

3.如果try中没有产生异常对象,就不会执行catch中异常的处理逻辑,执行完try中的代码,继续执行try catch后边的代码

4.如果try中产生了多个异常对象,就需要定义多个catch来捕获处理这些异常对象

全局统一异常处理

通过 @ControllerAdvice 和 @ExceptionHandler 注解定义全局异常处理

使用方式:

  • @ControllerAdvice 注解:异常监听。标注在 java 类上
  • 定义一个异常处理方法

    • @ExceptionHandler 注解:标注在方法上

      • value 属性:指定当前异常处理器处理的异常类型
  • @ControllerAdvice 注解 + @ResponseBody 注解 可以合并成组合注解 @RestControllerAdvice
/**
* 全局异常处理器
*/
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {
 
    /**
     * 异常处理
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public DataResult exceptionHandler(Exception e) {
        log.error("GlobalExceptionHandler.exceptionHandler , 异常信息",e);
        return DataResult.fail(e.getMessage());
    }
 
    /**
     * 业务异常
     */
    @ResponseBody
    @ExceptionHandler(value = BplCommonException.class)
    public DataResult bplCommonExceptionHandler(BplCommonException e) {
        log.warn("",e);
        return DataResult.fail(e.getMessage());
    }
 
    /**
     * 处理所有RequestBody注解参数验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public DataResult handleMethodArgumentNotValidException(MethodArgumentNotValidException e){
        log.warn(e.getMessage());
        return DataResult.fail(e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
    }
 
    /**
     * 处理所有RequestParam注解数据验证异常
     */
    @ExceptionHandler(BindException.class)
    public DataResult handleBindException(BindException ex) {
        FieldError fieldError = ex.getBindingResult().getFieldError();
        log.warn("必填校验异常:{}({})", fieldError.getDefaultMessage(),fieldError.getField());
        return DataResult.fail(ex.getBindingResult().getAllErrors().get(0).getDefaultMessage());
    }
}

finally 关键字

作用:

​ finally关键字里边定义的代码,无论程序是否有异常,都会执行。工作中一般用于资源释放(IO)

格式:

try{
    可能产生异常的代码
}catch(定义一个异常相关的变量 ){
    异常的处理逻辑(想怎么写就怎么写)
}
...
catch(定义一个异常相关的变量 ){
    异常的处理逻辑(想怎么写就怎么写)
}finally{
    无论程序是否有异常,都会执行的代码
}

注意:

1,finally不能单独使用,必须和try一起使用

2,如果try中出现了异常,会先执行catch中异常的处理逻辑,再执行finally中定义的代码。执行完毕finally中的代码,会继续执行try catch finally之后的代码

3,如果try没有异常,执行完try中的代码,再执行finally中定义的代码。执行完毕finally中的代码,会继续执行try catch finally之后的代码

Throwable类中定义的异常处理逻辑

仅供参考,我们可以使用,也可以自己定义异常的处理逻辑

Throwable类中成员方法:

// JVM处理异常对象,把异常对象打印在控制台,默认调用的就是此方法
void printStackTrace()
// 返回此 throwable 的简短描述
String getMessage()
// 返回此 throwable 的详细消息字符串
String toString()

Exception类继承了Throwable,所以Exception所有的子类都可以使用这三个方法

注意事项

运行期异常

  • 运行期异常被抛出可以不处理,默认会交给JVM处理==>中断。

    即不捕获(不使用try catch来捕获处理异常)也不声明抛出(不使用throws声明抛出异常对象)

  • 运行时异常,我们处理没有意义,处理了也是为了让后续代码可以继续执行,但是运行时异常本身还是存在的。

    比如如果使用数组,超出了数组索引的使用范围,就算我们使用try catch处理了运行时异常。实际上数组还是越界的,没有从根本上解决问题。这时候我们应该修改代码,不让数组的索引越界

子父类异常的处理

  • 如果父类的方法抛出了多个异常,

    ​ 子类重写父类方法时,子类可以抛出和父类方法相同的异常

    ​ 子类重写父类方法时,抛出父类异常的子类

    ​ 子类重写父类方法时,可以不抛出异常

  • 父类方法没有抛出异常,子类重写父类该方法时也不可抛出异常

    若此时子类产生异常,只能捕获处理,不能声明抛出

重点:子类重写父类方法,父类方法异常什么样,子类和父类一样就可以了,无需考虑异常问题

多个异常的捕获处理

  • 多个异常分别处理

    一个异常使用一个try catch处理

  • 多个异常一次捕获,多次处理

    格式:

    try{
        ...
    }catch(xxxException e){
        ...
        e.printStackTrace();
    }catch(xxxException e){
        ...
        e.printStackTrace();
    }

    好处:

    ​ 简化代码,只写一个try就可以了

    ​ 每个catch中都可以写不同的异常处理逻辑

    注意:

    ​ 一个try多个catch这种写法,catch中定义的异常变量,不能是下边定义异常变量的父类

  • 多个异常一次捕获一次处理

    格式:

    try{
        ...
    }catch(Exception e){
        ...
        e.printStackTrace();
    }

    好处:格式简单

    弊端:无论try中有多少种异常产生,只能在catch中写一种异常的处理逻辑

自定义异常类

java给我们提供的异常类不够我们使用,就需要我们自己定义一些异常相关的类

注意:

1.自定义异常类名,一般都是以Exception结尾,说明这就是一个异常相关的的类(见名知意)

2.自定义异常类

​ a.继承Exception:自定义异常就是一个编译期异常

​ 使用:如果在方法中抛出了编译期异常,那么我们就必须的处理这个异常,有两种处理方式

​ 1)使用throws关键字在方法上继续声明抛出这个异常对象,让方法调用者处理,最终抛出给JVM(中断)

​ 2)使用try catch自己捕获处理异常对象

​ b.继承RuntimeException:自定义异常就是一个运行期(时)异常

​ 使用:如果在方法中抛出了运行期异常,我们无需处理,默认交给JVM处理(中断)

自定义编译异常类

public class BaseException extends Exception{
    public BaseException() {
    }

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

自定义运行期异常类

运行期异常类

/**
 * 自定义通用运行期异常
 */
public class BaseRuntimeException extends RuntimeException{
    static final long serialVersionUID = -3387516993124229952L;

    private String code;

    public BaseRuntimeException() {
    }

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

    public BaseRuntimeException(String code, String message) {
        super(message);
        this.code = code;
    }

    public BaseRuntimeException(String message, Throwable e) {
        super(message, e);
    }

    public BaseRuntimeException(Throwable e) {
        super(e);
    }

    public BaseRuntimeException(BaseResponseEnum responseEnum) {
        this(responseEnum.getCode(), responseEnum.getMsg());
    }
}

异常信息码枚举类

import org.assertj.core.util.Preconditions;

/**
 * 异常信息码复用枚举类
 */
public class BaseResponseEnum {

    final private String code;
    final private String msg;

    public BaseResponseEnum(String code, String msg){
        Preconditions.checkNotNull(code);
        Preconditions.checkNotNull(msg);

        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public static final BaseResponseEnum SUCCESS =
            new BaseResponseEnum("000000", "sucess");

    public static final BaseResponseEnum FAILURE =
            new BaseResponseEnum("999999", "系统繁忙,请稍后再试");

    public static final BaseResponseEnum BUS_CUSTOMER_ERROR =
            new BaseResponseEnum("910000", "业务处理异常");

    public static final BaseResponseEnum ILLEGAL_REQUEST =
            new BaseResponseEnum("920000", "非法请求");
}

拓展

Objects类中requireNonNull方法

java.util.Objects:操作对象的工具类

// 判断传递的对象是否为null
static <T> T requireNonNull(T obj)
static <T> T requireNonNull(T obj, String message)
/*    如果传递的对象是null,方法内部就会抛出空指针异常
    如果传递的对象不是null,则方法内部会返回这个对象 */
   
// 方法的源码:
public static <T> T requireNonNull(T obj) {
    if (obj == null){
        throw new NullPointerException();
    }
    return obj;
}

public static <T> T requireNonNull(T obj, String message) {
    if (obj == null){
        throw new NullPointerException(message);
    }
    return obj;
}
相关文章
|
4天前
|
Java
在 Java 中捕获和处理自定义异常的代码示例
本文提供了一个 Java 代码示例,展示了如何捕获和处理自定义异常。通过创建自定义异常类并使用 try-catch 语句,可以更灵活地处理程序中的错误情况。
|
4天前
|
Java
在 Java 中,如何自定义`NumberFormatException`异常
在Java中,自定义`NumberFormatException`异常可以通过继承`IllegalArgumentException`类并重写其构造方法来实现。自定义异常类可以添加额外的错误信息或行为,以便更精确地处理特定的数字格式转换错误。
|
5天前
|
IDE 前端开发 Java
怎样避免 Java 中的 NoSuchFieldError 异常
在Java中避免NoSuchFieldError异常的关键在于确保类路径下没有不同版本的类文件冲突,避免反射时使用不存在的字段,以及确保所有依赖库版本兼容。编译和运行时使用的类版本应保持一致。
|
6天前
|
Java 编译器
如何避免在 Java 中出现 NoSuchElementException 异常
在Java中,`NoSuchElementException`通常发生在使用迭代器、枚举或流等遍历集合时,尝试访问不存在的元素。为了避免该异常,可以在访问前检查是否有下一个元素(如使用`hasNext()`方法),或者使用`Optional`类处理可能为空的情况。正确管理集合边界和条件判断是关键。
|
9天前
|
Java
Java异常捕捉处理和错误处理
Java异常捕捉处理和错误处理
11 1
|
11天前
|
Java 编译器 开发者
Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面
本文探讨了Java异常处理的最佳实践,涵盖理解异常类体系、选择合适的异常类型、提供详细异常信息、合理使用try-catch和finally语句、使用try-with-resources、记录异常信息等方面,帮助开发者提高代码质量和程序的健壮性。
27 2
|
18天前
|
Java
如何在 Java 中处理“Broken Pipe”异常
在Java中处理“Broken Pipe”异常,通常发生在网络通信中,如Socket编程时。该异常表示写入操作的另一端已关闭连接。解决方法包括:检查网络连接、设置超时、使用try-catch捕获异常并进行重试或关闭资源。
|
16天前
|
Java 网络安全 Maven
Exception in thread "main" java.lang.NoSuchMethodError: okhttp3.OkHttpClient$Builder.sslSocketFactory(Ljavax/net/ssl/SSLSocketFactory;Ljavax/net/ssl/X509TrustManager;)Lokhttp3/OkHttpClient$Builder; 问题处理
【10月更文挑战第26天】Exception in thread "main" java.lang.NoSuchMethodError: okhttp3.OkHttpClient$Builder.sslSocketFactory(Ljavax/net/ssl/SSLSocketFactory;Ljavax/net/ssl/X509TrustManager;)Lokhttp3/OkHttpClient$Builder; 问题处理
34 2
Java基础异常-自定义异常
Java基础异常-自定义异常
Java基础异常-自定义异常
|
Java 编译器
Java中的异常(抛出异常、自定义异常等)
Java中的异常(抛出异常、自定义异常等)
303 1