程式碼風格

我們遵循 Google’s Java Style Guidelines 以及一些補充與更動,詳述於下。

小訣竅

你可以在 Eclipse 或 IntelliJ IDEA 上使用我们的代码样式来让你的 IDE 正确格式化代码。详情可以查看 ` Sponge 代码样式<https://github.com/SpongePowered/SpongeAPI/tree/api-8/extra>`_.

  • 行尾

    • 在提交時使用 Unix 行尾(\n)

      • Windows 的 Git 使用者可以用 git config --global core.autocrlf true 來讓 Git 進行自動轉換

  • 欄寬

    • Javadocs:80字元

    • 程式碼:150字元

    • 若對可讀性有所助益,請自由換行

  • 縮排

    • 使用4個空格來縮排,不要只用2個空格

  • 空行

    • 在 class、interface、enum 等宣告的第一個成員之前(例如在 class Example { 之後)以及在最後一個成員之後放置一個空行

  • 檔頭

    • 檔頭必須包含專案的授權協議標頭。使用 updateLicenses Gradle 任務來自動添加。

  • Import

    • Import 必須按照以下順序進行分組,每組之間由一個空行分隔

      • Static import

      • 所有其他 import

      • java import

      • javax import

    • 這與Google的風格不同,因為 import 不是按照 top-level package 分組的,它們都被分在同一個組。

  • 例外

    • 對於要被忽略的例外,將例外變數命名為 ignored

  • 屬性存取

    • 使用 this 存取 所有的 欄位(Field)

  • Javadocs

    • 不要使用 @author

    • 將額外段落包進 <p></p>

    • 在每個「@子句」內的描述中,首字母大寫,即 @param name Player to affect ,不要有句號

  • 檔案結尾

    • 每個檔案的結尾應有一行空白行

程式碼慣例

  • 使用 Optionals 而不是在 API 中回傳 null

  • 接受 null 的方法參數必須註解為 @Nullable (來自 javax.*),預設所有的方法和參數都是 @Nonnull

  • API:使用 java.util.Objects.requireNonNull 进行空值检查,ifs 进行参数检查。

  • 实现:使用 Google Preconditions 进行空值及参数检查。

Gist

雖然我們強烈建議您閱讀 Google 的 Java 慣例,但這兩份文件都相當長。 為了讓您快速入門,下面是格式正確的程式碼範例:

/*
* This file is part of Sponge, licensed under the MIT License (MIT).
*
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.spongepowered.example;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.inject.Inject;
import org.slf4j.Logger;

import java.util.Optional;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;

import javax.annotation.Nullable;

/**
* An example class which generates a new ID based on a specified base string
* and a randomly generated integer.
*
* <p>There is a chance the integer purposely fails to generate, in which case
* you can choose to provide a backup integer.</p>
*/
public class Example {

    private static final long SEED = 4815162342L;

    @Inject
    private Logger logger;

    private final String base;
    private final Random random;

    public Example(String base) {
        checkNotNull(base, "The specified base string cannot be null!");
        this.base = base;
        this.random = ThreadLocalRandom.current();
        this.random.setSeed(SEED);
    }

    /**
    * Generates and returns an ID using the base string specified on creation
    * or the alternative string if specified as well as a randomly generated
    * integer, which purposely fails to generate around 50% of the time.
    *
    * <p>A {@link ThreadLocalRandom} is used to check if the integer should
    * be generated and generates the integer itself if so.</p>
    *
    * @param alternate An alternate base string which will be used if not null
    * @return The generated ID, if available
    */
    public Optional<String> generateId(@Nullable String alternate) {
        if (this.random.nextBoolean()) {
            return Optional.of(alternate == null ? this.base : alternate + " - " + this.random.nextInt());
        }

        return Optional.empty();
    }

    /**
    * Generates and returns an ID using the base string specified on creation,
    * using a randomly generated integer if it was generated successfully, or
    * using the backup integer you specify.
    *
    * <p>A {@link ThreadLocalRandom} is used to check if the integer should
    * be generated and generates the integer itself if so. If it was not
    * generated, that is when your backup integer will be used.</p>
    *
    * @param backup A backup integer to use to create the ID with
    * @return The generated ID using the generated integer or the ID created
    *     using the backup integer specified
    */
    public String generateId(int backup) {
        return generateId(null).orElse(this.base + " - " + backup);
    }

}