java-coding-guideline

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Java Coding Guideline

Java编码规范

CRITICAL: These rules apply to ALL Java code unless explicitly overridden by more specific skills.
重要提示:除非被更具体的规则明确覆盖,否则这些规则适用于所有Java代码。

Import Statements

导入语句

Always use explicit imports without wildcards for better code clarity and maintainability.
始终使用显式导入,避免使用通配符,以提升代码的清晰度和可维护性。

✅ Do

✅ 正确做法

java
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
java
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;

❌ Don't

❌ 错误做法

java
import static org.assertj.core.api.Assertions.*;

java
import static org.assertj.core.api.Assertions.*;

Vertical Spacing (Readability)

垂直间距(可读性)

Use consistent vertical spacing inside classes to make diffs smaller and code easier to scan.
在类内部使用一致的垂直间距,以减少差异对比的复杂度并提升代码的易读性。

Rule

规则

  • Insert exactly one blank line between:
    • field blocks and the next field block (when grouped)
    • fields and the first constructor
    • constructors and methods
    • methods and the next method
  • Also insert one blank line right after the opening
    {
    of a class (before the first field/initializer), unless the class is intentionally empty.
  • 在以下内容之间插入恰好一个空行
    • 分组的字段块与下一个字段块之间
    • 字段与第一个构造方法之间
    • 构造方法与方法之间
    • 方法与下一个方法之间
  • 除非类是有意设计为空的,否则在类的左大括号
    {
    之后(第一个字段/初始化器之前)也插入一个空行

✅ Do

✅ 正确做法

java
public final class SomeClass {

    @NonNull
    private final String fieldA;

    @NonNull
    private final String fieldB;

    public void someFunc() {
        // some action
    }

    public String getFieldA() {
        return fieldA;
    }
}
java
public final class SomeClass {

    @NonNull
    private final String fieldA;

    @NonNull
    private final String fieldB;

    public void someFunc() {
        // some action
    }

    public String getFieldA() {
        return fieldA;
    }
}

❌ Don't

❌ 错误做法

java
public final class SomeClass {
    @NonNull
    private final String fieldA;
    @NonNull
    private final String fieldB;
    public void someFunc() {
        // some action
    }
    public String getFieldA() {
        return fieldA;
    }
}
java
public final class SomeClass {
    @NonNull
    private final String fieldA;
    @NonNull
    private final String fieldB;
    public void someFunc() {
        // some action
    }
    public String getFieldA() {
        return fieldA;
    }
}

Constructors

构造方法

Use a single primary constructor and delegate auxiliary constructors using
this()
.
使用单个主构造方法,辅助构造方法通过
this()
委托调用主构造方法。

✅ Do

✅ 正确做法

java
public final class SomeClass {

    private final int field1;
    private final int field2;

    public SomeClass() {
        this(1, 2);
    }

    public SomeClass(int field1, int field2) {
         this.field1 = field1;
         this.field2 = field2;
    }
}
java
public final class SomeClass {

    private final int field1;
    private final int field2;

    public SomeClass() {
        this(1, 2);
    }

    public SomeClass(int field1, int field2) {
         this.field1 = field1;
         this.field2 = field2;
    }
}

❌ Don't

❌ 错误做法

java
public final class SomeClass {

    private final int field1;
    private final int field2;

    public SomeClass() {
        this.field1 = 1;
        this.field2 = 2;
    }

    public SomeClass(int field1, int field2) {
         this.field1 = field1;
         this.field2 = field2;
    }
}

java
public final class SomeClass {

    private final int field1;
    private final int field2;

    public SomeClass() {
        this.field1 = 1;
        this.field2 = 2;
    }

    public SomeClass(int field1, int field2) {
         this.field1 = field1;
         this.field2 = field2;
    }
}

Optional Usage

Optional使用

Avoid using
Optional
as return values or parameters. Use
@Nullable
annotations instead.
避免将
Optional
作为返回值或参数类型。改用
@Nullable
注解。

✅ Do

✅ 正确做法

java
public final class SomeClass {

    @Nullable
    public Integer someNullable() {
        if (something) return null;
        return 1;
    }

    public void func(@Nullable Integer param) {
        // do something
    }
}
java
public final class SomeClass {

    @Nullable
    public Integer someNullable() {
        if (something) return null;
        return 1;
    }

    public void func(@Nullable Integer param) {
        // do something
    }
}

❌ Don't

❌ 错误做法

java
public final class SomeClass {

    @NonNull
    public Optional<Integer> someNullable() {
        if (something) return Optional.ofNullable(null);
        return Optional.ofNullable(1);
    }

    public void func(@NonNull Optional<Integer> param) {
        // do something
    }
}

java
public final class SomeClass {

    @NonNull
    public Optional<Integer> someNullable() {
        if (something) return Optional.ofNullable(null);
        return Optional.ofNullable(1);
    }

    public void func(@NonNull Optional<Integer> param) {
        // do something
    }
}

Wrapper vs Primitive Types

包装类型与基本类型

  • Use wrapper types when
    null
    is expected
  • Use primitive types when
    null
    should not occur
  • 当可能出现
    null
    时使用包装类型
  • 当不应该出现
    null
    时使用基本类型

✅ Do

✅ 正确做法

java
public final class SomeClass {

    private final int field1;

    @Nullable
    private final Long field2;

    public SomeClass(int field1, @Nullable Long field2) {
        this.field1 = field1;
        this.field2 = field2;
    }
}
java
public final class SomeClass {

    private final int field1;

    @Nullable
    private final Long field2;

    public SomeClass(int field1, @Nullable Long field2) {
        this.field1 = field1;
        this.field2 = field2;
    }
}

❌ Don't

❌ 错误做法

java
public final class SomeClass {

    @NonNull
    private final Integer field1;

    @Nullable
    private final Long field2;

    public SomeClass(@NonNull Integer field1, @Nullable Long field2) {
        this.field1 = field1;
        this.field2 = field2;
    }
}

java
public final class SomeClass {

    @NonNull
    private final Integer field1;

    @Nullable
    private final Long field2;

    public SomeClass(@NonNull Integer field1, @Nullable Long field2) {
        this.field1 = field1;
        this.field2 = field2;
    }
}

Null Comparison

空值比较

  • Use
    A == null
    for general cases
  • Use
    Objects.isNull
    for Stream API or functional programming contexts
  • 一般情况下使用
    A == null
  • 在Stream API或函数式编程场景下使用
    Objects.isNull

✅ Do

✅ 正确做法

java
final Integer someVariable = null;

if (someVariable == null) {
    // do something
}

List<Integer> lists = new ArrayList<>();
lists.stream()
  .filter(Objects::isNull)
  .collect(Collectors.toList());
java
final Integer someVariable = null;

if (someVariable == null) {
    // do something
}

List<Integer> lists = new ArrayList<>();
lists.stream()
  .filter(Objects::isNull)
  .collect(Collectors.toList());

❌ Don't

❌ 错误做法

java
final Integer someVariable = null;

if (Objects.isNull(someVariable)) {
    // do something
}

List<Integer> lists = new ArrayList<>();
lists.stream()
  .filter(p -> p == null)
  .collect(Collectors.toList());

java
final Integer someVariable = null;

if (Objects.isNull(someVariable)) {
    // do something
}

List<Integer> lists = new ArrayList<>();
lists.stream()
  .filter(p -> p == null)
  .collect(Collectors.toList());

Nullability Annotations

空值注解

  • Use JSpecify annotations
  • Apply
    @Nullable
    and
    @NonNull
    to all methods including private ones
  • Avoid class-level or package-level annotations (Lombok compatibility issues)
  • 使用JSpecify注解
  • 为所有方法(包括私有方法)添加
    @Nullable
    @NonNull
    注解
  • 避免使用类级或包级注解(存在Lombok兼容性问题)

✅ Do

✅ 正确做法

java
public final class SomeClass {

    @Nullable
    private final Integer field1;

    @NonNull
    private final String field2;

    @NonNull
    public String func() {
        return process();
    }

    @Nullable
    private String process() {
        if (field1 == null) return null;
        return "awesome";
    }
}
java
public final class SomeClass {

    @Nullable
    private final Integer field1;

    @NonNull
    private final String field2;

    @NonNull
    public String func() {
        return process();
    }

    @Nullable
    private String process() {
        if (field1 == null) return null;
        return "awesome";
    }
}

❌ Don't

❌ 错误做法

java
public final class SomeClass {

    private final Integer field1;
    private final String field2;

    public String func() {
        return process();
    }

    private String process() {
        if (field1 == null) return null;
        return "awesome";
    }
}

java
public final class SomeClass {

    private final Integer field1;
    private final String field2;

    public String func() {
        return process();
    }

    private String process() {
        if (field1 == null) return null;
        return "awesome";
    }
}

Package Naming

包命名

Use all lowercase and numbers only, following Google Java Style Guide conventions.
仅使用小写字母和数字,遵循Google Java风格指南的约定。

✅ Do

✅ 正确做法

java
package com.example.project.initscript;
java
package com.example.project.initscript;

❌ Don't

❌ 错误做法

java
package com.example.project.initScript;

java
package com.example.project.initScript;

Static Factory Methods

静态工厂方法

Use only
of
naming convention. For multiple types, use format
of<Postfix>
.
仅使用
of
命名约定。对于多种类型,使用
of<后缀>
的格式。

✅ Do

✅ 正确做法

java
public final class SomeClass {

    private final int field1;

    private SomeClass(int field1) {
        this.field1 = field1;
    }

    public static SomeClass ofDefault() {
        return new SomeClass(1);
    }

    public static SomeClass ofSpecial() {
        return new SomeClass(2);
    }
}
java
public final class SomeClass {

    private final int field1;

    private SomeClass(int field1) {
        this.field1 = field1;
    }

    public static SomeClass ofDefault() {
        return new SomeClass(1);
    }

    public static SomeClass ofSpecial() {
        return new SomeClass(2);
    }
}

❌ Don't

❌ 错误做法

java
public final class SomeClass {

    private final int field1;

    private SomeClass(int field1) {
        this.field1 = field1;
    }

    public static SomeClass from() {
        return new SomeClass(1);
    }

    public static SomeClass valueOf() {
        return new SomeClass(2);
    }
}
java
public final class SomeClass {

    private final int field1;

    private SomeClass(int field1) {
        this.field1 = field1;
    }

    public static SomeClass from() {
        return new SomeClass(1);
    }

    public static SomeClass valueOf() {
        return new SomeClass(2);
    }
}

Resource Management

资源管理

Always use try-with-resources for
AutoCloseable
resources. Never rely on finalizers.
对于
AutoCloseable
资源,始终使用try-with-resources。永远不要依赖finalizer方法。

Try-With-Resources

Try-With-Resources

✅ Do

✅ 正确做法

java
public String readFile(@NonNull Path path) throws IOException {
    try (var reader = Files.newBufferedReader(path)) {
        return reader.lines().collect(Collectors.joining("\n"));
    }
}

// Multiple resources
public void copyStream(@NonNull InputStream in, @NonNull OutputStream out) throws IOException {
    try (in; out) {  // Java 9+: can use already-declared variables
        in.transferTo(out);
    }
}
java
public String readFile(@NonNull Path path) throws IOException {
    try (var reader = Files.newBufferedReader(path)) {
        return reader.lines().collect(Collectors.joining("\n"));
    }
}

// Multiple resources
public void copyStream(@NonNull InputStream in, @NonNull OutputStream out) throws IOException {
    try (in; out) {  // Java 9+: can use already-declared variables
        in.transferTo(out);
    }
}

❌ Don't

❌ 错误做法

java
public String readFile(@NonNull Path path) throws IOException {
    BufferedReader reader = Files.newBufferedReader(path);
    try {
        return reader.lines().collect(Collectors.joining("\n"));
    } finally {
        reader.close();  // The original exception may be suppressed if one occurs here
    }
}

java
public String readFile(@NonNull Path path) throws IOException {
    BufferedReader reader = Files.newBufferedReader(path);
    try {
        return reader.lines().collect(Collectors.joining("\n"));
    } finally {
        reader.close();  // The original exception may be suppressed if one occurs here
    }
}

Composition over Inheritance

组合优于继承

Prefer composition over inheritance.
优先使用组合而非继承。

✅ Do

✅ 正确做法

java
public final class SomeFeature {
    public void func() { /* ... */ }
}

public final class SomeClass {

    private final SomeFeature feature;

    public void func2() {
        feature.func();
        // do something
    }
}
java
public final class SomeFeature {
    public void func() { /* ... */ }
}

public final class SomeClass {

    private final SomeFeature feature;

    public void func2() {
        feature.func();
        // do something
    }
}

❌ Don't

❌ 错误做法

java
public class SomeFeature {
    public void func() { /* ... */ }
}

public final class SomeClass extends SomeFeature {

    public void func2() {
        super.func();
        // do something
    }
}

java
public class SomeFeature {
    public void func() { /* ... */ }
}

public final class SomeClass extends SomeFeature {

    public void func2() {
        super.func();
        // do something
    }
}

Immutable Objects

不可变对象

All objects should use
final
keyword unless needed for extension or framework requirements.
除非因扩展或框架要求需要,否则所有对象都应使用
final
关键字。

✅ Do

✅ 正确做法

java
public final class SomeClass {
    // ...
}
java
public final class SomeClass {
    // ...
}

❌ Don't

❌ 错误做法

java
public class SomeClass {
    // ...
}

java
public class SomeClass {
    // ...
}

Exception Catching

异常捕获

Catch only the minimum necessary exceptions.
仅捕获必要的最少异常。

✅ Do

✅ 正确做法

java
try {
    // do something
} catch (IllegalArgumentException e) {
    // do catch
}
java
try {
    // do something
} catch (IllegalArgumentException e) {
    // do catch
}

❌ Don't

❌ 错误做法

java
try {
    // do something
} catch (RuntimeException e) {
    // do catch
}
java
try {
    // do something
} catch (RuntimeException e) {
    // do catch
}

Implementing AutoCloseable

实现AutoCloseable

When implementing
AutoCloseable
:
  1. Make
    close()
    idempotent (safe to call multiple times)
  2. Never throw exceptions from
    close()
    (suppressed exceptions problem)
  3. Log errors instead of throwing them
实现
AutoCloseable
时:
  1. 确保
    close()
    方法是幂等的(多次调用安全)
  2. 永远不要从
    close()
    抛出异常
    (存在异常被抑制的问题)
  3. 记录错误而非抛出异常

✅ Do

✅ 正确做法

java
public final class DatabaseConnection implements AutoCloseable {

    @NonNull
    private final Connection connection;

    private volatile boolean closed = false;

    @Override
    public void close() {
        if (closed) return;  // Idempotent: safe to call multiple times

        closed = true;
        try {
            connection.close();
        } catch (SQLException e) {
            // Log only; do not throw (exceptions in close can suppress the original)
            logger.warn("Failed to close connection", e);
        }
    }
}
java
public final class DatabaseConnection implements AutoCloseable {

    @NonNull
    private final Connection connection;

    private volatile boolean closed = false;

    @Override
    public void close() {
        if (closed) return;  // Idempotent: safe to call multiple times

        closed = true;
        try {
            connection.close();
        } catch (SQLException e) {
            // Log only; do not throw (exceptions in close can suppress the original)
            logger.warn("Failed to close connection", e);
        }
    }
}

❌ Don't

❌ 错误做法

java
public final class DatabaseConnection implements AutoCloseable {

    @NonNull
    private final Connection connection;

    @Override
    public void close() throws SQLException {
        connection.close();  // Not idempotent; exception propagates
    }
}

java
public final class DatabaseConnection implements AutoCloseable {

    @NonNull
    private final Connection connection;

    @Override
    public void close() throws SQLException {
        connection.close();  // Not idempotent; exception propagates
    }
}

Date/Time API

日期/时间API

Use
java.time
(JSR-310) exclusively.
java.util.Date
and
java.util.Calendar
are banned in new code.
仅使用
java.time
(JSR-310)。在新代码中禁止使用
java.util.Date
java.util.Calendar

Type Selection

类型选择

Use CaseTypeExample
Storage/transfer (UTC)
Instant
API timestamps, DB storage
User display
ZonedDateTime
Time shown in UI
Date only
LocalDate
Birthdays, expiration dates
Time only
LocalTime
Business hours, alarms
Duration
Duration
/
Period
Elapsed time, date differences
使用场景类型示例
存储/传输(UTC)
Instant
API时间戳、数据库存储
用户展示
ZonedDateTime
UI中显示的时间
仅日期
LocalDate
生日、到期日
仅时间
LocalTime
营业时间、闹钟
时长
Duration
/
Period
经过的时间、日期差

✅ Do

✅ 正确做法

java
public final class Event {

    @NonNull
    private final Instant createdAt;  // UTC timestamp

    @NonNull
    private final LocalDate eventDate;  // Date only

    @NonNull
    private final ZoneId timeZone;  // Display time zone

    @NonNull
    public ZonedDateTime displayTime() {
        return createdAt.atZone(timeZone);
    }
}
Formatter reuse (thread-safe):
java
public final class DateFormats {

    // DateTimeFormatter is thread-safe, so reuse as constants
    public static final DateTimeFormatter ISO_DATE = DateTimeFormatter.ISO_LOCAL_DATE;

    public static final DateTimeFormatter ENGLISH_DATE = DateTimeFormatter.ofPattern("MMM dd, yyyy");

    private DateFormats() {}
}
java
public final class Event {

    @NonNull
    private final Instant createdAt;  // UTC timestamp

    @NonNull
    private final LocalDate eventDate;  // Date only

    @NonNull
    private final ZoneId timeZone;  // Display time zone

    @NonNull
    public ZonedDateTime displayTime() {
        return createdAt.atZone(timeZone);
    }
}
格式化器复用(线程安全):
java
public final class DateFormats {

    // DateTimeFormatter is thread-safe, so reuse as constants
    public static final DateTimeFormatter ISO_DATE = DateTimeFormatter.ISO_LOCAL_DATE;

    public static final DateTimeFormatter ENGLISH_DATE = DateTimeFormatter.ofPattern("MMM dd, yyyy");

    private DateFormats() {}
}

❌ Don't

❌ 错误做法

java
public final class Event {

    @NonNull
    private final Date createdAt;  // Do not use java.util.Date

    @NonNull
    private final Calendar calendar;  // Do not use java.util.Calendar

    @NonNull
    public String format() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");  // Not thread-safe
        return sdf.format(createdAt);
    }
}
java
public final class Event {

    @NonNull
    private final Date createdAt;  // Do not use java.util.Date

    @NonNull
    private final Calendar calendar;  // Do not use java.util.Calendar

    @NonNull
    public String format() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");  // Not thread-safe
        return sdf.format(createdAt);
    }
}

Legacy Interop (boundary only)

遗留代码互操作(仅在边界层)

When interfacing with legacy APIs that require
Date
, convert at the boundary:
java
// Instant → Date (boundary layer only)
Date legacyDate = Date.from(instant);

// Date → Instant (convert immediately on receipt)
Instant instant = legacyDate.toInstant();

当与需要
Date
的遗留API交互时,仅在边界层进行转换:
java
// Instant → Date (boundary layer only)
Date legacyDate = Date.from(instant);

// Date → Instant (convert immediately on receipt)
Instant instant = legacyDate.toInstant();

Additional Guidelines

其他规范

Builder Pattern

建造者模式

Use Lombok-style builders for API consistency.
使用Lombok风格的建造者以保证API一致性。

Variable and Method Naming

变量与方法命名

  • Use
    var
    keyword from JVM 10+
  • Use meaningful variable names
    • But avoid too long variable, function, field names
  • Method names should be verbs
  • Avoid using 'get' prefix except for getters
  • 从JVM 10+开始使用
    var
    关键字
  • 使用有意义的变量名
    • 但避免过长的变量、函数、字段名
  • 方法名应为动词
  • 除了getter方法,避免使用'get'前缀

Camel Case Convention

驼峰命名约定

Apply camel case to mixed-case words and abbreviations (e.g., "MultiNIC" becomes "MultiNic").
对混合大小写的单词和缩写应用驼峰命名法(例如,"MultiNIC"应改为"MultiNic")。

Control Flow Statements

控制流语句

Use one-liner syntax for simple if statements without braces.
对于简单的if语句,使用无大括号的单行语法。

✅ Do

✅ 正确做法

java
if (someCondition) doSomething();
java
if (someCondition) doSomething();

❌ Don't

❌ 错误做法

java
if (someCondition) {
    doSomething();
}
java
if (someCondition) {
    doSomething();
}

Comments

注释

  • Use comments only in special cases
  • TODO comments should be for immediate tasks
  • Avoid unnecessary comments that restate the code

  • 仅在特殊情况下使用注释
  • TODO注释应针对即时任务
  • 避免添加重复代码含义的不必要注释

See Also

另请参阅

Reference Guides

参考指南

For deeper understanding of specific topics:
  • references/async.md - CompletableFuture and async programming patterns
  • references/javadoc.md - Javadoc conventions and exception documentation
  • references/lombok.md - Allowed and banned Lombok annotations
  • references/security-resources.md - Security best practices, password handling, SQL injection prevention, PII masking
如需深入了解特定主题:
  • references/async.md - CompletableFuture与异步编程模式
  • references/javadoc.md - Javadoc规范与异常文档
  • references/lombok.md - 允许和禁止使用的Lombok注解
  • references/security-resources.md - 安全最佳实践、密码处理、SQL注入防护、PII掩码