Communitygithub.com

Java编码规范

适用于Spring Boot和Quarkus服务的Java编码规范:涵盖命名、不可变性、Optional使用、流式处理、异常、泛型、CDI、响应式模式及项目布局。自动应用框架特定的约定。在编写或审查Spring Boot或Quarkus服务的Java代码时使用。

Java编码规范 是什么?

该技能为构建在Spring Boot或Quarkus上的Java(17+)服务提供了一套全面的编码标准。它根据构建文件(检测`quarkus`或`spring-boot`)自动检测框架,并应用相应约定。核心原则包括:优先使用不可变性、借助记录类和密封类实现类型安全、清晰且一致的命名风格、使用`Optional`(而非`null`)、遵循流式处理最佳实践以保持可读性、在Quarkus中使用`Uni`/`Multi`进行响应式编程,以及使用特定异常和集中式处理(Spring的`@RestControllerAdvice`或Quarkus的`ExceptionMapper`/`@ServerExceptionMapper`)来管理机构化异常处理。该技能还涵盖了依赖注入模式(Spring中推荐构造器注入,Quarkus中允许包级私有字段注入)、带`@ConfigMapping`(Quarkus)或`@ConfigurationProperties`(Spring)的配置管理、针对每个框架的日志记录策略(SLF4J对应Spring,JBoss Logging对应Quarkus),以及针对每个框架的测试期望(Spring Controller测试使用`@WebMvcTest`,Quarkus集成测试使用`@QuarkusTest`,普通JUnit 5用于单元测试)。它提供了通过/失败代码示例,以强化这些约定。该技能对开发人员非常有用,因为它通过消除歧义、确保Spring Boot和Quarkus代码库之间的一致性、通过类型安全模式减少运行时错误、以及通过标准化编码实践使代码更易于审查和维护,从而加速了开发。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/ECC/tree/main/skills/java-coding-standards

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Java编码规范 是做什么的?

适用于Spring Boot和Quarkus服务中可读、可维护的Java(17+)代码的规范。

何时使用

  • 在Spring Boot或Quarkus项目中编写或审查Java代码
  • 强制执行命名、不可变性或异常处理约定
  • 使用记录类、密封类或模式匹配(Java 17+)
  • 审查Optional、流式处理或泛型的使用
  • 组织包和项目结构
  • [QUARKUS]:处理CDI作用域、Panache实体或响应式管道

工作原理

框架检测

在应用规范前,根据构建文件确定框架:

  • 构建文件包含quarkus → 应用 [QUARKUS] 约定
  • 构建文件包含spring-boot → 应用 [SPRING] 约定
  • 两者均未检测到 → 仅应用共享约定

核心原则

  • 清晰胜于巧妙
  • 默认不可变;最小化共享可变状态
  • 快速失败并提供有意义的异常
  • 一致的命名和包结构
  • [QUARKUS]:优先编译时处理而非运行时处理;尽可能避免运行时反射

示例

以下各节展示了Spring Boot、Quarkus和共享Java在命名、不可变性、依赖注入、响应式代码、异常、项目布局、日志记录、配置和测试方面的具体示例。

命名

// PASS:类/记录:帕斯卡命名法
public class MarketService {}
public record Money(BigDecimal amount, Currency currency) {}

// PASS:方法/字段:驼峰命名法
private final MarketRepository marketRepository;
public Market findBySlug(String slug) {}

// PASS:常量:大写蛇形命名法
private static final int MAX_PAGE_SIZE = 100;

// PASS:[QUARKUS] JAX-RS资源命名为*Resource,而非*Controller
public class MarketResource {}

// PASS:[SPRING] REST控制器命名为*Controller
public class MarketController {}

不可变性

// PASS:优先使用记录类和final字段
public record MarketDto(Long id, String name, MarketStatus status) {}

public class Market {
  private final Long id;
  private final String name;
  // 仅有getter,无setter
}

// PASS:[QUARKUS] Panache活跃记录实体使用公有字段(Quarkus约定)
@Entity
public class Market extends PanacheEntity {
  public String name;
  public MarketStatus status;
  // Panache在构建时生成访问器;此处公有字段是惯用写法
}

// PASS:[QUARKUS] Panache MongoDB实体
@MongoEntity(collection = "markets")
public class Market extends PanacheMongoEntity {
  public String name;
  public MarketStatus status;
}

Optional使用

// PASS:在find*方法中返回Optional
// [SPRING]
Optional<Market> market = marketRepository.findBySlug(slug);

// [QUARKUS] Panache
Optional<Market> market = Market.find("slug", slug).firstResultOptional();

// PASS:使用map/flatMap代替get()
return market
    .map(MarketResponse::from)
    .orElseThrow(() -> new EntityNotFoundException("Market not found"));

流式处理最佳实践

// PASS:使用流进行转换,保持管道简短
List<String> names = markets.stream()
    .map(Market::name)
    .filter(Objects::nonNull)
    .toList();

// FAIL:避免复杂嵌套流;为清晰起见优先使用循环

依赖注入

// PASS:[SPRING] 构造器注入(优于@Autowired字段注入)
@Service
public class MarketService {
  private final MarketRepository marketRepository;

  public MarketService(MarketRepository marketRepository) {
    this.marketRepository = marketRepository;
  }
}

// PASS:[QUARKUS] 构造器注入
@ApplicationScoped
public class MarketService {
  private final MarketRepository marketRepository;

  @Inject
  public MarketService(MarketRepository marketRepository) {
    this.marketRepository = marketRepository;
  }
}

// PASS:[QUARKUS] 包级私有字段注入(在Quarkus中可接受——避免代理问题)
@ApplicationScoped
public class MarketService {
  @Inject
  MarketRepository marketRepository;
}

// FAIL:[SPRING] 使用@Autowired进行字段注入
@Autowired
private MarketRepository marketRepository; // 应使用构造器注入

// FAIL:[QUARKUS] 需要拦截或懒初始化时使用@Singleton
@Singleton // 不可代理——应改用@ApplicationScoped
public class MarketService {}

响应式模式 [QUARKUS]

// PASS:从响应式端点返回Uni/Multi
@GET
@Path("/{slug}")
public Uni<Market> findBySlug(@PathParam("slug") String slug) {
  return Market.find("slug", slug)
      .<Market>firstResult()
      .onItem().ifNull().failWith(() -> new MarketNotFoundException(slug));
}

// PASS:非阻塞管道组合
public Uni<OrderConfirmation> placeOrder(OrderRequest req) {
  return validateOrder(req)
      .chain(valid -> persistOrder(valid))
      .chain(order -> notifyFulfillment(order));
}

// FAIL:在Uni/Multi管道内进行阻塞调用
public Uni<Market> find(String slug) {
  Market m = Market.find("slug", slug).firstResult(); // 阻塞——破坏事件循环
  return Uni.createFrom().item(m);
}

// FAIL:对共享的Uni进行多次订阅
Uni<Market> shared = fetchMarket(slug);
shared.subscribe().with(m -> log(m));
shared.subscribe().with(m -> cache(m)); // 重复订阅——应使用Uni.memoize()

异常

  • 对领域错误使用非受检异常;用上下文包装技术异常
  • 创建领域特定异常(例如MarketNotFoundException)
  • 除非是集中重新抛出/记录日志,否则避免宽泛的catch (Exception ex)
throw new MarketNotFoundException(slug);

集中式异常处理

// [SPRING]
@RestControllerAdvice
public class GlobalExceptionHandler {
  @ExceptionHandler(MarketNotFoundException.class)
  public ResponseEntity<ErrorResponse> handle(MarketNotFoundException ex) {
    return ResponseEntity.status(404).body(ErrorResponse.from(ex));
  }
}

// [QUARKUS] 选项A:ExceptionMapper
@Provider
public class MarketNotFoundMapper implements ExceptionMapper<MarketNotFoundException> {
  @Override
  public Response toResponse(MarketNotFoundException ex) {
    return Response.status(404).entity(ErrorResponse.from(ex)).build();
  }
}

// [QUARKUS] 选项B:@ServerExceptionMapper(RESTEasy Reactive)
@ServerExceptionMapper
public RestResponse<ErrorResponse> handle(MarketNotFoundException ex) {
  return RestResponse.status(Status.NOT_FOUND, ErrorResponse.from(ex));
}

泛型和类型安全

  • 避免原始类型;声明泛型参数
  • 对可重用工具优先使用有界泛型
public <T extends Identifiable> Map<Long, T> indexById(Collection<T> items) { ... }

项目结构

[SPRING] Maven/Gradle

src/main/java/com/example/app/
  config/
  controller/
  service/
  repository/
  domain/
  dto/
  util/
src/main/resources/
  application.yml
src/test/java/...(与main镜像)

[QUARKUS] Maven/Gradle

src/main/java/com/example/app/
  config/              # @ConfigMapping、@ConfigProperty bean、Producers
  resource/            # JAX-RS资源(非"controller")
  service/
  repository/          # PanacheRepository实现(如未使用活跃记录)
  domain/              # JPA/Panache实体、MongoDB实体
  dto/
  util/
  mapper/              # MapStruct映射器(如使用)
src/main/resources/
  application.properties   # Quarkus约定(通过quarkus-config-yaml支持YAML)
  import.sql               # Hibernate开发/测试自动导入
src/test/java/...(与main镜像)

格式和风格

  • 一致使用2或4个空格(项目标准)
  • 每个文件一个公有顶级类型
  • 保持方法简短且专注;提取辅助方法
  • 成员顺序:常量、字段、构造器、公有方法、保护方法、私有方法

应避免的代码坏味

  • 长参数列表 → 使用DTO/构建器
  • 深层嵌套 → 提前返回
  • 魔术数字 → 命名常量
  • 静态可变状态 → 优先依赖注入
  • 静默捕获块 → 记录日志并处理或重新抛出
  • [QUARKUS]:应该使用@ApplicationScoped的地方使用了@Singleton——会破坏代理和拦截
  • [QUARKUS]:混用quarkus-resteasy-reactive和quarkus-resteasy(经典)——请选择一个堆栈
  • [QUARKUS]:在同一有界上下文中同时使用Panache活跃记录和仓库模式——请选择一个

日志记录

// [SPRING] SLF4J
private static final Logger log = LoggerFactory.getLogger(MarketService.class);
log.info("fetch_market slug={}", slug);
log.error("failed_fetch_market slug={}", slug, ex);

// [QUARKUS] JBoss Logging(默认,构建时零成本)
private static final Logger log = Logger.getLogger(MarketService.class);
log.infof("fetch_market slug=%s", slug);
log.errorf(ex, "failed_fetch_market slug=%s", slug);

// [QUARKUS] 替代方案:使用@Inject简化日志记录
@Inject
Logger log; // CDI注入,作用域限定于声明类

null处理

  • 仅在不可避免时接受@Nullable;否则使用@NonNull
  • 对输入使用Bean Validation(@NotNull、@NotBlank)
  • [QUARKUS]:对@BeanParam、@RestForm和请求体参数应用@Valid

配置

// [SPRING] @ConfigurationProperties
@ConfigurationProperties(prefix = "market")
public record MarketProperties(int maxPageSize, Duration cacheTtl) {}

// [QUARKUS] @ConfigMapping(类型安全,构建时验证)
@ConfigMapping(prefix = "market")
public interface MarketConfig {
  int maxPageSize();
  Duration cacheTtl();
}

// [QUARKUS] 通过@ConfigProperty使用简单值
@ConfigProperty(name = "market.max-page-size", defaultValue = "100")
int maxPageSize;

测试期望

共享

  • JUnit 5 + AssertJ用于流畅断言
  • Mockito用于模拟;尽可能避免部分模拟
  • 优先确定性测试;不要使用隐藏的sleep

[SPRING]

  • @WebMvcTest用于控制器切片,@DataJpaTest用于仓库切片
  • @SpringBootTest保留用于完整集成测试
  • @MockBean用于在Spring上下文中替换bean

[QUARKUS]

  • 普通JUnit 5 + Mockito用于单元测试(无@QuarkusTest)
  • @QuarkusTest保留用于CDI集成测试
  • @InjectMock用于在集成测试中替换CDI bean
  • Dev Services用于数据库/Kafka/Redis——在Dev Services足够时避免手动Testcontainers配置
  • @QuarkusTestResource用于自定义外部服务生命周期
// [SPRING] 控制器测试
@WebMvcTest(MarketController.class)
class MarketControllerTest {
  @Autowired MockMvc mockMvc;
  @MockBean MarketService marketService;
}

// [QUARKUS] 集成测试
@QuarkusTest
class MarketResourceTest {
  @InjectMock
  MarketService marketService;

  @Test
  void should_return_404_when_market_not_found() {
    given().when().get("/markets/unknown").then().statusCode(404);
  }
}

// [QUARKUS] 单元测试(无CDI,无@QuarkusTest)
@ExtendWith(MockitoExtension.class)
class MarketServiceTest {
  @Mock MarketRepository marketRepository;
  @InjectMocks MarketService marketService;
}

记住:保持代码有意图、类型化且可观察。优先考虑可维护性而非微优化,除非已证明有必要。

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/content-engine

Create platform-native content systems for X, LinkedIn, TikTok, YouTube, newsletters, and repurposed multi-platform campaigns. Use when the user wants social posts, threads, scripts, content calendars, or one source asset adapted cleanly across platforms.

affaan-m/ECC

Multi-platform content distribution across X, LinkedIn, Threads, and Bluesky. Adapts content per platform using content-engine patterns. Never posts identical content cross-platform. Use when the user wants to distribute content across social platforms.

affaan-m/fal-ai-media

Unified media generation via fal.ai MCP — image, video, and audio. Covers text-to-image (Nano Banana), text/image-to-video (Seedance, Kling, Veo 3), text-to-speech (CSM-1B), and video-to-audio (ThinkSound). Use when the user wants to generate images, videos, or audio with AI.

affaan-m/manim-video

日本語翻訳:このファイルは manim-video 用の日本語翻訳が必要です

affaan-m/remotion-video-creation

Remotion のベストプラクティス - React で動画を作成する。3D、アニメーション、音声、字幕、チャート、トランジションなどをカバーするドメイン固有の29のルール。

affaan-m/video-editing

AI-assisted video editing workflows for cutting, structuring, and augmenting real footage. Covers the full pipeline from raw capture through FFmpeg, Remotion, ElevenLabs, fal.ai, and final polish in Descript or CapCut. Use when the user wants to edit video, cut footage, create vlogs, or build video content.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

agent-self-evaluation

Use after completing any non-trivial task. The agent self-rates its output on 5 axes — accuracy, completeness, clarity, actionability, conciseness — with concrete evidence per criterion. Produces a structured 1-5 scorecard with specific improvement suggestions.

agent-sort

Build an evidence-backed ECC install plan for a specific repo by sorting skills, commands, rules, hooks, and extras into DAILY vs LIBRARY buckets using parallel repo-aware review passes. Use when ECC should be trimmed to what a project actually needs instead of loading the full bundle.

ai-first-engineering

Engineering operating model for teams where AI agents generate a large share of implementation output. Use when setting team process, review gates, or ownership rules for a codebase largely written by agents.

ai-regression-testing

Regression testing strategies for AI-assisted development. Sandbox-mode API testing without database dependencies, automated bug-check workflows, and patterns to catch AI blind spots where the same model writes and reviews code. Use when adding regression coverage to AI-assisted code, or when the same model both wrote and reviewed a change.

android-clean-architecture

Clean Architecture patterns for Android and Kotlin Multiplatform projects — module structure, dependency rules, UseCases, Repositories, and data layer patterns. Use when structuring modules, layers, or data flow in an Android or KMP project.

angular-developer

Generates Angular code and provides architectural guidance. Trigger when creating projects, components, or services, or for best practices on reactivity (signals, linkedSignal, resource), forms, dependency injection, routing, SSR, accessibility (ARIA), animations, styling (component styles, Tailwind CSS), testing, or CLI tooling.

相关技能