攻克 Java 异常难题:典型异常解析、最佳处理方案与设计模式实践

攻克 Java 异常难题:典型异常解析、最佳处理方案与设计模式实践

在 Java 开发中,异常处理是衡量代码健壮性、可维护性的核心指标之一。多数开发者在入门阶段仅能实现"捕获异常"的基础操作,却常常陷入"空 catch 块""滥用 try-catch""异常信息模糊"等误区,导致系统上线后出现难以排查的 Bug、日志冗余混乱,甚至引发服务雪崩。本文将聚焦 Java 开发中最典型的异常场景,拆解问题根源,探讨可落地的最佳处理方案,并结合设计模式优化异常处理逻辑,帮助开发者从"被动解决异常"转向"主动预防、规范处理",写出更健壮、更易维护的 Java 代码。

一、Java 异常基础认知:跳出认知误区

在深入探讨异常处理之前,我们先厘清 Java 异常体系的核心概念,避免因基础认知偏差导致的处理失当。Java 异常体系以 Throwable 为顶层父类,分为两大分支:Error(错误)和 Exception(异常)。

1.1 核心区别:Error vs Exception

  • Error:由 JVM 抛出,代表系统级错误(如 OutOfMemoryError、StackOverflowError),无法通过代码捕获和恢复,属于不可逆的严重问题。开发中无需针对 Error 做处理,重点在于通过合理的系统设计(如内存优化、线程池配置)预防其发生。
  • Exception :程序运行时可预测、可处理的异常,分为 Checked Exception(受检异常)和 Unchecked Exception(非受检异常)。
    • Checked Exception:编译期强制要求捕获或声明抛出(如 IOException、SQLException),通常与外部资源交互相关(如文件读取、数据库连接),需开发者明确处理逻辑。
    • Unchecked Exception:继承自 RuntimeException,编译期不强制处理(如 NullPointerException、IllegalArgumentException),多由代码逻辑错误导致(如空指针调用、非法参数传入),重点在于通过编码规范预防。

1.2 常见认知误区

很多开发者在异常处理中存在以下误区,导致代码质量下降:

  • 误区 1:捕获通用异常(catch Exception),导致无法精准定位异常原因;
  • 误区 2:空 catch 块(不做任何处理),掩盖异常问题,增加排查难度;
  • 误区 3:滥用 throws,将异常直接抛给上层,推卸处理责任;
  • 误区 4:异常信息模糊(如 e.printStackTrace()),无关键上下文,难以排查。

后续内容将围绕这些误区,结合典型异常场景,给出可落地的解决方案。

二、典型 Java 异常解析:场景、根源与解决方案

本节选取 Java 开发中最常出现的 5 类典型异常,从"常见场景 → 问题根源 → 常规处理 → 优化方案"四个维度拆解,确保每个方案都贴合实际开发场景,可直接复用。

2.1 NullPointerException(NPE):最高频的"隐形杀手"

NPE 是 Java 开发中出现频率最高的异常,本质是"调用了 null 对象的方法、字段或数组下标",看似简单,却常常因代码不规范导致难以排查。

常见场景
  • 调用 null 对象的成员方法(如 String str = null; str.length(););
  • 访问 null 对象的成员变量(如 User user = null; String name = user.getName(););
  • 数组为 null 时访问下标(如 String[] arr = null; arr[0] = "test";);
  • 方法返回 null,调用方未判断直接使用(如 List list = getList(); list.size();)。
问题根源

核心是"未对可能为 null 的对象做前置校验",或"过度依赖方法返回非 null 值",违背了"防御性编程"原则。

常规处理方案(不推荐)
java 复制代码
// 常规处理:频繁if-null判断,代码冗余,可读性差
public void handleNPE(String str) {
    if (str != null) {
        System.out.println(str.length());
    } else {
        System.out.println("字符串为空");
    }
}
优化方案(推荐)
  • 方案 1:使用 Java 8+ Optional 类,优雅避免空判断(推荐用于方法返回值);
  • 方案 2:编码规范:避免返回 null,优先返回空集合、空字符串(如 return Collections.emptyList());
  • 方案 3:使用 Objects.requireNonNull()做前置校验(适用于方法参数);
  • 方案 4:借助 IDE 工具(如 IDEA)开启 NPE 预警,提前发现潜在问题。
java 复制代码
// 优化方案1:Optional类使用(推荐)
public Optional<String> getUserName(User user) {
    // 若user为null,返回Optional.empty(),避免NPE
    return Optional.ofNullable(user).map(User::getName);
}

// 调用方使用
Optional<String> userNameOpt = getUserName(user);
String userName = userNameOpt.orElse("默认名称"); // 无值时返回默认值

// 优化方案3:Objects.requireNonNull()参数校验
public void checkParam(String str) {
    // 若str为null,直接抛出NullPointerException,明确异常原因
    Objects.requireNonNull(str, "参数str不能为空");
    System.out.println(str.length());
}

2.2 IllegalArgumentException:非法参数的"第一道防线"

该异常属于非受检异常,用于表示"方法接收的参数不符合预期"(如参数为负数、空字符串、超出合法范围),是防御性编程的重要手段。

常见场景
  • 方法参数为负数(如计算分页时,pageSize = -1);
  • 参数格式非法(如手机号长度不为 11 位、邮箱格式错误);
  • 参数为空字符串且不允许为空(如用户注册时,用户名为空字符串)。
问题根源

未对方法参数做合法性校验,导致非法参数进入业务逻辑,引发后续异常(如数据库查询报错、业务逻辑错乱)。

最佳处理方案
  • 前置校验:在方法入口处对参数进行全面校验,优先抛出 IllegalArgumentException,明确异常原因;
  • 借助工具类:使用 Apache Commons Lang3(如 StringUtils、Validate)或 Spring Validation 简化校验逻辑;
  • 异常信息:明确说明"参数名 + 非法原因 + 合法范围",方便排查。
java 复制代码
// 推荐方案:结合Apache Commons Lang3简化校验
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;

public void registerUser(String username, String phone) {
    // 校验用户名:不为null且不为空字符串
    Validate.notBlank(username, "用户名不能为空(参数名:username)");
    // 校验手机号:不为null、长度为11位
    Validate.isTrue(StringUtils.isNotBlank(phone) && phone.length() == 11, 
                    "手机号非法(参数名:phone),需为11位有效数字");
    // 业务逻辑...
}

// Spring Boot场景:使用Spring Validation注解校验(更简洁)
public void addUser(@NotBlank(message = "用户名不能为空") String username,
                   @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式非法") String phone) {
    // 业务逻辑...
}

2.3 IOException:外部资源交互的"必然挑战"

IOException 是受检异常,主要发生在"外部资源交互"场景(如文件读取/写入、网络请求、流操作),核心问题是"资源未正确关闭"或"资源不可用"(如文件不存在、权限不足)。

常见场景
  • 读取不存在的文件(如 new FileInputStream("test.txt"),文件不存在);
  • 流操作后未关闭资源(如 InputStream 未 close(),导致资源泄露);
  • 权限不足(如写入文件时,当前用户无写入权限)。
问题根源
  1. 未使用"自动关闭资源"机制,手动关闭资源时遗漏(如 try-catch-finally 中,finally 块未正确关闭流);2. 未预判资源不可用场景(如文件路径错误、网络中断)。
最佳处理方案
  • 使用 try-with-resources(Java 7+):自动关闭实现 AutoCloseable 接口的资源(如 InputStream、OutputStream),避免资源泄露;
  • 分层处理:底层捕获 IOException,封装为自定义业务异常,上层统一处理;
  • 预判异常场景:提前校验资源可用性(如文件是否存在、权限是否足够)。
java 复制代码
// 推荐方案:try-with-resources自动关闭资源
public String readFile(String filePath) throws BusinessException {
    // 前置校验:文件是否存在
    File file = new File(filePath);
    if (!file.exists()) {
        throw new BusinessException("文件不存在(路径:" + filePath + ")", ErrorCode.FILE_NOT_EXIST);
    }
    // try-with-resources:流会自动关闭,无需手动写finally
    try (InputStream is = new FileInputStream(file);
         BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8))) {
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            sb.append(line);
        }
        return sb.toString();
    } catch (IOException e) {
        // 底层异常封装为业务异常,上层统一处理
        throw new BusinessException("文件读取失败(路径:" + filePath + ")", ErrorCode.FILE_READ_ERROR, e);
    }
}

2.4 ClassCastException:类型转换的"隐形陷阱"

该异常属于非受检异常,发生在"强制类型转换"时,当对象的实际类型与目标转换类型不兼容时抛出(如将 String 对象转换为 Integer)。

常见场景
  • 集合未指定泛型,取出元素时强制转换(如 List list = new ArrayList(); list.add("test"); Integer num = (Integer) list.get(0););
  • 多态场景下,子类对象强制转换为非关联子类(如 Animal animal = new Dog(); Cat cat = (Cat) animal;);
  • 反射场景下,类型转换错误(如 Class.forName("java.lang.String").cast(123);)。
问题根源
  1. 未使用泛型(Java 5+)规范集合类型;2. 强制转换前未判断对象实际类型(未使用 instanceof);3. 反射场景下未校验类型兼容性。
最佳处理方案
  • 优先使用泛型:规范集合、泛型方法,从根源上避免类型转换错误;
  • 强制转换前使用 instanceof 判断类型兼容性;
  • 反射场景下,使用 Class.isAssignableFrom()校验类型兼容性。
java 复制代码
// 优化方案1:使用泛型,避免类型转换
List<String> list = new ArrayList<>();
list.add("test");
String str = list.get(0); // 无需强制转换,无ClassCastException风险

// 优化方案2:强制转换前用instanceof判断
public void castObject(Object obj) {
    if (obj instanceof Integer) {
        Integer num = (Integer) obj;
        System.out.println("转换成功:" + num);
    } else {
        throw new IllegalArgumentException("对象类型非法,需为Integer类型(实际类型:" + obj.getClass().getName() + ")");
    }
}

// 优化方案3:反射场景下校验类型
public <T> T castByReflection(Class<T> targetClass, Object obj) {
    // 校验类型兼容性:obj的类型是否可转换为targetClass
    if (targetClass.isAssignableFrom(obj.getClass())) {
        return targetClass.cast(obj);
    } else {
        throw new ClassCastException("类型转换失败:" + obj.getClass().getName() + " 无法转换为 " + targetClass.getName());
    }
}

2.5 自定义异常:业务异常的"标准化表达"

Java 内置异常无法满足业务场景的个性化需求(如"用户不存在""订单状态异常"),此时需要自定义异常,实现"业务异常标准化",便于统一处理和排查。

最佳实践
  • 继承关系:业务异常优先继承 RuntimeException(非受检异常),避免编译期强制捕获,减少代码冗余;
  • 核心属性:包含错误码(ErrorCode)、错误信息、根因异常(cause),便于日志排查和上层统一处理;
  • 编码规范:异常类名结尾为 Exception,错误码统一管理(如枚举类),避免硬编码。
java 复制代码
// 1. 错误码枚举(统一管理)
public enum ErrorCode {
    USER_NOT_EXIST(10001, "用户不存在"),
    ORDER_STATUS_ERROR(10002, "订单状态异常"),
    FILE_NOT_EXIST(20001, "文件不存在"),
    FILE_READ_ERROR(20002, "文件读取失败");

    private final int code;
    private final String message;

    ErrorCode(int code, String message) {
        this.code = code;
        this.message = message;
    }

    // getter方法
    public int getCode() { return code; }
    public String getMessage() { return message; }
}

// 2. 自定义业务异常
public class BusinessException extends RuntimeException {
    private final int errorCode;
    private final String errorMessage;

    // 构造方法(重载,满足不同场景)
    public BusinessException(ErrorCode errorCode) {
        super(errorCode.getMessage());
        this.errorCode = errorCode.getCode();
        this.errorMessage = errorCode.getMessage();
    }

    public BusinessException(String errorMessage, ErrorCode errorCode, Throwable cause) {
        super(errorMessage, cause);
        this.errorCode = errorCode.getCode();
        this.errorMessage = errorMessage;
    }

    // getter方法
    public int getErrorCode() { return errorCode; }
    public String getErrorMessage() { return errorMessage; }
}

三、异常处理最佳方案:从规范到落地

结合上述典型异常的处理经验,总结 Java 异常处理的 7 个最佳实践,覆盖"预防、处理、日志、分层"全流程,可直接应用于实际开发,提升代码健壮性和可维护性。

3.1 预防优先:编码规范杜绝常见异常

  • 避免返回 null:优先返回空集合、空字符串、Optional.empty(),减少 NPE 风险;
  • 参数校验前置:所有方法入口处对参数进行校验(使用 Objects、Apache Commons、Spring Validation);
  • 使用泛型:规范集合、泛型方法,避免 ClassCastException;
  • 资源自动关闭:所有外部资源(流、数据库连接、网络连接)使用 try-with-resources 自动关闭,避免资源泄露。

3.2 规范处理:异常捕获与抛出的原则

  • 精准捕获:避免 catch Exception(通用异常),只捕获具体异常(如 NullPointerException、IOException),便于精准定位;
  • 不忽略异常:禁止空 catch 块,即使不需要处理,也需记录日志(说明忽略原因);
  • 合理抛出:throws 只用于"无法在当前层处理"的异常,抛出前需补充关键上下文信息,不盲目抛给上层;
  • 异常转换:底层异常(如 IOException、SQLException)封装为上层可理解的业务异常(自定义异常),避免上层处理底层技术细节。

3.3 日志规范:异常排查的"关键支撑"

  • 避免 e.printStackTrace():该方法会打印堆栈信息到控制台,且无法控制输出位置,推荐使用日志框架(SLF4J+Logback/Log4j2)记录;
  • 日志内容:包含"异常场景 + 错误码 + 错误信息 + 根因异常",便于排查(如"用户注册失败,用户名:xxx,错误码:10001,原因:用户已存在");
  • 日志级别:业务异常用 WARN 级别,系统异常(如 NPE、ClassCastException)用 ERROR 级别,避免日志冗余。
java 复制代码
// 推荐日志记录方式(SLF4J)
private static final Logger log = LoggerFactory.getLogger(UserService.class);

public User getUserById(Long userId) {
    try {
        User user = userDao.selectById(userId);
        if (user == null) {
            log.warn("用户查询失败,用户ID:{},错误码:{},原因:{}", 
                    userId, ErrorCode.USER_NOT_EXIST.getCode(), ErrorCode.USER_NOT_EXIST.getMessage());
            throw new BusinessException(ErrorCode.USER_NOT_EXIST);
        }
        return user;
    } catch (SQLException e) {
        log.error("用户查询数据库异常,用户ID:{},错误码:{},原因:{}", 
                userId, ErrorCode.DB_ERROR.getCode(), "数据库连接失败", e); // 传入根因异常e
        throw new BusinessException("用户查询失败", ErrorCode.DB_ERROR, e);
    }
}

3.4 分层处理:异常的"责任划分"

在分层架构(Controller→Service→Dao)中,异常处理需遵循"分层负责、统一收口"的原则,避免重复处理。

  • Dao 层:只抛出异常(如 SQLException),不处理,由 Service 层统一捕获并转换;
  • Service 层:捕获 Dao 层异常,转换为业务异常,补充业务上下文信息,必要时记录日志;
  • Controller 层:捕获 Service 层抛出的业务异常和系统异常,统一返回标准化响应(如包含错误码、错误信息的 JSON),避免异常暴露给前端。
java 复制代码
// Controller层统一异常处理(Spring Boot场景,使用@RestControllerAdvice)
@RestControllerAdvice
public class GlobalExceptionHandler {

    // 处理自定义业务异常
    @ExceptionHandler(BusinessException.class)
    public Result<Void> handleBusinessException(BusinessException e) {
        log.warn("业务异常:错误码={},错误信息={}", e.getErrorCode(), e.getErrorMessage());
        return Result.fail(e.getErrorCode(), e.getErrorMessage());
    }

    // 处理系统异常(如NPE、ClassCastException)
    @ExceptionHandler({NullPointerException.class, ClassCastException.class})
    public Result<Void> handleSystemException(RuntimeException e) {
        log.error("系统异常:原因={}", e.getMessage(), e);
        return Result.fail(500, "系统繁忙,请稍后再试");
    }

    // 处理其他未捕获异常
    @ExceptionHandler(Exception.class)
    public Result<Void> handleOtherException(Exception e) {
        log.error("未知异常:原因={}", e.getMessage(), e);
        return Result.fail(500, "系统繁忙,请稍后再试");
    }
}

四、异常处理设计模式:提升代码可扩展性

当系统规模扩大、异常场景增多时,单纯的 try-catch 会导致代码冗余、耦合度高,难以维护。此时可借助设计模式优化异常处理逻辑,实现"异常处理与业务逻辑解耦",提升代码可扩展性。

4.1 策略模式:不同异常,不同处理策略

应用场景

当不同类型的异常需要不同的处理逻辑(如业务异常返回友好提示、系统异常记录详细日志并报警、第三方异常重试)时,使用策略模式,将每种异常的处理逻辑封装为独立策略,避免多重 if-else 判断。

实现步骤
  1. 定义异常处理策略接口(ExceptionHandlerStrategy),包含处理方法;
  2. 为每种异常类型实现具体策略(如 BusinessExceptionStrategy、SystemExceptionStrategy);
  3. 定义策略工厂(ExceptionHandlerFactory),根据异常类型获取对应策略;
  4. 上层调用工厂获取策略,执行异常处理逻辑。
java 复制代码
// 1. 异常处理策略接口
public interface ExceptionHandlerStrategy {
    Result<Void> handle(Exception e);
}

// 2. 具体策略:业务异常处理
public class BusinessExceptionStrategy implements ExceptionHandlerStrategy {
    private static final Logger log = LoggerFactory.getLogger(BusinessExceptionStrategy.class);

    @Override
    public Result<Void> handle(Exception e) {
        BusinessException ex = (BusinessException) e;
        log.warn("业务异常:错误码={},错误信息={}", ex.getErrorCode(), ex.getErrorMessage());
        return Result.fail(ex.getErrorCode(), ex.getErrorMessage());
    }
}

// 3. 具体策略:系统异常处理
public class SystemExceptionStrategy implements ExceptionHandlerStrategy {
    private static final Logger log = LoggerFactory.getLogger(SystemExceptionStrategy.class);

    @Override
    public Result<Void> handle(Exception e) {
        log.error("系统异常:原因={}", e.getMessage(), e);
        // 可选:系统异常报警(如调用钉钉、企业微信接口)
        alarmService.sendAlarm("系统异常:" + e.getMessage());
        return Result.fail(500, "系统繁忙,请稍后再试");
    }
}

// 4. 策略工厂
public class ExceptionHandlerFactory {
    // 存储策略:异常类型 → 对应策略
    private static final Map<Class<? extends Exception>, ExceptionHandlerStrategy> STRATEGY_MAP = new HashMap<>();

    // 静态初始化:注册策略
    static {
        STRATEGY_MAP.put(BusinessException.class, new BusinessExceptionStrategy());
        STRATEGY_MAP.put(NullPointerException.class, new SystemExceptionStrategy());
        STRATEGY_MAP.put(ClassCastException.class, new SystemExceptionStrategy());
        // 可扩展:添加更多异常类型和对应策略
    }

    // 获取策略
    public static ExceptionHandlerStrategy getStrategy(Exception e) {
        // 若未找到对应策略,返回默认策略(处理未知异常)
        return STRATEGY_MAP.getOrDefault(e.getClass(), new DefaultExceptionStrategy());
    }

    // 默认策略:处理未知异常
    private static class DefaultExceptionStrategy implements ExceptionHandlerStrategy {
        @Override
        public Result<Void> handle(Exception e) {
            log.error("未知异常:原因={}", e.getMessage(), e);
            return Result.fail(500, "系统繁忙,请稍后再试");
        }
    }
}

// 5. 上层调用(替换多重if-else)
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(Exception.class)
    public Result<Void> handleException(Exception e) {
        // 工厂获取策略,执行处理逻辑
        ExceptionHandlerStrategy strategy = ExceptionHandlerFactory.getStrategy(e);
        return strategy.handle(e);
    }
}
优势

解耦异常处理逻辑与业务逻辑,新增异常类型时,只需新增具体策略并注册到工厂,无需修改原有代码,符合"开闭原则",可扩展性强。

4.2 模板方法模式:固定异常处理流程

应用场景

当多个方法的异常处理流程一致(如"前置校验 → 业务逻辑 → 异常捕获 → 日志记录 → 异常转换"),仅业务逻辑不同时,使用模板方法模式,将固定流程封装为模板,业务逻辑由子类实现。

实现步骤
  1. 定义抽象模板类,包含固定流程的模板方法(如 execute()),以及抽象业务方法(如 doBusiness());
  2. 模板方法中固定异常处理流程(try-catch、日志记录、异常转换);
  3. 子类继承抽象类,实现具体业务方法,无需关注异常处理流程。
java 复制代码
// 1. 抽象模板类
public abstract class BusinessTemplate<T> {
    private static final Logger log = LoggerFactory.getLogger(BusinessTemplate.class);

    // 模板方法:固定异常处理流程
    public final Result<T> execute() {
        try {
            // 1. 前置校验(固定流程)
            validate();
            // 2. 业务逻辑(抽象方法,由子类实现)
            T result = doBusiness();
            // 3. 成功响应(固定流程)
            return Result.success(result);
        } catch (BusinessException e) {
            // 4. 业务异常处理(固定流程)
            log.warn("业务异常:错误码={},错误信息={}", e.getErrorCode(), e.getErrorMessage());
            return Result.fail(e.getErrorCode(), e.getErrorMessage());
        } catch (Exception e) {
            // 5. 系统异常处理(固定流程)
            log.error("系统异常:原因={}", e.getMessage(), e);
            return Result.fail(500, "系统繁忙,请稍后再试");
        }
    }

    // 前置校验(可重写,默认空实现)
    protected void validate() {}

    // 抽象业务方法:由子类实现具体业务逻辑
    protected abstract T doBusiness() throws Exception;
}

// 2. 子类实现:用户查询业务
public class UserQueryTemplate extends BusinessTemplate<User> {
    private Long userId;

    // 构造方法:传入业务参数
    public UserQueryTemplate(Long userId) {
        this.userId = userId;
    }

    // 重写前置校验(可选)
    @Override
    protected void validate() {
        Objects.requireNonNull(userId, "用户ID不能为空");
    }

    // 实现业务逻辑
    @Override
    protected User doBusiness() throws SQLException {
        // 具体业务逻辑:查询用户
        return userDao.selectById(userId);
    }
}

// 3. 调用方式(无需关注异常处理)
public Result<User> queryUser(Long userId) {
    UserQueryTemplate template = new UserQueryTemplate(userId);
    return template.execute();
}
优势

统一异常处理流程,减少代码冗余,子类只需关注业务逻辑,提升开发效率;同时便于统一修改异常处理流程(如调整日志格式、新增异常类型)。

4.3 其他常用模式

  • 工厂模式:用于统一创建异常对象(如自定义异常工厂),避免硬编码异常信息和错误码;
  • 装饰器模式:用于增强异常处理逻辑(如在原有异常处理基础上,新增日志记录、报警功能),不修改原有代码。

五、总结:异常处理的核心思维

Java 异常处理的本质,不是"捕获所有异常",而是"在合适的层级、用合适的方式,处理合适的异常"。它不仅是一项编码技能,更是一种系统设计思维------好的异常处理,既能保证系统的健壮性(避免崩溃、资源泄露),也能提升代码的可维护性(便于排查、易于扩展),还能优化用户体验(友好的错误提示)。

结合本文内容,总结核心要点:

  1. 基础认知:分清 Error 与 Exception、Checked 与 Unchecked 异常,跳出常见误区;
  2. 典型异常:针对 NPE、非法参数、IO 异常等高频场景,采用"预防 + 优化"的处理方案;
  3. 最佳实践:遵循"预防优先、精准捕获、规范日志、分层处理"的原则;
  4. 设计模式:通过策略模式、模板方法模式等,实现异常处理与业务逻辑解耦,提升可扩展性。

异常处理没有"银弹",只有"适合"。在实际开发中,需结合项目规模、业务场景,灵活运用本文所述的方案和模式,避免过度设计,也避免敷衍处理。希望本文能帮助你攻克 Java 异常难题,写出更健壮、更优雅的 Java 代码。

结尾互动

你在 Java 开发中遇到过哪些难以解决的异常问题?有哪些自己的异常处理技巧?欢迎在评论区留言讨论,一起交流进步 ~

关注我的CSDN:blog.csdn.net/qq_30095907...

相关推荐
青云计划7 小时前
知光项目知文发布模块
java·后端·spring·mybatis
赶路人儿7 小时前
Jsoniter(java版本)使用介绍
java·开发语言
探路者继续奋斗8 小时前
IDD意图驱动开发之意图规格说明书
java·规格说明书·开发规范·意图驱动开发·idd
消失的旧时光-19439 小时前
第十九课:为什么要引入消息队列?——异步系统设计思想
java·开发语言
A懿轩A9 小时前
【Java 基础编程】Java 面向对象入门:类与对象、构造器、this 关键字,小白也能写 OOP
java·开发语言
乐观勇敢坚强的老彭9 小时前
c++寒假营day03
java·开发语言·c++
biubiubiu07069 小时前
谷歌浏览器无法访问localhost:8080
java
大黄说说10 小时前
新手选语言不再纠结:Java、Python、Go、JavaScript 四大热门语言全景对比与学习路线建议
java·python·golang
烟沙九洲10 小时前
Java 中的 封装、继承、多态
java
识君啊10 小时前
SpringBoot 事务管理解析 - @Transactional 的正确用法与常见坑
java·数据库·spring boot·后端