代码复杂度的代价远比你想象得大

引言:复杂度的代价远比你想象得大

在 Java 后端系统演进过程中,代码复杂度是影响可维护性、稳定性和迭代效率的核心因素。然而,复杂度往往被忽视,直到一次“小改动”引发线上事故,才被重新审视。

本文以“复杂度战争”为主题,系统性地探讨如何识别、评估和治理代码中的复杂性。本文不会停留在抽象原则,而是结合真实案例、Java 代码示例和可落地的工程实践,让你了解你应用的代码复杂度,以及一个优秀的开发同学应该做到的避免代码”腐烂“的最佳实践。

让我们以一些代码案例引入今天的话题。(文中代码案例皆为模拟案例)

案例一:圈复杂度过高导致大事故

在某一个大促开始的日子,订单创建接口在高峰期响应时间飙升,错误率突破 XX%。 紧急回滚?没有最近的发布记录。 最终排查日志发现,数据库连接池被耗尽,而根源竟是一次两周前的“微小优化”。

开发同学为了支持一个新的促销规则,在 OrderService.createOrder() 方法中加了这么一段逻辑:

if (user.isVip() && order.getTotalAmount().compareTo(BigDecimal.valueOf(100)) > 0) {try {Discount discount = promotionClient.getDiscount(order);if (discount != null && discount.isValid()) {order.setFinalPrice(order.getTotalAmount().subtract(discount.getValue()));} else {order.setFinalPrice(order.getTotalAmount());}} catch (Exception e) {// 静默失败,使用原价(开发本意是防崩)order.setFinalPrice(order.getTotalAmount());}
}

问题来了:这个 catch (Exception e) 不仅吞掉了业务异常,还捕获了 数据库连接超时异常(SQLException),导致外层事务未及时中断,线程持续等待,最终拖垮连接池。

而这个方法本身已有 350 行,嵌套层级达 6 层,圈复杂度高达 38 —— 没有人意识到,这次“小修”成了压垮系统的最后一根稻草。

这不是孤例。类似的复杂度事故,正在无数系统中悄然上演。

案例二:重复代码引发的数据错乱

支付网关中,签名计算逻辑在 AlipayProcessorWechatPayProcessor 等 7 个类中重复出现:

String sign = DigestUtils.md5Hex(data + secretKey).toUpperCase();

某天,安全团队要求升级为 SHA-256,但只改了其中 4 个实现类。剩下的 3 个渠道继续用 MD5,导致“无效签名”错误激增,影响数万笔交易。

工具扫描显示:重复代码率达 12%,而这些“看起来一样”的代码,分散在不同模块,无人统一维护。

案例三:“上帝类”无人敢动

CRM 系统中的 CustomerManager 类长达 2800 行,承担着客户创建、积分计算、消息推送、审计日志、缓存同步等 8 种职责。

更可怕的是,每次调用 updateCustomer(),都会触发一连串隐式行为:

public void updateCustomer(Customer customer) {customerRepo.save(customer);// 更新积分(即使只是改了个电话)rewardService.calculateReward(customer);// 推送消息(同步阻塞)messageQueue.send(buildUpdateMessage(customer));// 写审计日志auditLogService.log("UPDATE", customer.getId(), getCurrentUser());// 刷新缓存cacheService.evict("customer:" + customer.getId());
}

新来的工程师想改个字段校验逻辑,结果测出 5 个副作用 bug。从此,这个类成了团队心中的“禁区”。

案例四:微服务拆分后更慢了

物流平台将单体拆分为订单、路由、运力三个服务后,原本本地调用 routeService.findOptimalRoute() 的耗时从 50ms 变成 350ms(含网络+序列化+重试)。

而最致命的是,当路由服务不稳定时,订单服务因未配置熔断,持续重试,反向拖垮整个链路。

复杂度没有消失,只是从“代码层面”转移到了“分布式层面”

这些事件背后,都有一个共同敌人:失控的代码复杂度

它不像内存泄漏那样立刻崩溃系统,也不像权限漏洞那样被安全扫描抓出。它潜伏在每一次“先上线再说”的妥协里,在每一个没人敢动的类中,在每一段“还能看懂”的嵌套逻辑中,缓慢侵蚀系统的生命力。

而作为 Java 后端开发者,尤其是架构师,我们必须清醒地认识到:

系统的可维护性,不取决于功能多强大,而取决于它的复杂度是否可控。

在这场看不见硝烟的 复杂度战争 中,我们不能靠运气取胜。我们需要工具来度量它,需要原则来约束它,更需要实战策略来持续降低它。

接下来,我们将深入探讨:

  • 哪些指标能真正衡量代码复杂度?
  • 如何用合理的工具发现系统中的“复杂度热点”?
  • 在日常编码中,如何写出高质量、低复杂度的 Java 代码?
  • 架构层面,又该如何从源头控制复杂度的增长?

代码复杂度的主流定义

当我们说一段代码“太复杂”时,往往是一种直觉判断。但真正的工程实践需要可量化、可检测、可改进的指标。所谓“复杂度”,并不是指代码行数多,而是指理解、维护、修改它的认知成本高

在软件工程领域,已有多个被广泛认可的复杂度维度,它们从不同角度揭示代码的“健康状况”。

我们将逐一介绍这些指标的含义和实际案例,并按照其作用粒度分为三个层次:方法级、类级、继承结构级,帮助你系统化地识别和治理复杂度。

1. 圈复杂度(Cyclomatic Complexity)

定义

由 Thomas McCabe 提出,衡量程序中独立执行路径的数量。路径越多,测试难度越大,出错概率越高。

计算规则:每有一个 ifforwhilecasecatch,复杂度 +1;else 不加分。总分>5 需关注

危害

  • 路径爆炸 → 难以覆盖所有分支
  • 异常处理易遗漏
  • 修改风险高,容易引入副作用

实际案例

public BigDecimal calculateFinalPrice(Order order, User user, boolean hasCoupon) {BigDecimal total = order.getItems().stream().map(Item::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);if (total.compareTo(BigDecimal.valueOf(100)) > 0) {           // +1if (user.isVip()) {                                       // +2total = total.multiply(BigDecimal.valueOf(0.9));      // VIP 9折} else if (hasCoupon) {                                   // +3total = total.subtract(BigDecimal.valueOf(10));       // 减10元}}try {Promotion promotion = promotionClient.getActivePromotion(); // +4if (promotion != null && promotion.isValid()) {             // +5total = total.subtract(promotion.getDiscount());}} catch (RemoteException e) {                                   // +6log.warn("Failed to fetch promotion, using base price");}return total;
}

该方法圈复杂度 = 6

虽然不算极端,但已接近警戒线(>5 需关注)。若未来增加节日折扣、地区限制等条件,极易突破 10。

改进方向

使用策略模式或规则引擎解耦判断逻辑,或将促销计算抽象为独立服务。

2. 嵌套深度(Nesting Depth)

定义

代码块的嵌套层级,如 if 中套 if,再套 fortry。每增加一层,理解成本呈指数上升。。推荐阈值:≤3 层,超过即应重构。

实际案例:“左箭头综合征”

public boolean processRefund(RefundRequest request) {if (request != null) {Order order = orderService.findById(request.getOrderId());if (order != null) {if (order.getStatus() == OrderStatus.PAID) {PaymentRecord record = paymentService.findByOrder(order);if (record != null) {try {RefundResult result = paymentGateway.refund(record);if (result.isSuccess()) {refundRepo.save(new Refund(record, SUCCESS));return true;} else {log.error("Refund failed: {}", result.getMessage());return false;}} catch (PaymentException e) {log.error("Payment system error", e);return false;}} else {return false;}} else {return false;}} else {return false;}} else {return false;}
}

嵌套达 6 层,阅读需不断“缩进-回退”,极易漏判条件。

改进方向

使用卫语句(Guard Clauses)提前返回

public boolean processRefund(RefundRequest request) {if (request == null) return false;Order order = orderService.findById(request.getOrderId());if (order == null || order.getStatus() != OrderStatus.PAID) return false;PaymentRecord record = paymentService.findByOrder(order);if (record == null) return false;try {RefundResult result = paymentGateway.refund(record);if (result.isSuccess()) {refundRepo.save(new Refund(record, SUCCESS));return true;} else {log.error("Refund failed: {}", result.getMessage());return false;}} catch (PaymentException e) {log.error("Payment system error", e);return false;}
}

逻辑扁平化,可读性显著提升。

3. 方法长度 & 类长度

定义

  • 方法长度:单个方法的代码行数(不含空行和注释)
  • 类长度:单个类的总行数

经验阈值:

  • 方法 ≤ 50 行
  • 类 ≤ 500 行

超出即可能违反 单一职责原则(SRP)

实际案例:上帝方法

// 一个长达 320 行的 createOrder() 方法
// 包含:参数校验、库存扣减、价格计算、优惠应用、积分发放、消息推送、日志记录、异常重试……
public Order createOrder(CreateOrderRequest request) {// ... 320 行混合逻辑 ...
}
  • 无法单元测试所有路径
  • 任何改动都可能引发未知副作用
  • 新人完全看不懂执行流程

改进方向

public Order createOrder(CreateOrderRequest request) {validateRequest(request);                    // 校验InventoryResult inv = inventoryService.deduct(request); // 扣库存PriceCalculation calc = priceEngine.calculate(request); // 算价Order order = orderRepo.save(mapToEntity(request, calc)); // 保存rewardService.awardPoints(order);            // 发积分eventPublisher.publish(new OrderCreatedEvent(order)); // 发事件return order;
}

每个步骤独立,便于替换、测试、监控。

4. 类级复杂度:CK Metrics 四大经典指标

在面向对象系统中,仅看行数和方法数量还不够。我们需要更精细的指标来评估一个类的设计质量。以下四个指标合称 CK Metrics Suite(Chidamber & Kemerer),是业界公认的类复杂度评估标准。

(1)WMC(Weighted Methods per Class)

类的方法圈复杂度加权和

  • 含义:一个类中所有方法的圈复杂度之和
  • 示例:若某类有 5 个方法,圈复杂度分别为 6、8、5、12、4,则 WMC = 35
  • 危害:WMC 越高,表示该类整体逻辑密度大,维护和测试成本高
  • 建议阈值:≤45,否则应考虑拆分

WMC 是对“类长度”的深化 —— 它不仅看有多少方法,更关注这些方法有多复杂。

(2)CBO(Coupling Between Object Classes)

类间耦合度

  • 含义:一个类所依赖的外部类的数量
  • 关联概念:你在“依赖复杂度”一节中提到的 Efferent Coupling(Ce) 本质上就是 CBO
  • 危害:CBO 高 → 耦合强 → 变动牵一发而动全身,不利于复用
  • 建议阈值:≤7

小结:CBO 和 Efferent Coupling 指标一致,只是术语来源不同。现代工具如 SonarQube 使用后者,但在学术和架构评审中,“CBO”仍是通用说法。

(3)RFC(Response for a Class)

类的响应集

  • 含义:一个类能直接或间接响应的方法总数,包括自身方法 + 它调用的外部方法
  • 示例:OrderService.create() 调用了 paymentService.pay()rewardService.award(),则这两个调用也计入 RFC
  • 危害:RFC 越大,表示该类的行为影响面越广,测试组合爆炸,理解成本上升
  • 建议阈值:≤50

(4)LCOM(Lack of Cohesion in Methods)

方法间内聚性缺失

  • 含义:衡量类中方法是否共享相同的字段。如果方法分为几组,各自操作不同的属性,则 LCOM 高
class User {private String name, email;private int loginCount;// updateProfile() 只用 name/email// incrementLogin() 只用 loginCount// → LCOM 高,说明职责不聚焦
}
  • 危害:LCOM 高 → 类缺乏内聚性 → 实际上承担了多个职责 → 应拆分
  • 改进方向:识别方法访问的字段簇,按业务边界进行类拆分

5. 继承结构复杂度

当系统使用继承时,还需关注类层次结构本身的复杂性。

(1)DIT(Depth of Inheritance Tree)

继承树深度

  • 含义:从当前类到根类的最大路径长度
  • 示例:Animal → Mammal → Dog,Dog 的 DIT = 2
  • 危害:DIT 越深,行为越难预测(父类逻辑隐式传递),调试困难
  • 建议:DIT ≤ 3,过深应考虑改用组合

(2)NOC(Number of Children)

子类数量

  • 含义:一个类的直接子类个数
  • 危害:NOC 过大(如 >10)说明父类抽象不够通用,或继承体系设计不合理
  • 改进方向:提取共性接口,或使用策略模式替代继承

6. 重复代码率(Duplication)

定义

系统中相同或高度相似代码块的比例。违背 DRY(Don't Repeat Yourself)原则。

实际案例:到处复制的签名逻辑

// 在 AlipayProcessor 中
String sign = DigestUtils.md5Hex(data + apiKey).toUpperCase();// 在 WechatPayProcessor 中(一模一样)
String sign = DigestUtils.md5Hex(data + apiKey).toUpperCase();// 在 UnionpayProcessor 中(还是一样)
String sign = DigestUtils.md5Hex(data + apiKey).toUpperCase();

改进:提取公共服务

@Component
public class SignatureService {public String sign(String data, String key) {return DigestUtils.sha256Hex(data + key).toUpperCase();}
}

总结

层级 指标 推荐阈值 主要危害
方法级 圈复杂度 ≤10 路径爆炸,难测试
嵌套深度 ≤3 可读性差
方法长度 ≤50 行 职责不清
类级 类长度 ≤500 行 上帝类风险
WMC ≤45 整体逻辑密度过高
CBO / Ce ≤7 耦合高,难维护
RFC ≤50 行为泛滥,测试难
LCOM 值越高越差 内聚不足,应拆分
继承级 DIT ≤3 行为隐式传递
NOC 不宜过大 抽象不充分
重复代码 DRY 不宜过多 不要重复自己

复杂度评估工具

要打赢复杂度战争,光靠人工 Code Review 远远不够。我们需要一套自动化的评估体系,在开发、提交、构建、部署的每个环节持续监控代码质量。

以下是目前 Java 生态中主流的复杂度评估方案与工具框架,它们可以单独使用,也可集成形成完整的质量门禁体系。

1. SonarQube:行业标准的静态分析平台

SonarQube 是目前最广泛使用的代码质量管理平台,支持对圈复杂度、重复率、代码坏味、测试覆盖率等指标进行可视化分析和阈值控制。

核心能力:

  • 自动计算每个方法的圈复杂度,并标记 >10 的热点
  • 检测重复代码块,支持跨文件识别
  • 提供“技术债”估算:修复所有问题需要多少人天
  • 支持 Quality Gate(质量门禁):CI 中断机制

集成方式:

<!-- Maven 配置示例 -->
<plugin><groupId>org.sonarsource.scanner.maven</groupId><artifactId>sonar-maven-plugin</artifactId><version>3.9.1.2184</version>
</plugin>

执行扫描:

mvn sonar:sonar \ -Dsonar.projectKey=my-app \ -Dsonar.host.url=http://localhost:9000 \ -Dsonar.login=your-token

推荐规则集:

  • cognitive-complexity:认知复杂度警告
  • nested-if-else-depth:嵌套深度检测
  • function-complexity:方法复杂度阈值
  • duplicated-blocks:重复代码告警

2. IntelliJ IDEA 内置分析工具

IntelliJ 提供了强大的本地静态分析功能,开发者无需离开 IDE 即可发现复杂度问题。

由于 IDEA 迭代很快,使用方式各位开发同学可以自行搜索,

优点:即时反馈,适合在编码阶段预防问题。

3. PMD 与 Checkstyle:轻量级静态检查工具

两者常配合使用,用于 CI/CD 流水线中的自动化检查。

PMD 特点:

  • 专注代码结构问题
  • 内建规则:ExcessiveMethodLength, CyclomaticComplexity, NestedIfDepth

具体使用方式不展开描述了,大家可以自行查阅。

4. ArchUnit:架构层面的依赖约束

ArchUnit 允许你用 Java 代码定义架构规则,防止模块间非法依赖。

5. GitHub Actions / Jenkins 集成:将复杂度检查纳入 CI

通过 CI 脚本自动运行分析工具,实现“不达标不合并”。

GitHub Actions 示例:

name: Code Quality
on: [push, pull_request]
jobs:sonar:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v3- name: Set up JDKuses: actions/setup-java@v3with:java-version: '17'- name: Run SonarQube Analysisrun: mvn verify sonar:sonar -Dsonar.qualitygate.wait=trueenv:SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

当质量门禁失败时,PR 将被阻断,强制开发者先修复问题。

总结

工具 适用场景 关键能力
SonarQube 团队级质量管控 可视化 + 质量门禁
IntelliJ 个人开发阶段 实时提示
PMD / Checkstyle CI 自动化检查 规则驱动
ArchUnit 架构治理 依赖断言
CI/CD 集成 流程卡点 强制合规

面向低复杂度的代码最佳实践

知道什么是复杂度还不够,关键是如何在日常编码中主动降低它。本着面向代码最佳实践的原则,尝试总结几条有效降低代码复杂的 Best Practise

原则一:单一职责

一个类或方法应该只做一件事。职责越清晰,修改影响面越小。

反例:多功能服务类

@Service
public class OrderService {public void createOrder() { /* 创建 */ }public void sendNotification() { /* 发送通知 */ }public void calculateReward() { /* 计算积分 */ }public void logAudit() { /* 写审计日志 */ }
}

这个类承担了订单生命周期的多个角色,任何变更都可能引发副作用。

改进:按职责拆分

@Service
public class OrderCreationService { ... }@Service
public class OrderNotificationService { ... }@Service
public class OrderRewardCalculationService { ... }

职责分离后,各模块可独立测试、演进。

原则二:优先组合,而非继承

继承容易导致深层类层次结构,增加理解和维护成本。组合更灵活、更可控。

反例:继承滥用

class BasePaymentProcessor { }
class AlipayProcessor extends BasePaymentProcessor { }
class WechatPayProcessor extends BasePaymentProcessor { }
class HybridAlipayProcessor extends AlipayProcessor { } // 多层继承

子类隐式继承父类行为,难以预测执行逻辑。

改进:使用策略模式 + 组合

public interface PaymentStrategy {PaymentResult pay(BigDecimal amount);
}@Service
public class AlipayStrategy implements PaymentStrategy { ... }@Service
public class WechatPayStrategy implements PaymentStrategy { ... }// 组合使用
public class UnifiedPaymentService {private final Map<String, PaymentStrategy> strategies;public UnifiedPaymentService(Map<String, PaymentStrategy> strategies) {this.strategies = strategies;}public PaymentResult pay(String type, BigDecimal amount) {return strategies.get(type).pay(amount);}
}

解耦清晰,扩展性强。

原则三:善用函数式编程减少状态污染

Java 8 引入的 OptionalStream 不仅是语法糖,更是对抗复杂度的利器。

反例:消除 null 嵌套判断

// 传统写法:多层 if 判断
if (user != null) {Cart cart = user.getCart();if (cart != null) {List<Item> items = cart.getItems();if (items != null && !items.isEmpty()) {return items.stream().map(Item::getPrice).reduce(BigDecimal::add).orElse(ZERO);}}
}
return ZERO;

改进:改为 Optional 链式调用

return Optional.ofNullable(user).map(User::getCart).map(Cart::getItems).filter(items -> !items.isEmpty()).flatMap(items -> items.stream().map(Item::getPrice).reduce(BigDecimal::add)).orElse(ZERO);

逻辑扁平化,无嵌套,可读性显著提升。

原则四:设计模式不是炫技,而是解耦武器

合理使用设计模式可以有效分解复杂逻辑,但切忌过度设计。

反例:if-else

// 反例:一堆 if-else
if ("alipay".equals(type)) {return alipayClient.pay(amount);
} else if ("wechat".equals(type)) {return wechatClient.pay(amount);
} else if ("unionpay".equals(type)) {return unionpayClient.pay(amount);
}

改进: 合理的设计模式

@Component
public class PaymentRouter {private final Map<String, PaymentClient> clients;public PaymentRouter(List<PaymentClient> clientList) {this.clients = clientList.stream().collect(Collectors.toMap(PaymentClient::getType, c -> c));}public PaymentResult pay(String type, BigDecimal amount) {PaymentClient client = clients.get(type);if (client == null) throw new UnsupportedPaymentTypeException(type);return client.pay(amount);}
}

新增支付方式只需实现接口并注册 Bean,无需修改路由逻辑。

原则五:命名即文档,好名字胜过千行注释

变量、方法、类的命名应准确传达其意图,避免缩写和模糊词汇。

反例:含义不明的数值枚举

public List<Order> getList(int status) { ... } // status 是什么?1 表示成功?

改进:明确的枚举

public List<Order> findOrdersByStatus(OrderStatus status) { ... }

再如:

// 不清楚用途
private boolean flag;// 明确语义
private boolean isEligibleForDiscount;

清晰的命名能让代码自解释,大幅降低理解成本。

原则六:防御性编程 + 清晰的错误处理

提前拦截非法输入,明确异常路径,避免静默失败。

正例:使用卫语句提前返回

public Order createOrder(CreateOrderRequest request) {if (request == null) {throw new IllegalArgumentException("Request cannot be null");}if (request.getItems() == null || request.getItems().isEmpty()) {throw new IllegalArgumentException("Order must have items");}// 正常逻辑开始……
}

正例:异常不要被吞掉

// 错误做法
catch (Exception e) {log.warn("Ignore error"); // 静默吞掉
}// 正确做法
catch (PaymentTimeoutException e) {log.error("Payment system timeout", e);throw new OrderCreationFailedException("Payment failed due to timeout", e);
}

确保异常传播路径清晰,便于定位问题。

小结:高质量代码的共同特征

原则 关键动作 效果
单一职责 拆分类与方法 降低变更风险
组合优于继承 使用接口 + 注入 提升灵活性
函数式思维 使用 Optional/Stream 减少嵌套
设计模式 策略、工厂、责任链 解耦复杂逻辑
清晰命名 表达业务意图 自解释代码
防御性编程 提前校验 + 明确异常 提高健壮性

这些原则不是教条,而是在长期实践中总结出的经验。坚持使用,你会发现自己写的代码越来越干净,系统也越来越稳健。

总结:坚持做正确的事

我们回顾一下最初的那几个问题:

  • 一个 catch (Exception e) 真的只是“防崩”吗?
  • 一段重复的签名逻辑,值得花几分钟复制粘贴吗?
  • 一个 2800 行的类,真的是“历史原因”无法改动吗?

答案从来都不是“代码本身有多难”,而是我们是否愿意为系统的长期健康付出短期成本

优秀的程序员不追求炫技式的“高复杂架构”,而是坚持写低复杂度、高表达力的代码。他们知道,可维护性才是系统最核心的非功能需求

工具可以帮助我们发现问题,原则可以指导我们重构代码,但最终,守护系统整洁的,是每一位工程师对质量的敬畏之心。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/953820.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

CSP2025 - S 年度总结大会报告

各大 oj 估分:洛谷:\(100+52+10+8=170\)。 小图灵:\(100+60+?+8=168+?\),当时他 \(T_3\) 数据还没有造。 梦熊:\(100+92+30+8=230\),感觉不准。自己估分:\(100+[48,70]+[0,40]+8=[156,218]\)。 第一:明确自己…

25CSP退役游记(11.1更新)

关于我在考虑要不要把S1的P话也加进来这件事 day—— -5 今天天气晴朗,不很像秋天,更不像济南今年的秋天。 考前焦虑期也是要休息的。它从一周之前来,从三四天之后来,这么算三个周能休七八天,比我的假期多多了。但…

第二章实践作业

第二章实践作业分治法找第 k 小的数:基础理解与思考 一、用分治法找第 k 小的数 找第 k 小的数,用分治法来解决其实思路还挺直观的。大概可以分成这几步: 先选一个 “基准数”,随便从数组里挑一个就行,比如选第一…

(补11月)代码大全阅读笔记2

第6-9章的架构设计内容,彻底解答了我长期以来的核心困惑:为何同样实现了基础功能的代码,有的在后续迭代中能轻松响应需求变化,有的却如同“牵一发而动全身”的乱麻,修改一个小功能就引发连锁bug。书中系统阐述的“…

java 基础语法一

java 基础语法一 一、基本概念 冯诺依曼结构,Java三大版本、编译型和解释型语言 1、五大组成部分:运算器、控制器、存储器、输入设备和输出设备;核心特点:采用二进制表示、存储程序原理、顺序执行指令 2、javaSE(…

VisualStudio 2022如何打开.slnx文件格式的解决方案

打开VisualStudio 2022,菜单中设置-选项-环境 > 预览功能 > 勾选最下方的“使用解决方案文件持久性模型”设置,再手动对.slnx文件进行关联设置即可。

(补11月)代码大全阅读笔记3

研读第23-25章关于测试与调试的内容后,我彻底摒弃了“开发负责写代码,测试负责找bug”的错误认知,建立起“开发者是质量第一责任人”的核心意识。书中一组数据让我尤为震撼:单元测试阶段发现并修复bug的成本,仅为…

CSP2025 - S 游记

Day -14 那天的模拟赛考得不错,拿了全校第二。 Day -13 太阳神开家长会骂了我们竞赛生。 心情不爽。 Day -11 晚上上厕所偶遇 xz,xz说我状态不错继续保持。 心情大好。 Day -7 集训,但是状态明显降低。 Day -5 没有…

CSP-S游记

CSP-S游记 首先读题,T1感觉直接贪心即可,T2应该不难,T3没想法,T4是计数我比较喜欢。 T1很快想出来代码也很好写20分钟过掉。 T2很容易想到 \(O(2^kn\log n)\) 的做法,但不确定能不能过就想优化把log去掉,想了一个…

小组作业1

小组作业1这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class12Grade23ComputerScience/这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class12Grade23ComputerScience/homework/13471姓名 学…

C语言字符串及其函数

字符串及其函数c语言 没有字符串类型,所以大多用字符数组代替。 1. 字符串的输入输出 使用 scanf 和 printf 的通用输入输出。 #include <stdio.h> #include <stdlib.h>/* run this program using the co…

CPULOAD建模设计

背景: 1.中断周期的建模 在单片机中中断和任务是两类处理数据的主要形式,中断的形式主要分为周期和时间两类。比如,LIN中断是根据调度表的周期去响应的,滚轮这种则是根据外部事件响应的。 2.响应时间的建模 中断的…

C 文件操作全解速览

文件操作文件分为二进制文件和文本文件,文本文件里面保存的内容形式是ASCII字符,二进制文件里面内容保存形式是01表示的。文件的主要作用是用来进行数据的持久化,能去长久的保存数据。这里f开头的文件操作命令,大多…

Java记录类:简化数据载体的新选择

Java 14引入的record类型为开发者提供了一种声明数据载体的简洁方式,有效减少了样板代码的编写。记录类旨在透明地保存不可变数据,自动实现数据访问方法和对象常用方法。 基本语法非常简单: public record User(Str…

第二次算法作业

基本思路 该算法采用分治策略来寻找数组中第k小的元素。首先从数组中随机选择一个基准元素,然后将数组划分为三个部分:小于基准的元素、等于基准的元素和大于基准的元素。根据k值所在的范围,决定在哪个子数组中继续…

NOIP 2025 游记 退役记

【洛谷专栏】 前言 前作:NOIP 2024 游记。 上一篇文章:CSP-S 2025 游记(The Last CSP ver.)。 同样地支持友链互挂,请私信。 CSP 结束了,可能没有冬令营机会了。 联赛,翻盘,还是,很难。 正文 2025.11 11.1 提…

一个万古常青的、小而美的输入法

一个万古常青的、小而美的输入法万古常青apt install fcitx-sunpinyin 即可安装。Ubuntu和Debian不倒,就一直有。美系统词库为libgooglepinyin和sunpinyin的合并去重版,词比它们都多。 用sunpinyin训练了字的三元语法…

开始学深度学习!

开始学深度学习!

LLaMA-Factory

LLaMA-Factory Used by Amazon, NVIDIA, Aliyun, etc.Supporters ❤️Warp, the agentic terminal for developersAvailable for MacOS, Linux, & WindowsEasily fine-tune 100+ large language models with zero-…

守护线程--daemon

线程可以分为用户线程与守护线程,虚拟机必须等待用户线程执行完毕但不用等待守护线程执行完毕 守护线程如:垃圾回收机制, 内存监控等 守护线程顾名思义,用于守护用户线程,下面举例介绍 public class Daemon {publ…