コントリビューター向けの AOSP Java コード スタイル

コレクションでコンテンツを整理 必要に応じて、コンテンツの保存と分類を行います。

このページのコード スタイルは、Java コードを Android オープン ソース プロジェクト (AOSP) に提供するための厳格なルールです。これらの規則に従わない Android プラットフォームへの投稿は、通常は受け付けられません。すべての既存のコードがこれらの規則に従っているわけではないことは認識していますが、すべての新しいコードが準拠することを期待しています。より包括的なエコシステムのために使用および回避する用語の例については、コーディングを尊重するを参照してください。

一貫性を保つ

最も単純なルールの 1 つは、BE CONSISTENT です。コードを編集している場合は、数分かけて周囲のコードを確認し、そのスタイルを判断してください。そのコードでif句の前後にスペースが使用されている場合は、スペースも使用する必要があります。コード コメントの周囲に星の小さなボックスがある場合は、コメントにも星の小さなボックスを配置します。

スタイル ガイドラインを持つことのポイントは、コーディングの共通語彙を持つことです。これにより、読者は、あなたがどのように言っているのかではなく、あなたが言っていることに集中することができます。ここでは語彙を理解できるようにグローバル スタイルのルールを示しますが、ローカル スタイルも重要です。ファイルに追加するコードが既存のコードと大幅に異なる場合、読者はそれを読むときにリズムを崩してしまいます。これを避けるようにしてください。

Java 言語の規則

Android は、標準の Java コーディング規約に従い、以下に説明する追加のルールを適用します。

例外を無視しない

次のような例外を無視するコードを書きたくなることがあります。

  void setServerPort(String value) {
      try {
          serverPort = Integer.parseInt(value);
      } catch (NumberFormatException e) { }
  }

これをしないでください。コードがこのエラー状態に遭遇することは決してない、またはそれを処理することが重要ではないと考えるかもしれませんが、このタイプの例外を無視すると、コード内に地雷が作成され、他の誰かがいつかトリガーする可能性があります。コード内のすべての例外を原則的な方法で処理する必要があります。具体的な取り扱いはケースによって異なります。

"誰かが空の catch 句を持っているときはいつでも、不気味な気持ちになるはずです。それが実際に正しいことであることは間違いありませんが、少なくともそれについて考える必要があります。Java では、不気味な気持ちから逃れることはできません。 」 —ジェームズ・ゴズリング

受け入れ可能な代替案 (優先順) は次のとおりです。

  • メソッドの呼び出し元まで例外をスローします。
      void setServerPort(String value) throws NumberFormatException {
          serverPort = Integer.parseInt(value);
      }
    
  • 抽象化のレベルに適した新しい例外をスローします。
      void setServerPort(String value) throws ConfigurationException {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new ConfigurationException("Port " + value + " is not valid.");
        }
      }
    
  • エラーを適切に処理し、 catch {}ブロックで適切な値に置き換えます。
      /** Set port. If value is not a valid number, 80 is substituted. */
    
      void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            serverPort = 80;  // default port for server
        }
      }
    
  • 例外をキャッチし、 RuntimeExceptionの新しいインスタンスをスローします。これは危険なので、このエラーが発生した場合にクラッシュするのが適切であると確信できる場合にのみ行ってください。
      /** Set port. If value is not a valid number, die. */
    
      void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new RuntimeException("port " + value " is invalid, ", e);
        }
      }
    
  • 最後の手段として、例外を無視することが適切であると確信している場合は無視してもかまいませんが、正当な理由とともに理由をコメントする必要があります。
    /** If value is not a valid number, original port number is used. */
    
    void setServerPort(String value) {
        try {
            serverPort = Integer.parseInt(value);
        } catch (NumberFormatException e) {
            // Method is documented to just ignore invalid user input.
            // serverPort will just be unchanged.
        }
    }
    

一般的な例外をキャッチしない

例外をキャッチするときに怠惰になり、次のようなことをしたくなることがあります。

  try {
      someComplicatedIOFunction();        // may throw IOException
      someComplicatedParsingFunction();   // may throw ParsingException
      someComplicatedSecurityFunction();  // may throw SecurityException
      // phew, made it all the way
  } catch (Exception e) {                 // I'll just catch all exceptions
      handleError();                      // with one generic handler!
  }

これをしないでください。ほとんどの場合、一般的なExceptionまたはThrowableをキャッチすることは不適切です ( Error例外が含まれるため、 Throwableではないことが望ましい)。これは、予期しない例外 ( ClassCastExceptionなどのランタイム例外を含む) がアプリ レベルのエラー処理でキャッチされることを意味するため、危険です。これにより、コードのエラー処理のプロパティがわかりにくくなります。つまり、誰かが呼び出しているコードに新しい種類の例外を追加しても、コンパイラはエラーを別の方法で処理する必要があることを指摘しません。ほとんどの場合、異なる種類の例外を同じ方法で処理するべきではありません。

このルールのまれな例外は、あらゆる種類のエラーをキャッチする必要があるテスト コードと最上位コードです (エラーが UI に表示されないようにするため、またはバッチ ジョブの実行を維持するため)。このような場合、一般的なException (またはThrowable ) をキャッチして、エラーを適切に処理できます。ただし、これを行う前に慎重に検討し、このコンテキストで安全である理由を説明するコメントを入力してください。

一般的な例外をキャッチする代替手段:

  • マルチキャッチ ブロックの一部として、各例外を個別にキャッチします。例:
    try {
        ...
    } catch (ClassNotFoundException | NoSuchMethodException e) {
        ...
    }
  • コードをリファクタリングして、複数の try ブロックを使用して、よりきめ細かいエラー処理を行います。解析から IO を分割し、それぞれの場合に個別にエラーを処理します。
  • 例外を再スローします。多くの場合、このレベルで例外をキャッチする必要はありません。メソッドに例外をスローさせてください。

例外はあなたの友達であることを忘れないでください!例外をキャッチしていないとコンパイラが文句を言っても、顔をしかめないでください。笑顔!コンパイラにより、コード内の実行時の問題を簡単に検出できるようになりました。

ファイナライザーを使用しない

ファイナライザーは、オブジェクトがガベージ コレクションされるときにコードのチャンクを実行する方法です。ファイナライザーは (特に外部リソースの) クリーンアップには便利ですが、ファイナライザーがいつ呼び出されるか (またはまったく呼び出されるかどうか) についての保証はありません。

Android はファイナライザーを使用しません。ほとんどの場合、代わりに適切な例外処理を使用できます。どうしてもファイナライザーが必要な場合は、 close()メソッド (など) を定義し、そのメソッドをいつ呼び出す必要があるかを正確に文書化します (例については、 InputStreamを参照してください)。この場合、ファイナライザーから短いログ メッセージを出力することは適切ですが、必須ではありません。

インポートを完全に修飾する

パッケージfooからクラスBarを使用する場合、それをインポートする方法は 2 つあります。

  • import foo.*;

    import ステートメントの数を潜在的に削減します。

  • import foo.Bar;

    どのクラスが使用されているかが明確になり、メンテナーにとってコードが読みやすくなります。

import foo.Bar;を使用してください。すべての Android コードをインポートするため。 Java 標準ライブラリ ( java.util.*java.io.*など) および単体テスト コード ( junit.framework.* ) に対して明示的な例外が作成されます。

Java ライブラリの規則

Android の Java ライブラリとツールを使用するための規則があります。場合によっては、規則が重要な点で変更され、古いコードが非推奨のパターンまたはライブラリを使用している可能性があります。このようなコードを使用する場合は、既存のスタイルを継続しても問題ありません。ただし、新しいコンポーネントを作成するときは、非推奨のライブラリを使用しないでください。

Java スタイルのルール

Javadoc 標準コメントを使用する

すべてのファイルの先頭に著作権ステートメントがあり、その後に package ステートメントと import ステートメント (各ブロックは空白行で区切られています) が続き、最後にクラスまたはインターフェイスの宣言が続きます。 Javadoc コメントで、クラスまたはインターフェースの機能を説明します。

/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.foo;

import android.os.Blah;
import android.view.Yada;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * Does X and Y and provides an abstraction for Z.
 */

public class Foo {
    ...
}

作成するすべてのクラスおよび非自明なパブリック メソッドには、クラスまたはメソッドの機能を説明する少なくとも 1 つの文を含む Javadoc コメントを含める必要があります。この文は、三人称の記述動詞で始める必要があります。

/** Returns the correctly rounded positive square root of a double value. */

static double sqrt(double a) {
    ...
}

また

/**
 * Constructs a new String by converting the specified array of
 * bytes using the platform's default character encoding.
 */
public String(byte[] bytes) {
    ...
}

Javadoc に「sets Foo」としか書かれていない場合は、 setFoo()などの単純な get および set メソッドの Javadoc を記述する必要はありません。メソッドがより複雑なこと (制約の適用や重要な副作用があるなど) を行う場合は、それを文書化する必要があります。プロパティ「Foo」の意味が明らかでない場合は、それを文書化する必要があります。

public であろうとなかろうと、作成するすべてのメソッドは、Javadoc の恩恵を受けます。パブリック メソッドは API の一部であるため、Javadoc が必要です。 Android では、Javadoc コメントを記述するための特定のスタイルは強制されませんが、 Javadoc ツールのドキュメント コメントを記述する方法の手順に従う必要があります。

短いメソッドを書く

可能な場合は、メソッドを小さくして焦点を絞ってください。長いメソッドが適切な場合があることを認識しているため、メソッドの長さに厳密な制限はありません。メソッドが 40 行程度を超える場合は、プログラムの構造を損なわずに分割できるかどうかを検討してください。

標準的な場所でフィールドを定義する

ファイルの先頭か、フィールドを使用するメソッドの直前にフィールドを定義します。

変数のスコープを制限する

ローカル変数のスコープを最小限に抑えます。これにより、コードの可読性と保守性が向上し、エラーの可能性が減少します。変数のすべての使用を囲む最も内側のブロックで各変数を宣言します。

ローカル変数は、最初に使用する場所で宣言します。ほとんどすべてのローカル変数宣言には、初期化子が含まれている必要があります。変数を適切に初期化するのに十分な情報がまだない場合は、そうなるまで宣言を延期してください。

例外は、try-catch ステートメントです。チェック例外をスローするメソッドの戻り値で変数を初期化する場合は、try ブロック内で初期化する必要があります。値を try ブロックの外で使用する必要がある場合は、try ブロックの前に宣言する必要があります。

// Instantiate class cl, which represents some sort of Set

Set s = null;
try {
    s = (Set) cl.newInstance();
} catch(IllegalAccessException e) {
    throw new IllegalArgumentException(cl + " not accessible");
} catch(InstantiationException e) {
    throw new IllegalArgumentException(cl + " not instantiable");
}

// Exercise the set
s.addAll(Arrays.asList(args));

ただし、try-catch ブロックをメソッドにカプセル化することで、このケースを回避することもできます。

Set createSet(Class cl) {
    // Instantiate class cl, which represents some sort of Set
    try {
        return (Set) cl.newInstance();
    } catch(IllegalAccessException e) {
        throw new IllegalArgumentException(cl + " not accessible");
    } catch(InstantiationException e) {
        throw new IllegalArgumentException(cl + " not instantiable");
    }
}

...

// Exercise the set
Set s = createSet(cl);
s.addAll(Arrays.asList(args));

やむを得ない理由がない限り、for ステートメント自体でループ変数を宣言します。

for (int i = 0; i < n; i++) {
    doSomething(i);
}

for (Iterator i = c.iterator(); i.hasNext(); ) {
    doSomethingElse(i.next());
}

注文輸入明細書

import ステートメントの順序は次のとおりです。

  1. Android のインポート
  2. サードパーティ ( comjunitnetorg ) からのインポート
  3. javajavax

IDE 設定と正確に一致させるには、インポートを次のようにする必要があります。

  • 各グループ内でアルファベット順、小文字の前に大文字 (たとえば、a の前に Z)
  • 各主要グループ ( androidcomjunitnetorgjavajavax ) の間は空白行で区切られています。

つまり、IDE は常に順序を変更するか、IDE 開発者が自動インポート管理機能を無効にして手動でインポートを維持する必要がありました。これは悪いと判断されました。 Java スタイルについて尋ねられたとき、好まれるスタイルは非常に多様であり、単純に「順序を選択して一貫性を保つ」必要がある Android に行き着きました。そのため、スタイルを選択し、スタイル ガイドを更新し、IDE をそれに準拠させました。 IDE ユーザーがコードに取り組むとき、すべてのパッケージのインポートは、追加のエンジニアリング作業なしでこのパターンに一致することが期待されます。

このスタイルを選択した理由は次のとおりです。

  • 人々が最初に見たいと思うインポートは、トップ ( android ) にある傾向があります。
  • 人々が少なくとも見たいと思うインポートは、一番下 ( java ) にある傾向があります。
  • 人間はそのスタイルに簡単に従うことができます。
  • IDE はスタイルに従うことができます。

通常のインポートと同じように、静的インポートを他のすべてのインポートの上に配置します。

インデントにスペースを使用する

ブロックには 4 つのスペース インデントを使用し、タブは使用しません。疑わしい場合は、周囲のコードと一貫性を持たせてください。

関数呼び出しと代入を含む行の折り返しには、8 つのスペース インデントを使用します。

おすすめされた

Instrument i =
        someLongExpression(that, wouldNotFit, on, one, line);

非推奨

Instrument i =
    someLongExpression(that, wouldNotFit, on, one, line);

フィールドの命名規則に従う

  • 非パブリック、非静的フィールド名はm始まります。
  • 静的フィールド名はsで始まります。
  • 他のフィールドは小文字で始まります。
  • static final フィールド (定数、完全に不変) はALL_CAPS_WITH_UNDERSCORESです。

例えば:

public class MyClass {
    public static final int SOME_CONSTANT = 42;
    public int publicField;
    private static MyClass sSingleton;
    int mPackagePrivate;
    private int mPrivate;
    protected int mProtected;
}

標準ブレース スタイルを使用する

中かっこは、それ自体の行ではなく、前のコードと同じ行に置きます。

class MyClass {
    int func() {
        if (something) {
            // ...
        } else if (somethingElse) {
            // ...
        } else {
            // ...
        }
    }
}

条件文の前後に中括弧が必要です。例外: 条件全体 (条件と本体) が 1 行に収まる場合は、すべてを 1 行に入れることができます (ただし、そうする義務はありません)。たとえば、これは許容されます。

if (condition) {
    body();
}

これは許容されます。

if (condition) body();

しかし、これは受け入れられません:

if (condition)
    body();  // bad!

制限線の長さ

コード内のテキストの各行の長さは、最大 100 文字にする必要があります。このルールについては多くの議論がなされてきましたが、次の例外を除いて 100 文字が最大であるという決定が残っています。

  • コメント行に 100 文字を超えるサンプル コマンドまたはリテラル URL が含まれている場合、カット アンド ペーストを容易にするために、その行は 100 文字を超えることがあります。
  • 人間がそれらを見ることはめったにないため、インポート行は制限を超える可能性があります (これにより、ツールの作成も簡素化されます)。

標準の Java アノテーションを使用する

注釈は、同じ言語要素の他の修飾子よりも前にある必要があります。単純なマーカー注釈 ( @Overrideなど) は、言語要素と同じ行にリストできます。複数の注釈またはパラメーター化された注釈がある場合は、アルファベット順に 1 行に 1 つずつリストします。

Java で事前定義された 3 つのアノテーションに対する Android の標準的な方法は次のとおりです。

  • 注釈付き要素の使用が推奨されない場合は常に@Deprecated注釈を使用してください。 @Deprecatedアノテーションを使用する場合は、 @deprecated Javadoc タグも必要であり、別の実装を指定する必要があります。さらに、 @Deprecatedメソッドは引き続き機能することを忘れないでください。 @deprecated Javadoc タグを持つ古いコードを見つけた場合は、 @Deprecatedアノテーションを追加してください。
  • メソッドがスーパークラスからの宣言または実装をオーバーライドするときは常に@Overrideアノテーションを使用します。たとえば、 @inheritdocs Javadoc タグを使用し、(インターフェイスではなく) クラスから派生する場合、メソッドが親クラスのメソッドをオーバーライドすることも注釈する必要があります。
  • @SuppressWarningsアノテーションは、警告を除去できない状況でのみ使用してください。警告がこの「除去不可能」テストに合格した場合、 @SuppressWarningsアノテーション使用して、すべての警告がコード内の実際の問題を反映していることを確認する必要があります。

    @SuppressWarningsアノテーションが必要な場合は、「除去不可能」な状態を説明するTODOコメントを先頭に付ける必要があります。これは通常、扱いにくいインターフェイスを持つ問題のあるクラスを識別します。例えば:

    // TODO: The third-party class com.third.useful.Utility.rotate() needs generics
    @SuppressWarnings("generic-cast")
    List<String> blix = Utility.rotate(blax);
    

    @SuppressWarningsアノテーションが必要な場合は、コードをリファクタリングして、アノテーションが適用されるソフトウェア要素を分離します。

頭字語を単語として扱う

頭字語と略語を変数、メソッド、およびクラスの名前付けで単語として扱い、名前を読みやすくします。

良い悪い
XmlHttpRequest XMLHTTPRequest
getCustomerId getCustomerID
クラス HTMLクラス HTML
文字列 URL文字列 URL
長いID長い ID

JDK と Android のコード ベースは頭字語に関して一貫性がないため、周囲のコードと一貫性を保つことは事実上不可能です。したがって、頭字語は常に単語として扱います。

TODO コメントを使用する

一時的なコード、短期的な解決策、または十分ではあるが完全ではないコードには、 TODOコメントを使用します。これらのコメントには、すべて大文字の文字列TODOとそれに続くコロンを含める必要があります。

// TODO: Remove this code after the UrlTable2 has been checked in.

// TODO: Change this to use a flag instead of a constant.

TODOが「将来の日付で何かを行う」という形式の場合は、特定の日付 (「2005 年 11 月までに修正」) または特定のイベント (「すべてのプロダクション ミキサーがプロトコル V7 を理解したら、このコードを削除してください」) のいずれかを含めるようにしてください。 )。

控えめにログに記録する

ロギングは必要ですが、適度に簡潔にしないと、パフォーマンスに悪影響を及ぼし、有用性が失われます。ロギング機能は、5 つの異なるレベルのロギングを提供します。

  • ERROR : 何か致命的なことが起こった場合に使用します。つまり、何かがユーザーに目に見える結果をもたらし、一部のデータを削除したり、アプリをアンインストールしたり、データ パーティションを消去したり、デバイス全体を再フラッシュしたり (またはさらに悪いこと) しないと回復できません。このレベルは常にログに記録されます。 ERRORレベルでログを記録することを正当化する問題は、統計収集サーバーに報告するのに適した候補です。
  • WARNING : 深刻で予期しない事態が発生した場合に使用します。つまり、ユーザーに目に見える結果をもたらしますが、アプリの待機または再起動から再ダウンロードまでの明示的なアクションを実行することで、データを失うことなく回復できる可能性があります。アプリの新しいバージョンまたはデバイスの再起動。このレベルは常にログに記録されます。 WARNINGレベルでログを記録することを正当化する問題も、統計収集サーバーへのレポートで考慮される場合があります。
  • INFORMATIVE : 何か興味深いことが起こったことに注意するために使用します。つまり、必ずしもエラーではありませんが、広範な影響を与える可能性が高い状況が検出された場合です。このような状態は、そのドメインで最も権限があると考えているモジュールによってのみログに記録されます (権限のないコンポーネントによる重複したログ記録を避けるため)。このレベルは常にログに記録されます。
  • DEBUG : 予期しない動作の調査とデバッグに関連する可能性がある、デバイスで何が起こっているかをさらに書き留めるために使用します。コンポーネントで何が起こっているかについて十分な情報を収集するために必要なものだけをログに記録します。デバッグ ログがログを支配している場合は、詳細ログを使用する必要があります。

    このレベルはリリース ビルドでもログに記録され、 LOCAL_LOG[D]がクラスまたはサブコンポーネントで定義されている場合、 if (LOCAL_LOG)またはif LOCAL_LOGD)ブロックで囲む必要があるため、そのようなログをすべて無効にする可能性があります。 .したがって、 if (LOCAL_LOG)ブロックにアクティブなロジックがあってはなりません。ログのすべての文字列構築も、 if (LOCAL_LOG)ブロック内に配置する必要があります。文字列の構築がif (LOCAL_LOG)ブロックの外部で発生する場合は、ロギング呼び出しをメソッド呼び出しにリファクタリングしないでください。

    まだif (localLOGV)と言うコードがいくつかあります。名前は非標準ですが、これも許容できると見なされます。

  • VERBOSE : 他のすべてに使用します。このレベルは、デバッグ ビルドでのみログに記録され、デフォルトでコンパイルできるように、 if (LOCAL_LOGV)ブロック (または同等のもの) で囲む必要があります。文字列の構築はリリース ビルドから取り除かれ、 if (LOCAL_LOGV)ブロック内に表示される必要があります。

ノート

  • 特定のモジュール内では、 VERBOSEレベル以外では、エラーは可能であれば 1 回だけ報告する必要があります。モジュール内の関数呼び出しの単一チェーン内では、最も内側の関数のみがエラーを返す必要があり、同じモジュール内の呼び出し元は、問題を特定するのに大幅に役立つ場合にのみログを追加する必要があります。
  • VERBOSEレベル以外の一連のモジュールでは、下位モジュールが上位モジュールからの無効なデータを検出した場合、下位モジュールはこの状況をDEBUGログにのみ記録する必要があります。発信者が他の方法では利用できない情報。具体的には、例外がスローされた状況 (例外にはすべての関連情報が含まれている必要があります) や、ログに記録されている情報がエラー コードにのみ含まれている状況をログに記録する必要はありません。これは、フレームワークとアプリ間の相互作用において特に重要です。フレームワークによって適切に処理されるサードパーティ製アプリによって引き起こされた条件は、 DEBUGレベルよりも高いログをトリガーするべきではありません。 INFORMATIVEレベル以上でロギングをトリガーする必要がある唯一の状況は、モジュールまたはアプリがそれ自体のレベルまたは下位レベルからのエラーを検出した場合です。
  • 通常は何らかのログ記録を正当化する状況が何度も発生する可能性が高い場合、同じ (または非常に類似した) 情報の多数の重複コピーでログがオーバーフローするのを防ぐために、レート制限メカニズムを実装することをお勧めします。
  • ネットワーク接続が失われることはよくあることであり、当然のことであり、むやみにログに記録するべきではありません。アプリ内で結果をもたらすネットワーク接続の損失は、 DEBUGまたはVERBOSEレベルでログに記録する必要があります (結果がリリース ビルドに記録されるほど深刻であるか、予期しないものであるかによって異なります)。
  • サードパーティのアプリからアクセスできる、またはサードパーティのアプリに代わってアクセスできるファイル システム上に完全なファイル システムを持つことは、INFORMATIVE よりも高いレベルでログに記録されるべきではありません。
  • 信頼されていないソース (共有ストレージ上のファイルやネットワーク接続経由​​のデータを含む) からの無効なデータは、予期されるものと見なされ、無効であることが検出された場合に、 DEBUGよりも高いレベルでログをトリガーするべきではありません (さらにログを記録する場合でも)。可能な限り制限する必要があります)。
  • +演算子をStringオブジェクトで使用すると、デフォルトのバッファ サイズ (16 文字) でStringBuilderインスタンスが暗黙的に作成され、その他の一時的なStringオブジェクトが作成される可能性があります。したがって、 StringBuilderオブジェクトを明示的に作成しても、デフォルトの+演算子に依存するよりもコストがかかりません (さらに効率的になります)。 Log.v()を呼び出すコードは、ログが読み取られていない場合でも、文字列の構築を含め、リリース ビルドでコンパイルおよび実行されることに注意してください。
  • 他の人が読んだり、リリース ビルドで利用できるようにすることを意図したログは、わかりにくくなく簡潔で、理解しやすいものにする必要があります。これには、 DEBUGレベルまでのすべてのログが含まれます。
  • 可能であれば、1 行でログを記録し続けます。行の長さは最大 80 または 100 文字です。可能であれば、約 130 文字または 160 文字 (タグの長さを含む) を超える長さは避けてください。
  • ロギングが成功を報告する場合は、 VERBOSEよりも高いレベルで使用しないでください。
  • 再現が難しい問題を診断するために一時ログを使用している場合は、 DEBUGまたはVERBOSEレベルに保ち、コンパイル時に無効にできる if ブロックで囲みます。
  • ログによるセキュリティ リークに注意してください。個人情報の記録は避けてください。特に、保護されたコンテンツに関する情報のログ記録は避けてください。これは、フレームワーク コードを記述する場合に特に重要です。なぜなら、何が個人情報または保護されたコンテンツになるか、またはならないかを事前に知ることは容易ではないからです。
  • System.out.println() (またはネイティブ コードの場合はprintf()を使用しないでください。 System.outSystem.err/dev/nullにリダイレクトされるため、print ステートメントは目に見える影響を与えません。ただし、これらの呼び出しで発生するすべての文字列構築は引き続き実行されます。
  • ロギングの黄金律は、他のログがあなたのログを押し出さないのと同じように、あなたのログが他のログを不必要にバッファーから押し出さないことです。

Javatests スタイル ルール

テスト メソッドの命名規則に従い、アンダースコアを使用して、テスト対象とテスト対象の特定のケースを区別します。このスタイルにより、どのケースがテストされているかを簡単に確認できます。例えば:

testMethod_specificCase1 testMethod_specificCase2

void testIsDistinguishable_protanopia() {
    ColorMatcher colorMatcher = new ColorMatcher(PROTANOPIA)
    assertFalse(colorMatcher.isDistinguishable(Color.RED, Color.BLACK))
    assertTrue(colorMatcher.isDistinguishable(Color.X, Color.Y))
}