Javaコーディングのベストプラクティスの簡単な要約

Oracle、Google、Twitter、Spring Frameworkによるコーディング標準に基づいています

この記事の目的は、オラクル、グーグル、ツイッター、Spring Frameworkなどのテクノロジーの巨人によるコーディング標準に基づいて、「する」と「しない」を簡単に要約することです。

ここに提示されているベストプラクティスの一部に同意する場合と同意しない場合がありますが、コーディング標準が整っている限り、それはまったく問題ありません。

そもそもなぜコーディング標準なのか?あなたがそれをグーグルにすれば多くの正当な理由があり、私はあなたに次のイラストを残すでしょう

コーディング標準文書は長くて退屈なものになる可能性があります。この記事では、Google、Oracle、Twitter、Springのコーディング規約から細かな部分を取り上げています。その目的は、コードを読みやすく、保守しやすくするための、わかりやすく退屈な一連のプラクティスを提供することです。

ほとんどの場合、既存のソフトウェアに取り組んでいるチームに参加します。ほとんどの作者が別のプロジェクトを離れたり、別のプロジェクトに切り替えたりする可能性はかなり高く、人類に疑問を抱かせるコードの一部に取り残されます。

さまざまなコーディング標準のベストプラクティスに飛び込みましょう。

Javaソースファイル

Javaソースファイルに関しては、以下がベストプラクティスと見なされます。

  • ソースファイルの長さが2,000行未満のコード
  • ソースファイルは、以下に示すように、ドキュメンテーションコメント、パッケージ宣言、クラスコメント、グループ化されたインポート(静的な最後)、クラス/インターフェイスシグネチャなどで構成されています。
パッケージcom.example.model;
/ **
 *開発者が読むべき実装不要の視点
 *必ずしも手元にソースコードがあるとは限らない人
 *
 * @author x、y、z
 * @date
 * @版
 * @copyright
 *
 * /
import com.example.util.FileUtil;
/ *
 *オプションのクラス固有のコメント
 *
 * /
パブリッククラスSomeClass {
  //可視性の順序での静的変数
  public static final Integer PUBLIC_COUNT = 1;
  静的最終整数PROTECTED_COUNT = 1;
  private static final Integer PRIVATE_COUNT = 1;
  //可視性の順にインスタンス変数
  パブリック文字列名。
  文字列postalCode;
  プライベート文字列アドレス。
  //コンストラクターと順番にオーバーロード
  public SomeClass(){}
  public SomeClass(String name){
    this.name = name;
  }
  //メソッド
  public String doSomethingUseful(){
    「何か役に立つ」を返す;
  }
  //最後にゲッター、セッター、イコール、hashCode、toString
}

ネーミング

クラス名とインターフェース名はキャメルケースです。単語全体を使用し、頭字語/略語を避けることをお勧めします。たとえば、クラスRasterまたはクラスImageSprite

  • パッケージ— com.deepSpaceまたはcom.deep_spaceよりもcom.deepspaceの名前を指定します
  • ファイル—名前はCamelCaseで、クラス名に一致する.javaで終わります。ファイルごとに1つのパブリッククラスがあり、そのファイルには各トップレベルクラスがあります
  • 方法—名前は大文字と小文字が混在する動詞で、run()のように各単語が大文字になっている必要があります。またはrunFast();
  • 定数— int MIN_WIDTH = 44;のように、各単語を「_」で区切って大文字にする必要があります。およびint MAX_WIDTH = 99;
  • 変数—プログラムの読者に変数が何を表すかを伝える名前。つまり、テストの成績を保存している場合はgrade vs var1を選択します。メタデータを含めないように、変数名を短くしてください。
//優先()-変数名は短く、保存する内容を説明する
int schoolId;
int [] FilteredSchoolIds;
int [] uniqueSchooldIds;
Map <整数、ユーザー> usersById;
文字列値;
//回避(x)-変数の命名が詳細すぎる
int schoolIdentificationNumber;
int [] userProvidedSchoolIds;
int [] schoolIdsAfterRemovingDuplicates;
Map <整数、ユーザー> idToUserMap;
String valueString;

覚えておいてください-変数名は短く、どの値を表すのかを読者に簡単に伝えてください。あなたの判断を使用してください。

優先して回避

書式設定とインデントは、コードを整理して読みやすくすることであり、間隔、行の長さ、折り返​​し、改行などが含まれます

  • インデント— 2つまたは4つのスペースを使用し、一貫性を保ちます
  • 行の長さ—可読性への影響に応じて、最大70〜120文字。水平スクロールの必要性を排除し、カンマと演算子の後に改行を配置することが重要です。

方法—ベストプラクティスのリストを以下に示します

//優先()改行は任意であり、カンマの後に改行します。
String downloadAnInternet(インターネットインターネット、チューブチューブ、
    Blogosphereブログ、Amount 帯域幅){
  tubes.download(インターネット);
}
//(x)メソッドの引数をメソッド本体と比較しにくい
String downloadAnInternet(インターネットインターネット、チューブチューブ、
    Blogosphereブログ、Amount 帯域幅){
    tubes.download(インターネット);
}
//優先()深いインデント用に8(2または4のダブル)スペースを追加
プライベート静的同期horkingLongMethodName(int anArg、
        オブジェクトanotherArg、String yetAnotherArg、
        Object andStillAnother){
  ...
}
//優先()簡単なスキャンと余分な列スペース。
public String downloadAnInternet(
    インターネットインターネット、
    チューブチューブ、
    Blogosphereブログ、
    Amount  bandwidth){
  tubes.download(インターネット);
  ...
}
ユニットテストはそれをキャッチしたでしょうwould

if-checks-IMOは適切にフォーマットされたコードを記述することで、作成者とコードレビュー担当者にタイプミスやエラーを簡単に見つけることができます。以下を参照してください。

//回避(x){}を省略しない
if(条件)
  ステートメント;
//回避(x)
if(x <0)negative(x);
//回避(x)
if(a == b && c == d){
...
}
//優先()
if((a == b)&&(c == d)){
...
}
//優先()
if(条件){
  ステートメント;
} else if(条件){
  ステートメント;
} else if(条件){
  ステートメント;
}
//回避(x)
if((condition1 && condition2)
    || (condition3 && condition4)
    ||!(condition5 && condition6)){//悪いラップ
    そのために何かをする(); //この行を簡単に作成する
}
//優先()
if((condition1 && condition2)
        || (condition3 && condition4)
        ||!(condition5 && condition6)){
    そのために何かをする();
}

三項演算子—以下は推奨される方法です

alpha =(aLongBooleanExpression)? beta:ガンマ;
alpha =(aLongBooleanExpression)?ベータ
        :ガンマ;
alpha =(aLongBooleanExpression)
        ?ベータ
        :ガンマ;

スイッチ—スイッチについては、ベストプラクティスとして

  • コードがなくても常にデフォルトのケースがあります
  • / * fall through through * /を使用して、コントロールが次のケースに該当することを示します
スイッチ(条件){
  ケースABC:
    ステートメント;
  / *フォールスルー* /
  ケースDEF:
    ステートメント;
    ブレーク;
  デフォルト:
    ステートメント;
     ブレーク;
}

例外メッセージ—例外をスローする場合、ここには、インデントが適切なメッセージと不十分なメッセージのサンプルがあります。

//回避(x)-読みにくい
throw IllegalStateException( "リクエストの処理に失敗しました" + request.getId()
    + "ユーザー向け" + user.getId()+ "クエリ: '" + query.getText()
    + "'");
//優先()-かなり読みやすい
新しいIllegalStateException( "処理に失敗しました"
    + "request" + request.getId()
    +「ユーザー向け」+ user.getId()
    + "query: '" + query.getText()+ "'");

イテレータとストリーム—ストリームはより一般的になりつつあり、非常に複雑になる場合があるため、読みやすくするためにインデントすることが重要です。

//回避(x)-読みにくい
Iterable  modules = ImmutableList。 builder()。add(new LifecycleModule())
    .add(new AppLauncherModule())。addAll(application.getModules())。build();
//優先()-かなり読みやすい
Iterable  modules = ImmutableList。 builder()
    .add(new LifecycleModule())
    .add(新しいAppLauncherModule())
    .addAll(application.getModules())
    .build();
コーディング標準に従うだけです。

宣言と割り当て—以下に示すようにコメントを推奨するため、1行に1つの宣言をお勧めします。

//優先()
intレベル; //インデントレベル
int sizeMeter; //テーブルのサイズ
//上記を支持して(x)を避ける
intレベル、sizeMeter;
//優先()-変数名または型に単位を含める
long pollIntervalMs;
int fileSizeGb;
Amount  fileSize;
//(x)タイプの混在を避ける
int foo、fooarray [];
//回避(x)-コンマで区切らない
Format.print(System.out、“ error”)、exit(1);
//(x)複数の割り当てを避けます
fooBar.fChar = barFoo.lchar = 'c';
//パフォーマンスを向上させるため、または行を保存するために、(x)埋め込み割り当てを避けます。私はこれを行うのは有罪です:(
d =(a = b + c)+ r;
//上記よりも優先()
a = b + c;
d = a + r;
//優先()
String [] args
//回避(x)
文字列引数[]
//優先()1との混乱を避けるため、「l」ではなく「L」を長く使用します
長いタイムアウト= 3000000000L;
//回避(x)-最後の文字がlではなく1
長いタイムアウト= 3000000000l;

ブロックの先頭にのみ宣言を配置します(ブロックは、中括弧{と}で囲まれたコードです)。変数を最初に使用するまで宣言しないでください。不注意なプログラマを混乱させ、スコープ内でのコードの移植性を妨げる可能性があります。

//ブロックの先頭で宣言()します。
public void doSomething(){
  int whatIRepresent; //メソッドブロックの始まり
  if(条件){
    int someFlag; //「if」ブロックの始まり
    …
  }
}

また、上位レベルの宣言を隠すローカル宣言を避けることも重要です。また、以下に示すような混乱を避けることも重要です

intカウント;
...
public void doSomething(){
  if(条件){
    intカウント; //避ける!
    ...
  }
  ...
}

間隔と改行—可読性を犠牲にして1〜2行のコードを保存する誘惑を避けます。スペースと空白行に関するベストプラクティスは次のとおりです(空白は違いをもたらします)

  • メソッドとSpring開発者の間の1行の空白行では、コンストラクター、静的ブロック、フィールド、内部クラスの後に2行の空白行を推奨しています。
  • スペースパッド演算子、つまりint foo = a + b + 1を使用します。 over int foo = a + b + 1;
  • スペースを使用して、オペランドから「。」以外のすべての二項演算子を区切ります
  • 開き中かっこ「{」は宣言文またはメソッドと同じ行の最後に表示され、閉じ中かっこ「}」はインデントされた行を開始します
//優先()-「while」の後、「(」の前のスペース
while(true){
  ...
}
//回避(x)-上記とは異なり、スペースなし
while(true){
  ...
}
//優先()-「doSomething」と「(」の間にスペースがない
public void doSomething(){
  ...
}
//回避(x)-上記のスペースとは異なります
public void doSomething(){
  ...
}
//優先()-引数の後にスペースを追加します
public void doSomething(int a、int b){
  ...
}
//優先()-オペランドと演算子の間のスペース(つまり、+、=)
a + = c + d;
a =(a + b)/(c * d);
while(d ++ = s ++){
  n ++;
}

ドキュメントとコメント

ほぼすべてのコードはその存続期間を通じて変化することに注意してください。明確な説明がない限り、コードの複雑なブロック、メソッド、またはクラスが何を意図しているのかを理解しようとしている場合があります。現実はほとんど常に以下の通りです

コード、メソッド、クラスの複雑な部分に対するコメントは、値を追加したり、その目的を果たさないことがあります。これは通常、コメントのためにコメントするときに起こります。

コメントを使用して、コードの概要を示し、コード自体では容易に入手できない追加情報を提供する必要があります。始めましょう。コメントには2種類あります

実装コメント—コードをコメントアウトするか、コードの特定の実装についてコメントするためのものです。

ドキュメントコメント—ソースコードが必ずしも手元にない可能性のある開発者が読むために、実装のない観点からコードの仕様を説明するためのものです。

コメントの頻度は、コードの質の低さを反映する場合があります。コメントを追加する必要がある場合は、コードを書き直して、より明確にすることを検討してください。

実装コメントの種類

以下に示すように、4つのタイプの実装コメントがあります。

  • コメントをブロック-以下の例を参照
  • 単一行コメント—コメントが1行より長くない場合
  • 末尾のコメント—非常に短いコメントが右端に移動しました
  • 行末コメント—改行まで続くコメントを開始します。行全体または一部の行のみをコメントアウトできます。テキストコメントの連続した複数行で使用しないでください。ただし、コードのセクションをコメントアウトするために連続した複数行で使用できます。
//コメントをブロック
/ *
 *使用法:ファイル、メソッド、データ構造の説明を提供します
 *およびアルゴリズム。各ファイルの先頭で使用でき、
 *各メソッドの前。収まらない長いコメントに使用
 * 単線。 1ブロックコメントの後に進むための空白行。
 * /
//単一行のコメント
if(条件){
 / *状態を処理します。 * /
  ...
}
//末尾のコメント
if(a == 2){
 TRUEを返します。 /* 特別なケース */
} else {
 return isPrime(a); / *奇数の場合のみ機能します* /
}
//行末コメント
if(foo> 1){
  //ダブルフリップを行います。
  ...
} else {
  falseを返します。 //ここで理由を説明します。
}
// if(bar> 1){
//
// //トリプルフリップを行います。
// ...
//}
//その他
// falseを返します;

ドキュメントのコメント(つまりJavadoc)

Javadocは、/ **で始まり* /で終わるコメントを使用して、JavaコードからHTMLドキュメントを生成するツールです。Javadocの動作の詳細については、Wikipediaをご覧ください。

Javadocの例を次に示します

/ **
 *画面にペイントできるImageオブジェクトを返します。
 * url引数には、絶対{@link URL}を指定する必要があります。名前
 *引数は、url引数に関連する指定子です。
 * 

 *このメソッドは、  *画像が存在します。このアプレットが画像を描画しようとするとき  *画面、データがロードされます。グラフィックスプリミティブ  *画像を描画すると、画面に徐々にペイントされます。  *  * @param url画像の基本位置を示す絶対URL  * @param name url引数に相対的な画像の場所  * @指定されたURLの画像を返す  * @see画像  * /  public Image getImage(URL url、String name){         {             return getImage(new URL(url、name));         } catch(MalformedURLException e){             nullを返します。         }  }

上記のコードに対してjavadocを実行すると、上記の結果は次のようなHTMLになります。

詳細はこちらをご覧ください

生成されたJavaドキュメントの品質を向上させるために使用できる重要なタグを次に示します。

@author => @author Raf
@code => {@code A  C}
@deprecated => @deprecated deprecation-message
@exception => @exception IOExceptionがスローされるのは
@link => {@link package.class#member label}
@param => @paramパラメーター名説明
@return =>メソッドが返すもの
@see => @see "string" OR @see  
@since =>パブリックにアクセス可能なメソッドが追加されたときにバージョンを示す

完全なリストと詳細な説明については、こちらをご覧ください

Twitterのコーディング標準では、@ authorタグの使用は推奨されていません

コードは、その存続期間中に何度も手を変更する可能性があり、ソースファイルの元の作成者は、何度か繰り返した後は無関係であることが非常に多くあります。コミット履歴とOWNERSファイルを信頼して、コード本体の所有権を判断する方が良いと判断しました。

以下は、Twitterのコーディング標準で説明されているように、洞察力に富んだドキュメントコメントを作成する方法の例です。

//悪い。
//-ドキュメントは、メソッド宣言がしなかったことを何も伝えません。
//-これは「フィラードキュメント」です。スタイルチェックに合格しますが、
誰にも役に立たない
/ **
 *文字列を分割します。
 *
 * @param s文字列。
 * @return文字列のリスト。
 * /
List  split(String s);
//より良い。
//-メソッドが何に分割されるかを知っています。
//-未定義の動作。
/ **
 *文字列を空白で分割します。
 *
 * @param s分割する文字列。 {@code null}文字列は空の文字列として扱われます。
 * @return入力の空白で区切られた部分のリスト。
 * /
List  split(String s);
// すばらしいです。
//-さらに別のエッジケースをカバーします。
/ **
 *文字列を空白で分割します。繰り返される空白文字
 *折りたたまれています。
 *
 * @param s分割する文字列。 {@code null}文字列は空の文字列として扱われます。
 * @return入力の空白で区切られた部分のリスト。
 * /
List  split(String s);

コメントを書く際にはプロになることが重要です

//回避(x)
// xml / soapが大嫌いなのに、どうしてこんなことができないのですか?
{
  userId = Integer.parseInt(xml.getField( "id"));
} catch(NumberFormatException e){
  ...
}
//優先()
// TODO(Jim):ライブラリ内でフィールド検証を隠します。
{
  userId = Integer.parseInt(xml.getField( "id"));
} catch(NumberFormatException e){
  ...
}

また、実装が変更されない限り、オーバーライドされたメソッドを文書化しないように注意することが重要です。

そして、心に留めておくべきもういくつかのポイントがあります

  • ワイルドカードのインポートを避けます-Twitterのコーディング標準で説明されているように、クラスのソースがわかりにくくなります。私はEclipseユーザーとIntelliJユーザーが混在するチームで働いていますが、Eclipseはワイルドカードのインポートを削除し、IntelliJがそれを導入することがわかりました。おそらくそれをオフにするオプションがありますが、2つのデフォルトを指摘したかっただけです。
  • オーバーライドするときは常に@Overrideアノテーションを使用します
  • フィールドまたはメソッドがnullを返すとき、@ Nullableの使用を奨励する
  • 将来の作業のために特別なコメントを使用し、自分自身への参照を忘れずに、他の人が推測、削除、またはgit blameをチェックして追加した人を見つけるのではなく、誰がY質問をするかを知ってください。 EclipseやIntelliJのような一部のIDEは、簡単にアクセスできるようにこれらを一覧表示するのに役立ちます。
// FIXME(Raf):実行可能なアクションを説明するアクション可能なメッセージ
// TODO(Raf):実行可能なアクションを説明するアクション可能なメッセージ

最後のゲームは、将来の作者とメンテナーの生活を楽にするコードを書くことです。

終盤

その他の関連資料

クリーンで、適切に構造化され、読みやすく、保守可能なコードの記述に関連する関連記事のリスト。さらに読みたい場合は、間違いなく以下をお勧めします

きれいなコードを書くためのヒントの別の良いリスト