Copyright (c) 1999 Scott Ambler, Ambysoft, Inc.

「Java Coding Guidelines」は、Scott Ambler, Ambysoft Inc. (www.ambysoft.com) の ライセンスの下で提供されています。また、Rational Unified Process に合わせて構成し直されています。


目次

1      はじめに
       
1.1    唯一のガイドライン

2    コーディングの標準
     
2.1    命名規則
     2.2    本書の規則
              2.2.1  Java コメントの種類
              2.2.2  javadoc の概要   

3    メンバー関数に関する標準
     
3.1    メンバー関数の命名
              3.1.1    アクセサー・メンバー関数の命名
                         3.1.1.1    Getter
                         3.1.1.2    Setter
     3.2    コンストラクターの命名
      3.3    メンバー関数の可視性
      3.4    メンバー関数の文書化
               3.4.1    メンバー関数のヘッダー
               3.4.2    内部文書
      3.5    きれいなコードを作成する技術
               3.5.1    コードを文書化する
               3.5.2    段落やインデントを使用する
               3.5.3    空白を使用する
               3.5.4    30 秒ルールに従う
               3.5.5    簡潔に、1 行に 1 つのコマンドを記述する
               3.5.6    演算の順序を指定する

4    フィールドとプロパティーに関する標準
      4.1    フィールドの命名
              4.1.1    コンポーネントの命名 (ウィジェット)
                         4.1.1.1    コンポーネントのその他の命名方法: ハンガリアン記法
                         4.1.1.2    コンポーネントのその他の命名方法: 接尾辞ハンガリアン記法
                         4.1.1.3    コンポーネント名に関する標準の設定
              4.1.2    定数の命名
               4.1.3    コレクションの命名
      4.2    フィールドの可視性
               4.2.1    名前を「隠蔽」しない
      4.3    フィールドの文書化
      4.4    アクセサー・メンバー関数の使用法
              4.4.1    アクセサーを使用する理由               
                          4.4.1.1   アクセサーを使用しない場合
              4.4.2    アクセサーの命名
              4.4.3    アクセサーに関する高度な技術
                         4.4.3.1    遅延初期化
                         4.4.3.2    
定数に対するアクセサー
                         4.4.3.3    
コレクションに対するアクセサー
                         4.4.3.4    複数のフィールドへの同時アクセス   
      4.5    アクセサーの可視性
      4.6    static フィールドを常に初期化する

5    ローカル変数に関する標準
      5.1    ローカル変数の命名
                  5.1.1    ストリームの命名
                   5.1.2    ループ・カウンターの命名
                   5.1.3    例外オブジェクトの命名
        5.2   ローカル変数の宣言と文書化
               5.2.1     宣言に関する一般的な注意

6    メンバー関数のパラメーターに関する標準
     
6.1    パラメーターの命名
     6.2    パラメーターの文書化
               6.2.1    パラメーターのタイプに対するインターフェースの使用

7    クラス、インターフェース、パッケージ、コンパイル・ユニットに関する標準
      7.1    クラスに関する標準
                7.1.1    クラスの命名
                7.1.2    クラスの文書化
                7.1.3    クラスの宣言
                7.1.4    public と protected インターフェースの最小化
                            7.1.4.1    public インターフェースを最初に定義する
      7.2     インターフェースに関する標準
                7.2.1    インターフェースの命名
                            7.2.1.1    その他の命名規則
                7.2.2    インターフェースの文書化
      7.3     パッケージに関する標準
                7.3.1    パッケージの命名
                7.3.2    パッケージの文書化
      7.4     コンパイル・ユニットに関する標準
                7.4.1    コンパイル・ユニットの命名
                7.4.2    コンパイル・ユニットの文書化

8    エラー処理と例外

9    さまざまな標準と問題
      9.1    再利用
     9.2    クラスのインポート
      9.3    Java コードの最適化
      9.4    Java テスト・ハーネスの作成

10    成功のパターン
       10.1    効果的な標準の使用法
       10.2    適切なコードを作成するためのその他の要素

11    まとめ
       
11.1    Java の命名規則
        11.2    Java の文書化規則
                   11.2.1    Java コメントの種類
                   11.2.2    文書化の対象
        11.3    Java のコーディング規則 (全般)

12    参考資料

13    用語集


1    はじめに

ここでは、信頼できる Java コードを記述するための、標準、規則、 ガイドラインについて説明しています。これらは信頼性のある、実証されたソフトウェア・エンジニアリング原則に基づいており、 生成されるコードは理解、保守、拡張が容易になります。さらに、 これらのコーディング標準に従うことで、Java 開発者の生産性が飛躍的に向上します。経験的に、 最初から時間をかけて高い品質のコードを記述することで、開発プロセスを通して、 コードをより簡単に変更できることが分かっています。最後に、一般的なコーディング標準に従うことで、 一貫性が保たれ、開発チームの生産性が大きく向上します。

1.1    唯一のガイドライン 

常識的な考え方を採用します。規則やガイドラインが見つからない場合、 規則が明らかに適用されていない場合、何もかもが失敗する場合は、 常識的な考え方に基づいて、基本的な原則を確認します。この規則は、 他のどの規則よりも優先されます。常識的な考え方は必要不可欠 です。


2    コーディング標準

Java のコーディング標準は重要です。これに従うことで、自分自身のコードや、 チームメイトのコード内で一貫性が保たれます。一貫性が維持されることにより理解が容易になり、 開発や保守が簡単になります。これにより、アプリケーションの作成にかかる総コストが削減されます。

作成した Java コードは、それを作成した開発者が別のプロジェクトに移った後でも、長い期間存在し続けることに注意してください。開発時の重要な目標は、 自分の作業が別の開発者や別の開発者チームに引き渡されたときに、 移行先の開発者が過度の調査をせずにコードを理解し、保守や拡張作業を継続できるようにすることです。 理解が困難なコードは、廃棄されるか、書き直される危険性があります。

2.1    命名規則

標準に関する説明では、どこでも命名規則について述べています。ここで、いくつかの基本的な点を説明しておきます。

  1. フルスペルの英語の記述子を使用して、変数、フィールド、 クラスの内容を正確に表します。例えば、firstNamegrandTotalCorporateCustomer などの名前を使用します。x1y1fn などの名前は短いので入力が簡単ですが、 これでは何を表しているか分からず、コードの理解、保守、拡張が困難になります。
  2. 対象となる分野に適切な用語を使用します。ユーザーが、 クライアント (client) のことを顧客 (customer) と呼んでいる場合は、 クラスに対して Customer という用語を使用します。Client という用語は使用しません。多くの開発者は、 業界や対象分野に適切な用語が存在しているのに、その概念に対して一般的な用語を当ててしまうという間違いを犯しています。
  3. 名前が読みやすいように、大文字と小文字を組み合わせて使用します。通常は小文字を使用しますが、 クラス名やインターフェース名の最初の文字は大文字にします。 また、名前の先頭以外にある単語の 1 文字目も、同様に大文字で表します。(参考資料 [KAN97])
  4. 略語は控えめに、できるだけ慎重に使用します。つまり、標準的な省略形 (略語) のリストを作成し、 適切なものを注意して選択し、それを一貫して使用するということです。例えば、"number" という単語の省略形を使用する場合は、nbrnonum のいずれかを選択し、 どれを選択したかを文書化し (どれを選択するかは問題ではありません)、以後は選択したものだけを使用します。
  5. 長い名前は避けます (15 文字未満が適切です)。クラス名 PhysicalOrVirtualProductOrService は適切な名前と思えますが、 この名前は長すぎます。Offering など、短い名前に変更すべきでしょう。
  6. 似たような名前や、違いが大文字と小文字だけであるような名前は避けます。例えば、 変数名 persistentObjectpersistentObjects は、同時に使用しないでください。 また、anSqlDatabaseanSQLDatabase の場合も同様です。
  7. 名前の先頭または末尾にアンダースコアーを付けないようにします。先頭または末尾にアンダースコアーを持つ名前は、 通常、システムで予約されています。ユーザーはこのような名前を作成しないようにしてください。さらに重要なことは、 アンダースコアーの入力が面倒であることです。可能な限り、アンダースコアーは使わないようにしてください。

2.2    文書化規則

文書化規則についても説明します。まず、いくつかの基本を示します。

  1. コメントを付加し、コードを明確にします。コードを文書化する目的は、自分自身、共同作業者、後任の開発者がコードをより理解しやすくすることにあります。
  2. 文書化する価値のないプログラムは、おそらく実行する価値もありません。 (参考資料 [NAG95])
  3. 過剰な装飾を避けます。つまり、バナーのようなコメントは使用しません。 1960 ~ 1970 年代の COBOL プログラマーには、コメントの前後をアスタリスクなどで囲む習慣がありました。 確かに、これは彼らの芸術的な主張を示す方法になりましたが、最終的な製品にほとんど価値を付加することがなく、 率直に言えば時間の無駄でした。面白みのあるコードではなく、すっきりとしたコードを作成してください。 さらに、コードの表示や印刷に使用されるフォントの多くがプロポーショナル・フォントである場合や、 そうでない場合があるので、囲みをきれいに揃えることはできません。
  4. コメントは簡潔にします。最適なコメントは、簡潔で要点をまとめた注釈です。本を書く必要はありません。 ほかの開発者がコードを理解するのに必要な情報があれば十分です。
  5. コードを作成する前に文書を記述します。コードを文書化する最適な方法は、 コードを作成する前にコメントを記述することです。こうすることで、コードを作成する前に、 コードがどのように動作するか、また文書に記述されたとおりにコードが動作するように考える機会になります。 これができない場合は、少なくともコードの作成とコードの文書化を同時に行います。文書によってコードが理解しやすくなります。 開発中にも、このことを利用することができます。文書の作成に時間をかければ、いずれにしても、 そこから何かが得られます (参考資料 [AMB98])。
  6. 何をしたかだけではなく、そうした理由を文書化します。例えば、 次の例 1 のコードは、$1,000 以上の注文に対して 5% の割引を実施することを示しています。 この理由は何でしょう。大口注文には割引が適用されるというビジネス・ルールがあるのでしょうか。 大口注文に対する期間限定の割引でしょうか。それとも、継続的な割引サービスでしょうか。 単にプログラマーが気前よかっただけでしょうか。ソース・コード自体か外部のドキュメントに文書化されていなければ、 その理由は誰にもわかりません。

例 1:

if ( grandTotal >= 1000.00)

{

grandTotal = grandTotal * 0.95;

}

2.2.1    Java コメントの種類

Java には、次の 3 種類のコメントがあります。 

次の表は、各コメントの使用方法に関する提案 と、使用例です。

コメントの種類 使用法
ドキュメンテーション ドキュメンテーション・コメントは、文書化するインターフェース、クラス、メンバー関数、フィールドの宣言の直前に使用します。ドキュメンテーション・コメントは javadoc で処理され (以下を参照)、クラスの外部文書が作成されます。 /**
Customer: A customer is any person or organization that we sell services and products to.
@author S.W. Ambler
*/
C 形式 C 形式のコメントは、不要になったコードを、開発者が考えを変えた場合に備えて残しておく場合や、デバッグ中に一時的にコードを無効化する場合に使用します。 /*
This code was commented out by B. Gustafsson on June 4, 1999 because it was replaced by the preceding code. Delete it after two years if it is still not applicable.
. . . (the source code )
*/
単一行 単一行コメントは、ビジネス・ロジック、コードの一部、一時変数の宣言を、メンバー関数内で文書化するために使用します。 // Apply a 5% discount to all
// Invoices Over $1000 Due To
// generosity campaign started in
// Feb. of 1995.

重要な点は、開発組織内で C 形式のコメントと単一行コメントの使用に関する標準を決定し、 これに一貫して従うことです。一方をビジネス・ロジックの文書化に使用し、 もう一方を古いコードのコメント化に使用します。コードと同じ行に文書を配置 (インライン化) できるため、 ビジネス・ロジックには単一行コメントを使用します。使わなくなったコードの文書化には、 複数の行を一度にコメント化できる C 形式のコメントを使用します。C 形式のコメントはドキュメンテーション・コメントと見た目が似ているため、 混同しないように、ほかの場所では使用しないようにします。

行末コメントへの注意 - 参考資料 [MCO93] では、インライン・コメント (行末コメント) の使用に強く異を唱えています。 McConnell 氏は、コードの視覚的な構造に干渉しないように、コメントはコードの右に整列されている必要があると指摘しています。その結果、整形が難しくなり、 「コメントを多量に使用すれば、それだけ作業に時間がかかることになります。このような時間は、 コードに対する理解を深めるためのものではなく、スペース・キーやタブ・キーを押すだけの単調な作業でしかありません。」また、 ある行のコードが長くなって行末のコメントの位置がずれた場合、 これを整列するにはほかの行でも同様の作業を行う必要があるため、行末コメントは保守を困難にすることも指摘されています。

2.2.2        javadoc の概要

Sun の Java Development Kit (JDK) には、javadoc と呼ばれるプログラムが含まれています。 このプログラムは、Java コード・ファイルを処理し、Java プログラムの外部文書を HTML ファイル形式で生成します。javadoc で サポートされるタグの数は限られています。タグは、ドキュメンテーション・セクションの開始を示す予約語です。 詳しくは、JDK の javadoc のマニュアルを参照してください。

タグ 使用対象 目的
@author 名前 クラス、インターフェース コードの該当部分の作成者を示します。作成者ごとに 1 つのタグを使用します。
@deprecated クラス、 メンバー関数 クラスの API が異を唱えられており、今後は使用すべきでないことを表します。
@exception 名前 説明 メンバー関数 メンバー関数がスローする例外について説明します。例外ごとに 1 つのタグを使用し、 例外にはクラスの完全な名前を使用します。
@param 名前 説明 メンバー関数 メンバー関数に渡されるパラメーターを説明するために使用します。タイプやクラス、 使用方法も記述します。パラメーターごとに 1 つのタグを使用します。
@return 説明 メンバー関数 メンバー関数の戻り値について説明します。戻り値のタイプやクラス、 使用例を指定します。
@since クラス、メンバー関数 項目がどのバージョン (例えば、JDK 1.1) から存在しているかを示します。
@see クラス名 クラス、インターフェース、メンバー関数、フィールド 指定したクラスへのハイパーテキスト・リンクを文書中に生成します。クラスの完全な名前を使用します。
@see クラス名#メンバー関数名 クラス、インターフェース、メンバー関数、フィールド 指定したメンバー関数へのハイパーテキスト・リンクを文書中に生成します。クラスの完全な名前を使用します。
@version テキスト クラス、インターフェース 指定したコードのバージョン情報を示します。

コードを文書化する方法は、自分自身の生産性と、後でコードを保守し拡張する担当者の生産性の両方に大きく影響を及ぼします。開発プロセスの初期段階でコードを文書化することにより、 コードに変換する前に論理全体を考察することができるため、より生産性を向上させることができます。 さらに、 数日または数週間前に作成したコードを見直す場合にも、文書化されていれば、作成時に何を考えていたかを容易に判断することができます。


3    メンバー関数に関する標準

今日作成したコードはこれから数年先にも利用され続け、ほかの開発者によって保守され拡張される可能性があることは、 常に念頭に置いておく必要があります。作成するコードは可能な限りすっきりと、理解しやすくするように努める必要があります。 このようにすると、保守や拡張が容易になります。

3.1    メンバー関数の命名

メンバー関数は、英語のフルスペルで記述し、頭文字でない単語は、 単語の 1 文字目を大文字にします。また、メンバー関数名の最初の単語は、動作を表す動詞にするのが一般的です。

例:

openAccount()

printMailingLabel()

save()

delete()

この規則により、メンバー関数の名前を見ただけで、その目的が分かるようになります。この規則に従うと名前が長くなるため、 開発者がタイピングする量はいくらか増えますが、コードの理解しやすさは大きく向上します。

3.1.1    アクセサー・メンバー関数の命名

アクセサーについては次の章で詳しく説明します。アクセサーは、フィールド (フィールドまたはプロパティー) の値を取得し、 設定するメンバー関数です。ここでは、アクセサーの命名規則について概要を説明します。

3.1.1.1    Getter 

Getter は、フィールドの値を返すメンバー関数です。フィールドの名前の前に "get" という接頭辞を付けます。 ただし、論理型のフィールドの場合は、フィールド名の前に "is" という接頭辞を付けます。

例:

getFirstName()

getAccountNumber()

isPersistent()

isAtEnd()

この命名規則に従うと、メンバー関数がオブジェクトのフィールドを返すことを明確に示すことができます。 また、論理型の Getter の場合は、TRUE または FALSE を返すことを明確に示すことができます。 この標準の別の利点として、Getter メンバー関数は Beans Development Kit (BDK) で使用される命名規則に従っています (参考資料 [DES97])。不利な点は、"get" という入力が余分に必要であるという点です。

Getter のその他の命名規則: has と can

正しい英語表現に基づくなら、論理型の Getter の接頭辞は、"is" ではなく "has" または "can" になるはずです。 例えば、hasDependents()canPrint() のような名前の Getter は、 コードを読んだときにさまざまな意味に取れます。この方法の問題は、BDK がこの命名方法を (まだ) 採用していないことです。 これらのメンバー関数名は、isBurdenedWithDependents()isPrintable() に変更できます。

3.1.1.2    Setter

Setter は、フィールドの値を変更するメンバー関数で、mutator とも呼ばれます。フィールドの名前には、 フィールドのタイプに関係なく、"set" という接頭辞を付けます。

例:

setFirstName(String aName)

setAccountNumber(int anAccountNumber)

setReasonableGoals(Vector newGoals)

setPersistent(boolean isPersistent)

setAtEnd(boolean isAtEnd)

この命名規則に従うと、メンバー関数がオブジェクトのフィールドの値を設定することを明確に示すことができます。 この標準の別の利点として、Setter メンバー関数は BDK で使用される命名規則に従っています (参考資料 [DES97])。不利な点は、"set" という 入力が余分に必要であるという点です。

3.2    コンストラクターの命名

コンストラクターは、オブジェクトが作成されるときに、 必要な初期化を行うメンバー関数です。コンストラクターの名前は、常にクラスと同じになります。 例えば、クラス Customer のコンストラクターは Customer() です。大文字と小文字も同じになります。

例:

Customer()

SavingsAccount()

PersistenceBroker()

この命名規則は、Sun Microsystems によって決定されたものであり、厳守する必要があります。

3.3    メンバー関数の可視性

クラス同士の結合度が最小になるように適切な設計を行うには、 経験的に、メンバー関数の可視性を指定するときに可能な限り制限を強くします。メンバー関数を public にする必要がない場合は、 これを protected にします。また、protected にする必要がない場合は、private にします。

可視性 説明 適切な使用方法
public public メンバー関数は、ほかのオブジェクトやクラスのどのメンバー関数からでも呼び出すことができます。 メンバー関数が定義されているクラス階層の外部にあるオブジェクトやクラスからアクセスする必要がある場合に使用します。
protected protected メンバー関数は、定義されているクラス、そのクラスのサブクラス、同じパッケージのクラスのいずれかのメンバー関数から呼び出すことができます。 メンバー関数が、クラス階層やパッケージの外部ではなく内部だけで必要な振る舞いを提供している場合に使用します。
private private メンバー関数は、その関数が定義されているクラス内のほかのメンバー関数からだけ呼び出すことができます。サブクラス内のメンバー関数から呼び出すことはできません。 メンバー関数は、 クラスに固有の振る舞いを提供する場合に使用します。private メンバー関数は、 クラス内のほかのメンバー関数の振る舞いをリファクタリング (または、再編成) した結果として生成され、 特定の振る舞いをカプセル化します。
default デフォルト (可視性を指定しない状態) では、関数は定義されているクラスまたは同じパッケージ内のクラスのほかのメンバー関数のみから呼び出すことができます。 メンバー関数が、同じパッケージ内のクラスで必要な振る舞いを提供し、外部またサブクラスには提供しない場合に使用します。

3.4    メンバー関数の文書化

多くの場合、メンバー関数を文書化する方法は、理解しやすいかどうか、つまり保守容易性と拡張性に関する決定要因となります。

3.4.1    メンバー関数のヘッダー

すべての Java メンバー関数では、メンバー関数文書と呼ばれる、ある種のヘッダーをソース・コードの先頭に記述します。 ヘッダーには、メンバー関数を理解するために必要な情報をすべて文書化します。この情報の例として、以下があります。

  1. メンバー関数の動作とその理由。メンバー関数の動作を文書化することで、 ほかの開発者がそのコードを再利用できるかどうかを判断しやすくなります。メンバー関数の動作の理由を文書化することで、 ほかの開発者がコードの使用状況を判断しやすくなります。また、 実際にコードに新たな変更を行うべきかどうかも判断しやすくなります (新たな変更を行う理由は、おそらくコードが最初に作成された理由と矛盾しています)。
  2. メンバー関数に渡す必要のあるパラメーター。パラメーターがある場合は、メンバー関数に渡す必要のあるパラメーターと、 その使用方法を示す必要があります。この情報は、 メンバー関数にどのような情報を渡すかについて、ほかのプログラマーが確認する際に必要となります。「2.2.2, javadoc の概要」 で説明した、javadoc@param タグが、この目的で使用されます。
  3. メンバー関数の戻り値。戻り値がある場合は、メンバー関数の戻り値について 文書化し、ほかのプログラマーが戻り値またはオブジェクトを適切に使用できるようにする 必要があります。「2.2.2, javadoc の概要」 で説明した、javadoc@return タグが、この目的で使用されます。
  4. 既知のバグ。メンバー関数に関する未解決の問題を文書化し、 ほかの開発者がその欠点と問題点を理解できるようにします。 クラス内の複数のメンバー関数に関係するバグの場合は、クラスに関して文書化します。
  5. メンバー関数がスローする例外。メンバー関数がスローするすべての例外を文書化し、 ほかのプログラマーが各自のコードで何をキャッチする必要があるかを伝えます。「2.2.2, javadoc の概要」 で説明した、javadoc@exception タグが、この目的で使用されます。
  6. 可視性の決定。メンバー関数の可視性の選択について、ほかの開発者から質問を受けると思われる場合は、その決定について文書化しておきます。 例えば、ほかのオブジェクトから呼び出されることのないメンバー関数を public に指定している場合などです。これにより、 各開発者の考えがほかの開発者にも明らかとなり、時間を無駄にすることがありません。
  7. メンバー関数がどのようにオブジェクトを変更するか。 メンバー関数がオブジェクトを変更する場合は、これを明記する必要があります。 例えば、銀行口座の withdraw() メンバー関数が口座残高を変更するような場合です。 この情報は、ほかの Java プログラマーが、 メンバー関数の呼び出しがターゲット・オブジェクトにどのように影響を及ぼすかを正確に把握するために必要です。
  8. ヘッダーには含めない情報。作成者、電話番号、作成日と更新日、 ユニットの場所 (またはファイル名) などはすぐに古い情報となるため、 ヘッダーには記述しません。著作権に関する注意事項はユニットの末尾に記述します。 例えば、プログラムの理解に役立たないテキストを、2 ページも 3 ページもスクロールして読みたいとは思わないでしょう。 また、著作権に関する注意事項など、プログラムを何も実行しないテキストをスクロールして表示したいとも思わないはずです。垂直バーや囲みは使用しないようにします。 これらは視覚的に邪魔になるだけでなく、一貫性を保ちにくくします。 構成管理ツールを使用して、ユニットの履歴を保持します。
  9. メンバー関数の呼び出し方法の例。コードの動作を理解する最も簡単な方法の 1 つは、 使用例を見ることです。メンバー関数の呼び出し方法に関して、例を 1 つか 2 つ記述することを検討してください。
  10. 適切な事前条件と事後条件。事前条件は、メンバー関数が適切に機能するための制約です。 事後条件は、メンバー関数の実行が完了した後で TRUE になるプロパティーまたはアサーションです (参考資料 [MEY88])。 多くの場合、事前条件と事後条件は、メンバー関数の作成時に決定した仮定を表し (参考資料 [AMB98])、 メンバー関数が使用される範囲を正確に定義します。
  11. 並行性に関するすべての問題。 並行性は、多くの開発者にとって新しい複雑な概念です。 並行プログラミングの経験を持つプログラマーにとっても、見慣れてはいても、 やはり複雑な問題です。要するに、Java の並行プログラミング機能を使用する場合は、 それを完全に文書化する必要があります。参考資料 [LEA97] では、 クラスに同期と非同期のメンバー関数がどちらも含まれる場合は、 メンバー関数が依存する実行状況を文書化する必要があると提案されています。 特に、メンバー関数に制限のないアクセスが必要な場合は文書化が必要で、 ほかの開発者がメンバー関数を安全に使用できるようにします。Runnable インターフェースを実装するクラスの Setter (フィールドを更新するメンバー関数) が synchronized でない場合は、 その理由を文書化します。最後に、メンバー関数をオーバーライドまたは多重定義して、その同期の指定を変更する場合は、その理由も文書化します。
  12. 文書化は、それによってコードが明確になる場合にだけ行います。各メンバー関数とすべてのメンバー関数に対して、 ここに述べた要素のすべてを文書化する必要はありません。いつでもすべての要素を適用できるとは限りません。 メンバー関数を作成するごとに、上の要素のいくつかを文書化することになります。

3.4.2    内部文書

メンバー関数の文書に加え、メンバー関数の内部にコメントを記述して、 各自の作業を説明する必要もあります。その目的は、メンバー関数の理解、保守、拡張を容易にすることです。

コード内部に文書を記述するには、C 形式のコメント ( /* と */ ) と単一行コメント ( // ) の、2 種類のコメントを使用します。前に説明したように、 コードのビジネス・ロジックを文書化するためのコメント形式と、 不要なコードのコメント化に使用するコメント形式を十分に考慮して使用してください。ビジネス・ロジックのコメントには、単一行コメントを提案します。 このコメント形式は、コメント行全体をコメントにする場合にも、 コードの後ろに続くインライン・コメントにも使用できます。C 形式のコメントは、 不要なコード行のコメント化に使用します。1 つのコメントで、 複数の行を簡単にコメント化できます。 また、C 形式のコメントはドキュメンテーション・コメントと似ているため、混乱を招く可能性があり、 コードが理解しにくくなります。したがって、あまり使用しないようにしてください。

内部的に、次の項目は常に文書化してください。

  1. 制御構造。比較ステートメントやループなどの、制御構造をそれぞれ説明します。制御構造中のすべてのコードを読まなくても、 直前の 1 ~ 2 行のコメントを見れば動作内容が分かるようにします。
  2. コードの実行内容とその理由。 コードのある部分を見て、その動作内容を理解することはできます。ただし、あいまいなコードでは、 それが作成された理由まではわかりません。例えば、1 行のコードを見れば、 注文総額に 5% の割引が適用されることは簡単に理解できます。これは簡単なことです。 ただし、その割引が適用される理由を理解することは簡単ではありません。 割引を適用するというビジネス・ルールが存在することは明らかです。 コードの理由をほかの開発者が理解できるように、少なくともコード中でそのビジネス・ルールについて説明しておきます。
  3. ローカル変数。ローカル変数については、第 5 章で詳しく説明します。 メンバー関数で定義されるローカル変数は 1 行に 1 つずつ宣言し、通常は使用方法に関するインライン・コメントを付加します。
  4. 難しいコードまたは複雑なコード。コードを作成し直すことができない、または作成し直す時間がない場合は、 メンバー関数内の複雑なコードを完全に文書化しておく必要があります。経験的には、 コードが明確でない場合は文書化が必要です。
  5. 処理順序。コード中に、定義された順序での実行が必要なステートメントがある場合は、 その内容を文書化します (参考資料 [AMB98])。コードが機能しないことを調査するためだけに、 コードに簡単な変更を加えた結果、何時間も問題を調査することになり、結局ステートメントの順序が違っているだけだったと分かるほど無益なことはありません。
  6. 閉じ括弧。制御構造の中に制御構造が入れ子になる場合があります。このようなコードは避けるべきですが、 入れ子にした方が適切に記述できる場合もあります。問題は、閉じ括弧の } 文字が、 どの制御構造に属するのかわからなくなることです。コード・エディターによっては、開き括弧を選択すると、対応する閉じ括弧が強調表示されます。 ただし、すべてのエディターがこの機能をサポートしているわけではありません。//end if//end for//end switch などの インライン・コメントで閉じ括弧にコメントを付けると、コードが理解しやすくなります。

3.5    きれいなコードを作成する技術

ここでは、プロの開発者とそれ以外のコード作成者とを選り分けている技術について説明します。これらの技術を次に示します。

3.5.1    コードを文書化する 

文書化する必要のないコードは、保持しておく価値がない (参考資料 [NAG95]) ことに注意してください。 ここで提案されている文書化に関する標準やガイドラインを適切に採用すれば、コードの品質を大きく向上させることができます。

3.5.2    段落やインデントを使用する 

メンバー関数の読みやすさを向上させる方法の 1 つとして、コードの段落化があります。 つまり、コード・ブロックのスコープでコードをインデントする方法です。中括弧 ({}) で囲まれるコードは ブロックを形成します。基本的な考え方は、ブロック内のコードを 1 つのユニットとして一律にインデントするということです。

Java の慣例では、開き括弧はブロックの所有者の次の行に置かれ、閉じ括弧は 1 レベル分インデントされます。 重要な点は、参考資料 [LAF97] で指摘されているように、 組織でインデント形式を決定し、それに一貫して従うことです。Java 開発環境がコード生成に使用しているのと同じインデント形式を使用してください。

3.5.3    空白を使用する 

Java コードにブランク行を追加することで、コードが小さな要約しやすい部分に分割され、 より読みやすくなります。[参考資料 [VIS96] では、コードの論理グループ (制御構造など) を分けるために 1 行のブランク行を、 メンバー関数の定義を分けるために 2 行のブランク行を使用することが提案されています。空白がないと、コードは読みづらく、理解も困難になります。

3.5.4    30 秒ルールに従う 

ほかのプログラマーがメンバー関数を見たときに、その動作、理由、 方法が 30 秒以内で十分に理解できるようにします。30 秒以内で理解できない場合は、コードの保守が困難です。 改良することをお奨めします。あくまでも 30 秒です。経験的には、メンバー関数の長さが 1 画面を超えると長すぎるようです。

3.5.5    簡潔に、1 行に 1 つのコマンドを記述する 

1 行で 1 つのことだけを行います。パンチ・カードの時代には、1 行のコードにできるだけ多くの機能を詰め込むことに意味がありました。1 行で複数の機能を実行しようとすると、 必ず理解するのが困難になります。なぜ 1 行に 1 つのコマンドにするのでしょうか。 コードを理解しやすくして、コードの保守や拡張を容易にしたいからです。 メンバー関数がただ 1 つの動作だけを行うのと同じように、1 行のコードでは 1 つの動作だけを行います。

また、一画面に収まるようにコードを記述してください (参考資料 [VIS96])。インライン・コメントを使用しているコードを含め、 コード行全体を読むために編集ウィンドウを右にスクロールする必要がないようにします。

3.5.6    演算の順序を指定する 

コードの理解しやすさを簡単に向上させる方法は、 括弧 (丸括弧) を使用して、Java コード中の演算の順序を正確に指定することです。 参考資料 [NAG95] と [AMB98] を参照してください。ソース・コードを理解するために、 言語の演算順序を知っておく必要があるとしたら、重大な誤りがあります。この問題は主に、 別の比較演算と共に AND や OR を計算する論理比較で生じます。簡潔に、1 行に 1 つのコマンドを記述している場合は、この点は実際には問題になりません。


4    フィールドとプロパティーに関する標準

ここで使用するフィールド という用語は、BDK でプロパティーと呼んでいるフィールドを表します (参考資料 [DES97])。フィールドは、 オブジェクトやクラスを表すデータの一部分です。フィールドは、string や float のような基本データ型か、顧客や銀行口座などのオブジェクトになります。

4.1    フィールドの命名

英語のフルスペルの記述子を用いてフィールドに名前を付けます。これにより、フィールドが何を表しているかを明確にします。 参考資料 [GOS96] と [AMB98] を参照してください。 配列やベクトルなどのコレクションを表すフィールドには複数形の名前を付けて、複数の値を持つことを表します。

例:

firstName

zipCode

unitPrice

discountRate

orderItems

4.1.1    コンポーネントの命名 (ウィジェット)

コンポーネント (インターフェース・ウィジェット) の名前では、 ウィジェットのタイプの後に英語のフルスペルの記述子を付加します。これにより、コンポーネントの目的やタイプが識別しやすくなり、 リストで各コンポーネントを見つけやすくなります。多くのビジュアル・プログラミング環境では、 アプレットやアプリケーションのすべてのコンポーネントがリストに表示されます。 すべてが button1button2 のような名前であると、混乱する可能性があります。

例:

okButton

customerList

fileMenu

newFileMenuItem

4.1.1.1    コンポーネントのその他の命名方法: ハンガリアン記法 

「ハンガリアン記法」 (参考資料 [MCO93]) は、 フィールド名を xEeeeeeEeeeee という形式で指定するという原則に基づきます。x はコンポーネントのタイプを表し、EeeeeeEeeeee は英語のフルスペルによる記述子です。

例:

pbOk

lbCustomer

mFile

miNewFile

主な利点は、この記法が C++ コードで一般的な業界標準であり、多くの開発者がこの記法に従っていることです。 変数の名前から、開発者はそのタイプと使用方法をすぐに判断できます。主な欠点は、接頭表記法になることです。

4.1.1.2    コンポーネントのその他の命名方法: 接尾辞ハンガリアン記法 

これは基本的に、ほかの 2 つの方法の組み合わせたものであり、okPbcustomerLbfileMnewFileMi などの名前になります。 主な利点は、コンポーネントの名前がウィジェットのタイプを表すことと、 同じタイプのウィジェットがアルファベット順のリストでグループ化されないことです。 主な欠点は、英語のフルスペルを使用していないので、基準から外れ、標準を思い出すのが困難になることです。

4.1.1.3    コンポーネント名に関する標準の設定 

どのような規則を選択した場合でも、「公式な」ウィジェット名のリストを作成します。例えば、 ボタンの名前を付ける場合は、ButtonPushButton、または bpb を使用します。 リストを作成し、組織内のすべての Java 開発者がそのリストを利用できるようにします。

4.1.2    定数の命名

Java では、定数は変更できない値で、一般的にはクラスの static final フィールドとして実装されます。よく知られた命名規則は、英単語のフルスペルを使用し、 すべての文字を大文字で表し、単語間にアンダースコアーを入力する方法です (参考資料 [GOS96])。

例:

MINIMUM_BALANCE

MAX_VALUE

DEFAULT_START_DATE

この規則の主な利点は、変数と定数を区別しやすいことです。後で詳しく説明しますが、 定数を定義せずに、定数の値を返す Getter メンバー関数を定義することで、コードの柔軟性と保守容易性を大きく向上させることができます。

4.1.3    コレクションの命名

配列やベクトルなどのコレクションには、配列に保持されるオブジェクトのタイプを表す複数形の名前を使用します。名前には英語のフルスペルの記述子を使用し、 先頭以外の各単語の 1 文字目は大文字にします。

例:

customers

orderItems

aliases

この規則の主な利点は、複数の値 (コレクション) を表すフィールドと、単一の値 (非コレクション) を表すフィールドを区別できることです。

4.2    フィールドの可視性

フィールドが protected と宣言されている場合、サブクラスのメンバー関数がフィールドに直接アクセスする可能性があり、 クラス階層の結合度が大きく増加します。クラスの保守や拡張をより困難にするので、こうした宣言は行わないでください。フィールドには直接アクセスしないようにして、 代わりに (後に示す) アクセサー・メンバー関数を使用します。

可視性 説明 適切な使用方法
public public フィールドは、ほかのオブジェクトやクラスのどのメンバー関数からでもアクセスできます。 フィールドを public に指定しないでください。
protected protected フィールドには、宣言されているクラス内のすべてのメンバー関数から、またはそのクラスのサブクラスで定義されているすべてのメンバー関数からアクセスできます。 フィールドを protected に指定しないでください。
private private フィールドは、それが宣言されているクラス内のメンバー関数からのみアクセスできます。サブクラス内のメンバー関数からはアクセスできません。 すべてのフィールドは private に指定し、Getter または Setter メンバー関数 (アクセサー) を使ってアクセスします。

永続性を持たない (永続ストレージに保存されない) フィールドには、static または transient のいずれかを指定します (参考資料 [DES97])。これにより、BDK の規則に準拠します。

4.2.1    名前を「隠蔽」しない 

名前の隠蔽とは、ローカル変数、引数、フィールドに、 よりスコープの広いほかの変数と同じ (または類似した) 名前を付けることです。例えば、firstName という フィールドがある場合は、firstName というローカル変数やパラメーターを 作成しないようにします。 また、firstNamesfirstName のように近い名前も使用しません。 名前の隠蔽は、コードを理解しにくくし、バグを生み出す原因になります。 ほかの開発者や自分自身でも、編集中にコードを読み間違えて、エラーの発見が難しくなります。

4.3    フィールドの文書化

すべてのフィールドは、ほかの開発者が理解できるように十分に文書化します。文書化を効果的に行うには、次の文書を作成します。

  1. フィールドの説明。ほかの開発者が使用方法を理解できるように、フィールドを説明する必要があります。
  2. 適用できるすべての不変条件。フィールドの不変条件は、そのフィールドについて常に TRUE となる条件です。 例えば、dayOfMonth フィールドに関する不変条件は、値が 1 ~ 31 になることです (月と年に基づいてフィールドの値を制限することで、 この不変条件はさらに複雑になります)。フィールドの値に関する制限を文書化することで、重要なビジネス・ルールを定義して、 コードの動作を理解しやすくすることができます。
  3. 使用例。複雑なビジネス・ルールが関連付けられたフィールドでは、理解しやすいように、 いくつかの値の例を記述します。言葉でいくら説明するよりも、1 つの例を示すほうがわかりやすいものです。
  4. 並行性の問題。並行性は、多くの開発者にとって新しい複雑な概念です。並行プログラミングの経験を持つプログラマーにとっても、 見慣れてはいても、やはり複雑な問題です。要するに、Java の並行プログラミング機能を使用する場合は、それを完全に文書化する必要があります。
  5. 可視性の決定。フィールドの宣言で private 以外の可視性を指定する場合は、 その理由を文書化します。フィールドの可視性は、「4.2, フィールドの可視性」 で説明しました。また、アクセサー・メンバー関数の使用によるカプセル化のサポートについては、 「 4.4, アクセサー・メンバー関数の使用法」 で説明します。要点は、変数を private 以外に宣言する場合は、実際にそれだけの理由があるということです。

4.4    アクセサー・メンバー関数の使用法

フィールドの保守容易性は、命名規則に加えて、適切なアクセサー・メンバー関数 を使用することにも関係します。アクセサーは、フィールドを更新したり、 値にアクセスするための機能を提供するメンバー関数です。アクセサー・メンバー関数には、Setter (または mutator) と Getter の 2 つがあります。Setter は変数の値を変更します。一方、Getter は変数の値を取得します。

アクセサー・メンバー関数を使用するとコードにオーバーヘッドが生じます。ただし、現在の Java コンパイラーはこうした使い方に対して最適化されているので、 これは必ずしも正しいとは言えません。アクセサーは、クラスの実装の詳細を隠蔽します。変数へアクセスする場所を 2 つ (Setter と Getter) だけに制限することで、 変更が必要となる箇所が最小となり、クラスの保守容易性を向上させることができます。Java コードの最適化は、 「9.3, Java コードの最適化」で説明します。

組織で実施できる最も重要な標準の 1 つが、アクセサーを使用することです。 タイピングの量が増えるために、アクセサー・メンバー関数の使用を嫌がる開発者もいます。 例えば、Getter の場合、フィールド名の前後に "get" と "()" を入力する必要があります。重要な点は、 アクセサーの使用を正当化すること自体ではなく、アクセサーの使用により保守容易性と拡張性が向上するということです。

アクセサーは、フィールドにアクセスできる唯一の場所です。アクセサー・メンバー関数を適切に使用するという概念は、 フィールドを直接操作することを許可されたメンバー関数だけが、 アクセサー・メンバー関数自身であるということです。確かに、 フィールドが定義されているクラスのメンバー関数内で、private フィールドに直接アクセスすることもできますが、 これはクラスの結合度を増大させることになります。

4.4.1    アクセサーを使用する理由 

「優れたプログラム設計は、不要で意図しない外部の影響から、プログラムの各部分を分離しようとします。 アクセス修飾子 (アクセサー) は、これらの制限を管理する言語に対して、明示的で検証可能な手段を提供します。」(参考資料 [KAN97])

アクセサー・メンバー関数は、次のような方法でクラスの保守容易性を向上させます。

  1. フィールドの更新。各フィールドを更新する手段を 1 つにまとめ、変更やテストを簡単にします。言い換えると、フィールドがカプセル化されます。
  2. フィールドの値の取得。フィールドがどこからどのような方法でアクセスされるかを完全に制御します。
  3. 定数の値とクラスの名前の取得。定数とクラス名を Getter メンバー関数でカプセル化することにより、 これらの値や名前を変更する場合は、Getter の値を更新するだけで作業が完了します。 定数や名前が使用されているコード行を変更する必要はありません。
  4. フィールドの初期化。遅延初期化を使用して、フィールドが常に、必要なときにだけ初期化されるようにします。
  5. サブクラスとスーパークラス間の結合度の減少。サブクラスがスーパークラスから継承したフィールドに、 対応するアクセサー・メンバー関数だけを通してアクセスする場合は、サブクラスに影響を与えることなく、 スーパークラスのフィールドの実装を変更できます。サブクラスとスーパークラス間の結合度は効果的に下がります。 アクセサーは、スーパークラスの変更がサブクラスに波及するという「脆弱な基底クラス」のリスクを削減します。
  6. フィールドへの変更のカプセル化。1 つまたは複数のフィールドに関係するビジネス・ルールを変更する場合は、 アクセサーを変更して、変更前と同じ機能を維持することで、新しいビジネス・ルールに対応しやすくなります。
  7. 並行性に関する問題の単純化。参考資料 [LEA97] では、 フィールドの値に基づいて重み付けを行う場合、Setter メンバー関数は notifyAll のインクルードを行う場所を 1 箇所に限定すると指摘しています。 これにより、並行性のソリューションに移りやすくなります。
  8. 名前の隠蔽問題の無効化。ローカル変数にはフィールドと同じ名前を付けないようにして、名前の隠蔽を避けるべきですが、 常にアクセサーを使用してフィールドにアクセスすることで、ローカル変数に自由に名前を付けることができます。 フィールドに直接アクセスしなくなるため、フィールド名の隠蔽について注意する必要がなくなります。

4.4.1.1    アクセサーを使用しない場合 

アクセサーの使用を避けようと考えるのは、実行時間が最も重要視される場合だけです。ただし、 アプリケーション内の結合度が増大することを正当化できるようなケースはほとんどありません。

4.4.2    アクセサーの命名

Getter メンバー関数には、"get" + フィールド名の名前を付けます。 ただし、フィールドが論理値 (TRUE または FALSE) を表す場合は、"is" + フィールド名の名前を付けます。Setter メンバー関数には、 フィールドのタイプにかかわらず、"set" + フィールド名の名前を付けます (参考資料 [GOS96] と [DES97])。 フィールド名は大文字と小文字で構成し、名前の中に含まれる単語の 1 文字目は常に大文字で表します。 この命名規則は JDK で一貫して使用され、Bean 開発では必須です。

例:

フィールド Type Getter 名 Setter 名
firstName
string
getFirstName()
setFirstName()
address
Address 
オブジェクト
getAddress()
setAddress()
persistent
boolean
isPersistent()
setPersistent()
customerNo
int
getCustomerNo()
setCustomerNo()
orderItems
 
OrderItem 
オブジェクトの 
配列
getOrderItems()
 
setOrderItems()
 

 

4.4.3    アクセサーに関する高度な技術

アクセサーは、インスタンス・フィールドの値の取得と設定以外でも使用できます。ここでは、次の操作に対してアクセサーを使用して、コードの柔軟性を向上させる方法を説明します。

4.4.3.1    遅延初期化 

変数は、アクセスされる前に初期化する必要があります。初期化には 2 つの方法があります。1 つは、オブジェクトが作成されたときにすべての変数を初期化する (従来の) 方法です。 もう 1 つは、変数が最初に使用されるときに初期化する方法です。  

1 番目の方法では、オブジェクトが最初に作成されたときに呼び出される、特殊なメンバー関数を使用します。 このメンバー関数をコンストラクターと呼びます。この方法は正しく機能しますが、エラーとなりやすい場合があります。 新しい変数を追加するときに、コンストラクターの更新を忘れる可能性があります。

もう 1 つの方法は遅延初期化 と呼ばれます。次の例に示すように、 フィールドは Getter メンバー関数によって初期化されます。Getter メンバー関数内での、 Setter メンバー関数の使用法に注意してください。メンバー関数は、 支店番号が 0 であるかどうかを確認します。支店番号が 0 の場合は、 適切なデフォルト値を設定します。

/** Answers the branch number, which is the leftmost

four digits of the full account number.

Account numbers are in the format BBBBAAAAAA.

*/

protected int getBranchNumber()

{

if ( branchNumber == 0)

{

// The default branch number is 1000, which

// is the main branch in downtown Bedrock.

setBranchNumber(1000);

}

return branchNumber;

}

フィールドが実際にはデータベースに格納されているほかのオブジェクトである場合、 遅延初期化が一般的に使用されます。例えば、新しい在庫品を作成する場合、 デフォルトに設定した在庫品目のすべてのタイプをデータベースから取得する必要はありません。代わりに遅延初期化を使用して、 最初にアクセスされたときにこの値を設定します。必要なときにだけ、データベースから在庫品目のタイプのオブジェクトを取り出します。 

これは、定期的にアクセスされないフィールドを持つオブジェクトで都合のよい方法です。 永続ストレージからデータを取得する際のオーバーヘッドも、使用しないなら発生しません。

例に示したように、Getter メンバー関数で遅延初期化を使用する場合は、 必ずデフォルト値の理由を文書化します。 このときに、フィールドがコード中でどのように使用されているかを明らかにして、保守容易性と拡張性の両方を向上させます。

4.4.3.2    定数に対するアクセサー

Java の一般的な慣例では、定数値を static final フィールドとして実装します。この方法は、 安定していることが保証されている「定数」でだけ意味があります。例えば、 クラス BooleanTRUEFALSE の 2 つの static final フィールドを実装し、 そのクラスの 2 つのインスタンスを表します。また、 値が変更されることのない DAYS_IN_A_WEEK などの定数でも意味があります。

ただし、いわゆるビジネス「定数」の多くは、ビジネス・ルールの変更に応じて更新されます。 以下の例を検討してみてください。Archon Bank of Cardassia (ABC) では、 残高が $500 以上の口座に対して利息を付与することにしています。これを実装するには、 クラス Account に MINIMUM_BALANCE という static フィールドを追加し、 利息を計算するメンバー関数で使用します。この方法は正しく動作しますが、柔軟ではありません。 ビジネス・ルールが変更され、口座の種類に応じて最低残高が変更された場合はどうなるでしょう。 例えば、最低残高が貯蓄預金では $500、当座預金では $200 となったらどうでしょうか。 また、1 年目は最低残高が $500、2 年目は $400、3 年目には $300 などのようになったらどうでしょうか。 夏期は $500 で、冬季は $250 となる場合もあるでしょう。将来的には、これらのルールをすべて組み合わせて実装する必要が生じるでしょう。

要点は、定数をフィールドとして実装することは柔軟性に欠けるということです。より適切な解決法は、 定数を Getter メンバー関数として実装することです。 ここで示した例では、MINIMUM_BALANCE という static フィールドよりも、static (クラス) メンバー関数 getMinimumBalance() を使用するほうがより柔軟です。 このメンバー関数でさまざまなビジネス・ルールを実装したり、口座の種類に応じてメンバー関数をサブクラス化することができます。

/** Get the value of the account number. Account numbers are in the following 
    format: BBBBAAAAAA, where BBBB is the branch number and 
    AAAAAA is the branch account number.
*/
public long getAccountNumber()
{
	return ( ( getBranchNumber() * 100000 ) + getBranchAccountNumber() );
}
/**
	Set the account number. Account numbers are in the following 
	format: BBBBAAAAAA where BBBB is the branch number and
	AAAAAA is the branch account number.
*/
public void setAccountNumber(int newNumber)
{
	setBranchAccountNumber( newNumber % 1000000 );
	setBranchNumber( newNumber / 1000000 );
}

定数の Getter を使用するその他の利点は、コードの一貫性を向上させるのに役立つことです。前のコード例を見てください。 実際には、これは正しく動作しません。口座番号は、支店番号と支店口座番号を組み合わせたものです。このコードをテストすると、Setter メンバー関数 setAccountNumber() は、 支店口座番号を正しく更新しないことがわかります。左の 4 桁ではなく、3 桁が処理されています。これは、 フィールド branchAccountNumber から抽出するために、100,000 ではなく 1,000,000 を使用しているためです。この値の記述を、 定数 Getter の getAccountNumberDivisor() にまとめました。コードの一貫性が向上し、正しく動作するようになります。

/**
	Returns the divisor needed to separate the branch account number from the 
	branch number within the full account number. 
	Full account numbers are in the format BBBBAAAAAA.
*/
public int getAccountNumberDivisor()
{
	return ( (long) 1000000);
}
/**
	Get the value of the account number. Account numbers are in the following 
	format: BBBBAAAAAA, where BBBB is the branch number and 
	AAAAAA is the branch account number.
*/
public long getAccountNumber()
{
	return ( ( getBranchNumber() * getAccountNumberDivisor() ) + getBranchAccountNumber() );
}
/**
	Set the account number. Account numbers are in the following 
	format: BBBBAAAAAA where BBBB is the branch number and
	AAAAAA is the branch account number.
*/
public void setAccountNumber(int newNumber)
{
	setBranchAccountNumber( newNumber % getAccountNumberDivisor() );

	setBranchNumber( newNumber / getAccountNumberDivisor() );
}

定数にアクセサーを使用することで、バグの発生を減少させると共に、 システムの保守容易性を向上させます。口座番号の形式が変更された場合や、変更される予定がある場合、 口座番号を構成または分離するのに必要な情報を隠蔽し集中化しているため、コードの変更は容易です。

4.4.3.3    コレクションに対するアクセサー

アクセサーの主要な目的は、フィールドへのアクセスをカプセル化して、 コードの結合度を低下させることです。配列やベクトルなどのコレクションは単一の値を持つフィールドよりも複雑であるため、 標準的な Getter と Setter メンバー関数を実装すること以外にも必要な処理があります。 特に、コレクションでは要素の追加や削除が行われるため、 アクセサー・メンバー関数にはこれらの機能が必要になります。コレクションのフィールドに適切な、次のアクセサー・メンバー関数を追加します。

メンバー関数の種類 命名規則
コレクションの Getter
getCollection()
getOrderItems()
コレクションの Setter
setCollection() 
setOrderItems()
コレクションへのオブジェクトの追加
insertObject()
insertOrderItem()
コレクションからのオブジェクトの削除
deleteObject()
deleteOrderItem()
新しいオブジェクトの作成とコレクションへの追加
newObject()
newOrderItem()

この方法の利点は、コレクションが完全にカプセル化され、後でリンク・リストや B-tree などのほかの構造に置き換えることができることです。

4.4.3.4    複数のフィールドへの同時アクセス

アクセサー・メンバー関数を使用する大きな利点は、ビジネス・ルールを効果的に実施できることです。例えば、 図形のクラス階層を考えてください。Shape の各サブクラスは、"xPosition" と "yPosition" の 2 つのフィールドを通して位置を確認できます。 また、メンバー関数 move(Float xMovement, Float yMovement) を呼び出すことで、2 次元の画面上を移動できます。ここでの目的として、 図形を一度に 1 つの軸方向にだけ移動させても意味はありません。x 軸と y 軸の方向に同時に 移動させます (move() メンバー関数のいずれかのパラメーターとして、0.0 の値を渡すのはかまいません)。 暗黙的に、move() メンバー関数は public にしますが、メンバー関数の setXPosition()setYPosition() は private に指定します。 これらは、move() メンバー関数によって呼び出されます。

別の実装方法として、次に示すように、両方のフィールドを一度に更新する Setter メンバー関数を導入する方法もあります。 メンバー関数の setXPosition()setYPosition() は private にして、 外部クラスやサブクラスから直接呼び出せないようにします (文書を追加して、直接呼び出さないようにすることを示します)。

/** Set the position of the shape */
protected void setPosition(Float x, Float y)
{
	setXPosition(x);
	setYPosition(y);
}
/** Set the x position.  Important: Invoke setPosition(), not this member function. */
private void setXPosition(Float x)
{
	xPosition = x;
}
/** Set the y position of the shape
    Important: Invoke setPosition(), not this member function.
*/
private void setYPosition(Float y)
{
	yPosition = y;
}

4.5    アクセサーの可視性

アクセサーは常に protected にして、 フィールドにはサブクラスしかアクセスできないようにします。「外部クラス」がフィールドにアクセスする必要がある場合のみ、 対応する Getter または Setter を public にします。一般的には、Getter メンバー関数は public に、Setter メンバー関数は protected にします。

場合によっては、特定の不変性を維持するために、Setter を private にする必要があります。 例えば、Order クラスには、OrderItem インスタンスのコレクションを表すフィールドや、 注文全体の総額を表す orderTotal フィールドがあります。orderTotal は、注文された商品の総額、 またはすべての小計を表す便利なフィールドです。orderTotal の値を更新するメンバー関数だけが、 注文された商品のコレクションを操作するメンバー関数になります。 これらのメンバー関数がすべて Order に実装されている場合は、getOrderTotal() が public であっても、setOrderTotal() は private に指定します。

4.6    static フィールドを常に初期化する

static フィールド (クラス・フィールド) は、クラスのインスタンスが作成される前にアクセスされる可能性があるため、これらのフィールドには有効な値を設定します。

 


5    ローカル変数に関する標準

ローカル変数は、ブロック (多くの場合はメンバー関数) のスコープ内で定義されたオブジェクトまたはデータ項目です。 ローカル変数のスコープは、変数が定義されているブロックです。ローカル変数に対する重要なコーディング標準では、次の点に着目します。

5.1    ローカル変数の命名

一般的に、ローカル変数の名前は、フィールドの場合と同じ命名規則に従います。つまり、英語のフルスペルの記述子を使用して、先頭以外の単語の 1 文字目を大文字にします。

利便性を考えて、次のような特定用途で使用されるローカル変数に対しては、この命名規則を適用しなくてもかまいません。

5.1.1    ストリームの命名

メンバー関数内で 1 つの入力/出力ストリームを開き、使用して、閉じる場合、 一般的な規則では、これらのストリームの名前にそれぞれ InOut を付加します (参考資料 [GOS96])。 入力と出力の両方に使用されるストリームの場合は、暗黙的に inOut の名前を使用します。

別の一般的な命名規則として、InOutinOut の代わりに、それぞれ inputStreamoutputStreamioStream という名前を使用するという方法もあります。ただし、これは Sun で推奨されている命名法ではありません。

5.1.2    ループ・カウンターの命名

ループ・カウンターはよく使用されるローカル変数であり、C/C++ でも一般的であったため、Java プログラミングに おいても ijk をループ・カウンターとして使用できます (参考資料 [GOS96])。 ループ・カウンターにこれらの名前を使用する場合は、一貫性を保つようにしてください。

別の方法として、loopCounter や単純に counter などの名前を使用する方法もあります。 これらの方法の問題点は、複数のカウンターが必要なメンバー関数では、counter1counter2 といった名前がいくつも使用されることになる点です。 ijk は、カウンターとして機能し、入力が簡単で、一般的にも受け入れられるものです。

5.1.3    例外オブジェクトの命名

Java のコーディングでは例外処理は一般的であるため、一般の例外に e の文字を使用することも認められます (参考資料 [GOS96])。

5.2    ローカル変数の宣言と文書化

Java では、ローカル変数の宣言と文書化に関していくつかの規則があります。これらの規則を次に示します。

  1. ローカル変数は 1 行のコードに 1 つ宣言します。この規則は、コード 1 行につき 1 ステートメントという規則と一致しており、 各変数はインライン・コメントで文書化できます。
  2. ローカル変数はインライン・コメントで文書化します。インライン・コメントは、// で開始される単一行のコメント形式で、 コードの直後の同じ行に記述します。この形式は行末コメントとも呼ばれます。ローカル変数の使用目的、適切な使用場所、使用する理由を文書化します。 これによりコードがより理解しやすくなります。
  3. ローカル変数の目的は 1 つだけにします。1 つのローカル変数を複数の目的で使用すると、変数とコードの結合を弱め、 理解が難しくなります。また、ローカル変数の前の値が予期せず影響して、バグを生みやすくなります。 確かに、ローカル変数を再利用するとメモリーの使用量が削減されて効果的ですが、 コードの保守容易性が低下し、コードはより脆弱になります。メモリーの割り当てを削減するというわずかな節約をしても、 それに見合う価値はありません。

5.2.1    宣言に関する一般的な注意

if ステートメントのスコープ内など、コードの途中で宣言されるローカル変数は、コードをよく知っていなければ見つけにくい場合があります。

ローカル変数は、最初に使用する直前に宣言する代わりに、 コードの先頭で宣言することもできます。「3.5.5, 簡潔に、1 行に 1 つのコマンドを記述する」で説明したように、 メンバー関数をできるだけ短く記述すると、ローカル変数を確認するためにコードの先頭に移動する必要があるとしても、それほど効率が悪くなることはありません。


6    メンバー関数のパラメーターに関する標準

メンバー関数のパラメーターと引数に関する重要な標準では、命名方法と文書化の方法に注目します。パラメーター という用語は、メンバー関数の引数を表します。

6.1    パラメーターの命名

パラメーターは、ローカル変数の場合と同じ規則に従って命名します。ローカル変数の場合と同様、名前の隠蔽が問題になります。

例:

customer

inventoryItem

photonTorpedo

e

Smalltalk で使用されている方法ですが、ローカル変数の命名規則を使用し、 名前の先頭に "a" や "an" を付加する方法も利用できます。"a" や "an" を付加すると、 パラメーターがローカル変数やフィールドから区別されるため、名前の隠蔽問題を避けることができます。 これは好ましい方法です。

例:

aCustomer

anInventoryItem

aPhotonTorpedo

anInputStream

anException

6.2    パラメーターの文書化

メンバー関数のパラメーターは、javadoc@param タグを使用して、 メンバー関数のヘッダーに文書化します。次の内容を記述します。

  1. パラメーターの用途。パラメーターの用途を文書化する必要があります。パラメーターを使用する状況を、ほかの開発者が理解できるようにします。
  2. 制限または事前条件。メンバー関数で処理できる値が、パラメーターの取り得る値の一部だけである場合、 メンバー関数の呼び出し側はそれを把握しておく必要があります。例えば、正の値だけ、または 5 文字以内の文字列などといった制限になります。
  3. 使用例。パラメーターの動作が十分に明確でない場合は、文書に 1 つ以上の使用例を記述します。

6.2.1    パラメーターのタイプに対するインターフェースの使用

パラメーターのタイプに Object などのクラスを指定する際に、 適切な場合は Runnable などのインターフェースを指定します。この方法の利点は、 パラメーターをより明確に指定でき (Runnable は Object よりも明確です)、 多態性をサポートするより適切な方法となることです。パラメーターが特定のクラス階層中のクラスのインスタンスであることを示す代わりに、 特定のインターフェースをサポートすることを指定して、必要性に多態的に従うことが必要なだけであることを示します。


7    クラス、インターフェース、パッケージ、コンパイル・ユニットに関する標準

この章では、クラス、インターフェース、パッケージ、コンパイル・ユニットに関する標準とガイドラインについて説明します。クラスは、 オブジェクトをインスタンス化 (作成) するためのテンプレートです。クラスには、フィールドとメンバー関数の宣言が含まれます。インターフェースは、 メンバー関数とフィールドの両方を含む、共通のシグニチャーの定義です。インターフェースを実装するクラスは、 これをサポートする必要があります。パッケージは、関連するクラスのコレクションです。コンパイル・ユニットは、 クラスとインターフェースが宣言されているソース・コード・ファイルです。Java ではコンパイル・ユニットをデータベースに格納できるので、 個々のコンパイル・ユニットが物理的なソース・コード・ファイルに直接関連しているとは限りません。

7.1    クラスに関する標準

クラスに関する重要な標準は次のとおりです。

7.1.1    クラスの命名

標準的な Java の規則では、フルスペルの英語の記述子を使用して、先頭を大文字にします。 残りの部分では、大文字と小文字を使用し、名前に含まれる単語の 1 文字目を大文字にします (参考資料 [GOS96] と [AMB98])。

クラス名では単数形を使用します。

例:

Customer

Employee

Order

OrderItem

FileStream

String

7.1.2    クラスの文書化

クラス定義の直前のコメントに、次の情報を記述します。

  1. クラスの目的。 開発者は、クラスの一般的な目的を確認して、 クラスが要求を満たしているかどうかを判断する必要があります。クラスに関して知っておくと役に立つことは文書化する習慣を付けてください。 例えば、クラスがパターンの一部であるかどうかや、クラスを使用する上での制限事項などを記述します (参考資料 [AMB98])。
  2. 既知のバグ。クラスに関する未解決の問題がある場合は、これを文書化し、 ほかの開発者がその欠点と問題点を理解できるようにします。さらに、バグを解決していない理由も文書化する必要があります。 バグが単一のメンバー関数に固有である場合は、メンバー関数に直接関連付けます。
  3. クラスの開発または保守の履歴。クラスに対する変更の日付、作業者、概要を示す履歴の表を記述するのは一般的な慣例です。 この習慣は、保守プログラマーが過去に行われたクラスへの変更内容を確認するのに役立ちます。また、クラスに対して誰が何を行ったかが文書化されます。
  4. 適用できるすべての不変条件。不変条件は、「安定」時に常に TRUE になるインスタンスまたはクラスに関する一連のアサーションです。 安定時は、オブジェクトまたはクラスでメンバー関数が呼び出される前と、 メンバー関数が呼び出された直後の期間として定義されます (参考資料 [MEY88])。 クラスの不変条件を文書化することで、クラスの使用方法に関して、ほかの開発者が理解する支援になります。
  5. 並行性に関する戦略。インターフェース Runnable を実装するクラスでは、 並行性に関する戦略を十分に文書化します。並行性プログラミングは、多くのプログラマーにとって新しい複雑な話題です。 したがって、特に時間をかけて、ほかの開発者が作業について理解できるように文書化する必要があります。 並行性に関する戦略と、多くの戦略の中からそれを選んだ理由について文書化することが重要です。 一般的な並行性の戦略 (参考資料 [LEA97]) には次のものがあります。
  • 同期オブジェクト
  • ボーキング・オブジェクト
  • 保護オブジェクト
  • バージョン付きオブジェクト
  • 並行性ポリシー・コントローラー
  • アクセプター

7.1.3    クラスの宣言

クラスを理解しやすくする 1 つの方法は、一貫した方法で宣言することです。Java における一般的な方法では、クラスを次の順序で宣言します。

  • public メンバー関数
  • public フィールド
  • protected メンバー関数
  • protected フィールド
  • private メンバー関数
  • private フィールド

参考資料 [LAF97] では、コンストラクターと finalize() をリストの先頭に挙げるように指摘されています。 これは、ほかの開発者がクラスの使用法を理解する際に、これらのメンバー関数を最初に確認することが多いためです。さらに、 すべてのフィールドは private で宣言するという標準があるので、実際の宣言順序は次のようになります。

コンストラクター

finalize()

public メンバー関数

protected メンバー関数

private メンバー関数

private フィールド

メンバー関数の各グループ内では、アルファベット順で宣言するのが一般的です。多くの開発者は、 最初に各グループ内の static メンバー関数を、次にインスタンス・メンバー関数に宣言し、 これらのサブグループ内でメンバー関数をアルファベット順に並べています。これらの方法はどちらも有効です。 どちらを選択した場合でも、それに一貫して従う必要があります。

7.1.4    public と protected インターフェースの最小化

オブジェクト指向設計の基本の 1 つは、クラスの public インターフェースを最小限にすることです。この原則には、次のような理由があります。

  1. 学習のしやすさ。クラスの使用方法を習得する場合に、public インターフェースを理解するだけでよくなります。public インターフェースが少なければ、 それだけクラスについて学習しやすくなります。
  2. 結合度の引き下げ。あるクラスのインスタンスが別のクラスのインスタンスや、 クラス自身に直接メッセージを送信している場合、2 つのクラスは結合しています。public インターフェースを最小化するということは、 結合度の可能性を最小にすることになります。
  3. 柔軟性の向上。この理由は、結合度と直接関連します。public インターフェースのメンバー関数の実装方法を変更する場合 (例えば、メンバー関数の戻り値を変更する場合)、 メンバー関数を呼び出しているコードの変更が必要となる可能性があります。public インターフェースが少ないほど、カプセル化のレベルが上がり、柔軟性も向上します。

public インターフェースを最小限にすることに価値があるのは明らかですが、protected インターフェースを最小限にすべきかどうかは明らかではありません。 基本的な考え方として、スーパークラスのすべての protected インターフェースは、 サブクラスの視点から考えると実際には public です。protected インターフェースのメンバー関数は、 いずれもサブクラスから呼び出すことができます。したがって、public インターフェースを最小限にする場合と同じ理由で、 クラスの protected インターフェースも最小限にすべきです。

7.1.4.1    public インターフェースを最初に定義する

経験を積んだ開発者の多くは、クラスの public インターフェースを、コーディングを始める前に定義しています。 

7.2    インターフェース に関する標準

インターフェースに関する重要な標準は次のとおりです。

7.2.1    インターフェースの命名

Java の規則では、インターフェースの名前には大文字と小文字を使い、 各単語の 1 文字目を大文字にします。インターフェースに関する Java の命名規則では、RunnableCloneable などの説明的な形容詞を使用します。SingletonDataInput などの、説明的な名詞も一般的に使用されます (参考資料 [GOS96])。

7.2.1.1    その他の命名規則

インターフェースの名前には接頭辞 "I" を付加します。参考資料 [COA97] で提案されているように、 インターフェース名の前に "I" の文字を付加して、ISingletonIRunnable のような名前にします。この方法は、 インターフェース名とクラスやパッケージの名前を区別するのに役立ちます。この命名規則を使用すると、 クラス図 (オブジェクト・モデル) が読みやすくなります。主な欠点は、Runnable などの既存のインターフェースが、 この方法を使って命名されていないことです。このインターフェースの命名規則は、Microsoft の COM/DCOM アーキテクチャーでも一般的に使用されています。

7.2.2    インターフェースの文書化

インターフェース定義の直前のコメントに、次の情報を記述します。

  1. インターフェースの目的。ほかの開発者は、インターフェースを使用する前に、 カプセル化されている概念を理解する必要があります。言い換えると、 インターフェースの目的を知る必要があります。インターフェースを定義する必要があるかどうかを簡単に判断するには、 インターフェースの目的を簡単に説明できるかどうかを考えます。 目的を簡単に説明できない場合は、インターフェースを定義する必要はありません。 インターフェースの概念は Java では新しいものです。開発者はインターフェースの適切な使用について経験がなく、 新しいという理由で使いすぎてしまう傾向があります。
  2. インターフェースの適切な使用法と適切でない使用法。開発者は、インターフェースの適切な使用方法だけでなく、 不適切な使用についても知っておく必要があります (参考資料 [COA97])。

メンバー関数のシグニチャーはインターフェースで定義されるため、 メンバー関数のシグニチャーについては、第 3 章で説明したメンバー関数の文書化規則に従う必要があります。

7.3    パッケージに関する標準

パッケージに関する重要な標準は次のとおりです。

  • 命名規則
  • 文書化規則

7.3.1    パッケージの命名

パッケージの命名に関連して、いくつかの規則があります。これらの規則を次に示します。

  1. ID をピリオドで区切ります。Sun では、パッケージ名を読みやすくするために、 名前に含まれる ID をピリオドで区切るように提案しています。例えば、パッケージ名の java.awt は、javaawt の 2 つの ID で構成されています。
  2. Sun から提供されている標準 Java ディストリビューション・パッケージの名前は、"java" という ID で始まります。使用している Java 開発環境のベンダーにかかわらず、 標準 Java パッケージに一貫性のある名前を付けるために、Sun でこの権利を保有しています。
  3. ローカル・パッケージの名前は、すべて大文字の記述子で開始します。ローカル・パッケージは組織内部で使用され、 ほかの組織に配布されることはありません。これらのパッケージには、persistence.mapping.relational interface.screens といった名前を付けます。
  4. グローバル・パッケージ名の先頭には、組織のインターネット・ドメインを逆にしたものを付加します。複数の組織に配布するパッケージには、 配布元組織のドメイン・ネームを逆にしたものを付加します。トップレベル・ドメインの種類は大文字にします。 例えば、前の例のパッケージを配布する場合、パッケージ名は com.rational.www.persistence.mapping.relationalcom.rational.www.interface.screens になります。

7.3.2    パッケージの文書化

組織で開発したパッケージの目的を説明する外部文書を、1 つ以上作成して保守します。パッケージごとに、次の内容を文書化します。

  1. パッケージの根拠。ほかの開発者は、パッケージがどういうものであるかを確認して、使用するかどうかを決定する必要があります。 共有されたパッケージの場合は、それを強化または拡張するかどうかも判断する必要があります。
  2. パッケージに存在するクラス。ほかの開発者がパッケージの内容を確認できるように、 パッケージに含まれるクラスとインターフェースのリストを作成し、 それぞれについて 1 行で簡単な説明を記述します。

ヒント: パッケージの名前を使用して HTML ファイルを作成し、 パッケージのディレクトリーに保存します。ファイルの拡張子は .html にします。

7.4    コンパイル・ユニットに関する標準

コンパイル・ユニットに関する標準とガイドラインの基本は次のとおりです。

7.4.1    コンパイル・ユニットの命名

コンパイル・ユニット (この場合はソース・コード・ファイル) には、 ユニット内で宣言されている主要なクラスまたはインターフェースの名前を付けます。ファイル名には、 パッケージやクラスと同じ名前を、大文字と小文字も同じにして使用します。ファイル名の後に、.java の拡張子を付加します。

例:

Customer.java

Singleton.java

SavingsAccount.java

7.4.2    コンパイル・ユニットの文書化

1 つのファイルには 1 つのクラスまたはインターフェースだけを宣言するようにしますが、 場合によっては、同じファイルに複数のクラス (またはインターフェース) を宣言することにも意味があります。 クラス B の唯一の目的が、クラス A だけで必要な機能をカプセル化することである場合、一般的な経験則として、 クラス B をクラス A と同じソース・コード・ファイルに記述することは道理にかなっています。 したがって、次の文書化規則は、本質的にクラスではなく、ソース・コード・ファイルに適用されます。

  1. 複数のクラスを含むファイルでは、クラスのリストを作成します。ファイルに複数のクラスが含まれている場合は、 クラスのリストを作成し、それぞれに簡単な説明を加えます。
  2. ファイル名と識別情報。ファイルの先頭に、ファイルの名前を記述します。 コードを印刷するときに、コードに対応するソース・ファイルを確認できます。
  3. 著作権情報。可能な場合は、ファイルに関する著作権情報を示します。一般的には、著作権が発生した年と、 著作権を保有する個人または組織の名前を示します。コードの作成者が著作権の保有者であるとは限りません。

8    エラー処理と例外

一般的な考え方として、例外はエラー (論理エラーとプログラミング・エラー、構成エラー、データ破損、 リソースの枯渇など) に対してだけ使用します。一般的な規則は、通常の条件や、過負荷やハードウェア障害がない状態では、 システムは例外を発生しないということです。

  1. 例外を使用して、論理エラーやプログラミング・エラー、構成エラー、データ破損、リソースの枯渇を処理します。 

適切なログ・メカニズムにより、発生した位置を含め、できるだけ早く例外を報告します。

  1. 特定の抽象化からエクスポートされる例外の数を最小限にします。

大規模なシステムでは、各レベルで多数の例外を処理すると、コードの理解や保守が困難になります。例外処理によって、通常の処理が妨げられる場合もあります。

例外の数を最小限にする方法はいくつかあります。

  • エクスポートする例外を制限する代わりに、欠陥のある抽象化や不正なオブジェクトを問い合わせることができる「診断」プリミティブを提供します。これにより、発生した問題の性質に関して、より詳細な情報を取得できます。
  • オブジェクトに「例外的な」状態を追加し、オブジェクトの有効性を明示的にチェックするプリミティブを用意します。
  1. 発生頻度が高いと予想されるイベントに対して例外を使用しないようにします。

例外を使用して明らかにエラーでない状態を表すと、次のような不利益があります。

  • ややこしくなります。
  • 制御のフローに、理解や保守の困難な混乱が生じます。
  • コードのデバッグがさらに困難になります。ほとんどのソース・レベル・デバッガーは、デフォルトですべての例外を通知します。

例えば、関数によって返される余分な値 (検索における Value_Not_Found など) の形では、例外を使用しないでください。また、「out」パラメーターを持つプロシージャーを使用するか、Not_Found を表す特別な値を導入したり、返されるタイプを Not_Found の判別を持つレコードにパックします。

  1. 例外を使用して制御構造を実装しないようにします。

これは、前の規則の特殊な場合です。例外を、「goto」ステートメントの形で使用しないでください。

  1. ステータス・コードが適切な値であることを確認します。

サブプログラムが返したステータス・コードを「out」パラメーターとして使用する場合は、 サブプログラム本体の最初の実行可能ステートメントで、「out」パラメーターに必ず値を割り当てます。規則的に、すべてのステータスをデフォルトで成功、またはデフォルトで失敗にします。 例外処理を含め、サブプログラムが終了する可能性のある箇所をすべて考察します。

  1. 安全性のチェックはローカルで行うようにし、クライアントが行うようにしてはいけません。

適切な入力を与えなければ、サブプログラムが間違った出力を生成する可能性がある場合は、 管理された方法で無効な入力を検出して通知するコードを、サブプログラム側に作成します。クライアントに適切な値を渡すように、 コメントで指示することはあてになりません。遅かれ早かれコメントが無視されることは目に見えています。 その結果、無効なパラメーターが検出されなければ、エラーのデバッグは困難になります。


9    さまざまな標準と問題

この章では、重要な標準とガイドラインについて説明します。ここで説明する標準やガイドラインは、独立した章として説明が必要なほど総合的な話題です。

9.1    再利用

外部から購入したり再利用する Java クラス・ライブラリーやパッケージは、100% Pure Java として認証されているべきです (参考資料 [SUN97])。 この標準を実施することで、再利用するライブラリーやパッケージが、 配置先のすべてのプラットフォームで正常に動作することが保証されます。Java ライブラリー専門のサード・パーティー開発会社や、 組織内の別の部署またはプロジェクト・チームなど、Java クラス、パッケージ、 アプレットの入手先は多岐にわたります。

9.2    クラスのインポート

import ステートメントでは、ワイルドカードを使用してクラスの名前を指定できます。例えば、次のように記述できます。

import java.awt.*;

この場合、パッケージ java.awt 内のすべてのクラスがインポートされます。正確にいうと、 少し違います。実際には、java.awt パッケージで使用するクラスが、コンパイル時にコードにインポートされます。 使用しないクラスはインポートされません。優れた機能にも思えますが、 コードの読みやすさは損なわれます。より適切な方法は、 使用するクラスを完全な名前で指定することです (参考資料 [LAF97] と [VIS96])。 クラスをインポートする適切な方法を、次の例に示します。

import java.awt.Color
import java.awt.Button
import java.awt.Container

9.3    Java コードの最適化

コードの最適化は、プログラマーが最後に考慮すべきことです。最初から考慮すべきではありません。 最適化を最後に行うのは、必要なコードだけを最適化するためです。多くの場合、処理時間の大部分を占めているのはコードのごく一部であり、 最適化を行うのはこの部分です。経験のないプログラマーが犯す典型的な誤りは、コードの実行速度が十分な場合でも、コード全体を最適化しようとすることです。

  1. 誰も気にしていないコードを最適化するのは時間の無駄です。

コードを最適化するときに、何を探すべきでしょうか。 参考資料 [KOE97] で指摘されているように、最も重要な要素は、 固定のオーバーヘッドと、多量の入力があった場合の性能です。理由は簡単です。 固定のオーバーヘッドは少量の入力に対する実行速度に影響し、 アルゴリズムは多量の入力に対する実行速度を左右します。Koenig の経験則では、 少量と多量の両方の入力に対して適切に機能するプログラムは、中程度の入力に対しても同様に機能します。

複数のハードウェア・プラットフォームやオペレーティング・システムで動作するソフトウェアを作成する開発者は、 さまざまなプラットフォームの特異性について注意する必要があります。メモリーやバッファーを処理する方法など、特に時間のかかる操作は、 プラットフォームによって大きく異なる場合があります。一般的には、プラットフォームに応じてコードを最適化する必要があります。

コードを最適化する際に注意すべきその他の問題は、ユーザーの優先度です。 遅延に対するユーザーの感じ方は、状況によって異なります。例えば、データを 5 秒間ロードしてから画面を表示するよりも、 画面を表示してからデータを 8 秒間ロードするほうが、ユーザーは満足するはずです。つまり、ほとんどのユーザーは、フィードバックが直ちに得られるなら、 少しくらいは長く待てるということです。これは、コードを最適化する際の重要な情報です。

  1. いつでもユーザーの視点でコードを最適化して高速化する必要はありません。

最適化は、アプリケーションが成功するか失敗するかに関わる場合もありますが、 最も重要なのはコードが正しく動作することです。この点を忘れてはいけません。 動作しない高速なソフトウェアよりも、正しく動作する低速なソフトウェアの方が常に優先されます。

9.4    Java テスト・ハーネスの作成

オブジェクト指向のテストは、オブジェクト開発コミュニティーでは無視されていまが、重要な話題です。 実際に、作成したソフトウェアは、開発に使用した言語に関わらず、 開発者自身またはその他の開発者によってテストされる必要があります。テスト・ハーネスは、 アプリケーションをテストするためのメンバー関数のコレクションです。 これらは、クラス自体に埋め込まれたり (組み込みテストと呼ばれます)、 テスト専用のクラスに埋め込まれます。

  1. テスト用メンバー関数の名前には、接頭辞 "test" を付加します。これにより、 コード中のテスト用メンバー関数を簡単に見つけることができます。テスト用メンバー関数の名前に接頭辞 "test" を付けることで、 製品バージョンのソース・コードをコンパイルする前に、テスト用メンバー関数を簡単に取り除くことができます。
  2. メンバー関数テスト用のメンバー関数には一貫した名前を付けます。メソッド・テストは、1 つのメンバー関数が定義どおりに実行されるかどうかを確認する作業です。 メンバー関数テスト用のメンバー関数には、すべて「testメンバー関数名Forテスト名」の形式で名前を付けます。例えば、withdrawFunds() をテストするテスト・ハーネスのメンバー関数には、testWithdrawFundsForInsufficientFunds()testWithdrawFundsForSmallWithdrawal() があります。 withdrawFunds() に対して複数のテストがある場合は、 これらすべてを呼び出す testWithdrawFunds() というメンバー関数を作成できます。
  3. クラス・テスト用のメンバー関数には一貫した名前を付けます。クラス・テストは、1 つのクラスが定義どおりに実行されるかどうかを確認する作業です。 クラス・テスト用のメンバー関数には、すべて "testSelfFor テスト名" の形式で名前を付けます。 例えば、Account クラスをテストするテスト・ハーネスのメンバー関数には、testSelfForSimultaneousAccess()testSelfForReporting() があります。
  4. クラスのテストを呼び出す場所を 1 つにまとめます。testSelf() という static メンバー関数を作成し、 クラス・テスト用とメソッド・テスト用のすべてのメンバー関数をここから呼び出します。
  5. テスト・ハーネスのメンバー関数を文書化します。テスト・ハーネスのメンバー関数を文書化します。作成する文書には、 テストの説明と、予想されるテストの結果を記述します。

10    成功のパターン

標準に関する文書を持っているだけで、生産性の高い開発者になれるわけではありません。成功するためには、 より生産的になるように意識する必要があります。つまり、これらの標準を効果的に適用する必要があります。

10.1    効果的な標準の使用法

次のアドバイスは、ここで説明した Java のコーディング標準やガイドラインを、より効果的に使用する際に役立ちます。

  1. 標準を理解します。それぞれの標準やガイドラインが生産性を向上させる理由を、時間を割いて理解してください。例えば、 ローカル変数を 1 行に 1 つずつ宣言することも、 ガイドラインで説明されているという理由だけで実行しないようにしてください。コードの理解しやすさが向上するという理由に基づいて、これを実行してください。
  2. 標準を信頼します。まずは各標準を理解することですが、 これらの標準を信頼することも必要です。標準に従うということは、時間のあるときにだけ行うことではありません。 コードを作成する際の最善の方法であると信じて、常に標準に従うようにします。
  3. 後からではなく、コードの作成中に標準に従います。文書化されたコードは、 コードの作成中も作成後も理解しやすいものです。一貫性のあるメンバー関数やフィールドの名前は、 開発と保守のどちらにおいても作業を楽にします。また、明瞭なコードも開発と保守の両方の作業を楽にします。 つまり、標準に従うことで、開発中の生産性が向上し、コードの保守が容易になります。 それによって、保守担当者の生産性も向上します。最初から明瞭なコードを作成すれば、 作成中にもその利点を利用できます。
  4. 標準を品質保証プロセスの一部にします。コード検査の役割は、 ソース・コードが組織で採用している標準に従っていることを保証することです。標準を開発者へのトレーニングや指導の基本に使用して、さらに効果が上がるようにします。

10.2    適切なコードを作成するためのその他の要素

  1. コンピューターではなく、人のためにプログラムします。開発作業の主要な目標は、ほかの人にも理解しやすいコードを作成することです。 ほかの開発者が理解できないコードは、優れたコードではありません。命名規則に従ってください。コードを文書化する。 段落に分けてください。
  2. まず設計、次にコードを考えます。作成中のプログラムの参照先コードが 変更される、という状況は経験したことがあるでしょうか。おそらく、 メンバー関数に新しいパラメーターを渡す必要が生じたり、1 つのクラスを 複数のクラスに分割する必要が生じたりするはずです。作成中のコードを、 修正されたバージョンでも正しく動作させるために、余分な作業がどれくらい 必要になったでしょうか。楽しい作業ではないはずです。コードを最初に 作成するときに開発者がよく考えていれば、このような作業を行う必要はなかったとか、 開発者は最初に設計 しておくべきだったなどと考えませんでしたか。 もちろん考えたはずです。コーディングを実際に開始する前に、コードをどのように 記述するかについて時間をかけて考察していれば、コードの作成にはほとんど 時間がかかりません。さらに、前もって考えておくことで、将来的なコードの変更 に対する影響を小さくすることができます。
  3. 少しずつ開発します。開発を少しずつ進める (少数のメンバー関数を作成し、これをテストしてから、次のメンバー関数を作成する) ことは、 コード全体を 1 度に作成してから修正するよりも効果的です。100 行のコードをよりも、10 行のコードをテストして修正する方が簡単です。 正確には、100 行のコードを作成する場合に、10 行ずつコードをプログラム、テスト、修正すると、1 度に 100 行のコード・ブロックを作成する場合の半分以下の時間ですむということです。 
    この理由は簡単です。コードをテストしてバグを発見する場合、 バグは作成したばかりの新しいコードで見つかることがほとんどです (もちろん、コードの残りの部分は信頼できる状態にあると仮定します)。 大きなコードよりも小さなコードの方が、バグはずっと早く見つかります。少しずつ段階的に開発することで、バグの発見に必要な平均時間は短くなります。 結果的に、開発全体の時間も短縮されます。
  4. コードを簡潔にします。複雑なコードは、知的な満足感が得られるかもしれませんが、 ほかの開発者が理解できなければ、それは優れたコードではありません。ほかの開発者から、 バグの修正や改良のためにコードの複雑な部分を変更するように要求されたら (または、自分で必要を感じた場合は)、 コードを書き直すよい機会です。実際に、ほかの開発者が作成したコードを、 理解できないために書き直す必要が生じた場合もあるはずです。コードを書き直すときに、 作成した開発者のことをどう思ったでしょうか。この開発者は天才か、 それともその反対かと思いませんでしたか。後で書き直しが必要となるようなコードを作成することには、 何の誇りもありません。KISS (Keep it simple, stupid: 簡単にしなさい」) の規則に従ってください。
  5. 共通のパターン、アンチパターン、イディオムについて学習します。開発の生産性を向上させるために利用できる、 分析、設計、プロセスのパターンやアンチパターン、プログラム・イディオムは数多くあります。

11    まとめ

この章では、ここで説明したガイドラインを要約します。また、説明した Java のコーディング標準について、 トピックごとに 1 ページでまとめています。これらのトピックを次に示します。

  • Java の命名規則
  • Java の文書化規則
  • Java のコーディング規則

このホワイト・ペーパーで説明した標準やガイドラインをまとめる前に、重要な指針について繰り返しておきます。

標準に従わない場合は、それを文書化します。これ以外の標準はすべて違反できます。 その場合、標準に違反する理由、標準に違反したことによる影響、この状況に標準を適用するために必要な条件について記述する必要があります。

11.1    Java の命名規則

後に示すような例外はありますが、名前を付けるときは、常にフルスペルの英語の記述子を使用します。 また、通常は小文字を使用して、クラス名やインターフェース名の最初の文字は大文字にします。 また、名前の先頭以外にある単語の 1 文字目も、同様に大文字で表します。

一般概念

  • フルスペルの英語の記述子を使用します。
  • 対象となる分野に適切な用語を使用します。
  • 名前が読みやすいように、大文字と小文字を組み合わせて使用します。
  • 省略形は控えめに、できるだけ慎重に使用します。
  • 長い名前を避けます (15 文字未満が適切です)。
  • 似たような名前や、違いが大文字と小文字だけであるような名前は避けます。
  • アンダースコアーを使用しないようにします。
項目 命名規則
引数/
パラメーター
渡される値を、 フルスペルの英語で記述します。"a" または "an" を接頭辞として付加する場合もあります。重要なことは、1 つの方法を選択して、それに従うことです。
customer、account、
または
aCustomer、anAccount
フィールド /
プロパティー
フルスペルの英語でフィールドを記述します。名前の先頭の文字は小文字にし、先頭以外にある単語の 1 文字目は大文字にします。
firstName、lastName、
warpSpeed
 
論理型の Getter メンバー関数 論理型の Getter には、接頭辞 "is" を付加します。上に示した論理値フィールドの命名標準に従えば、 フィールド名に接頭辞を付加するだけです。
isPersistent()、isString()、
isCharacter() 
クラス フルスペルの英語で記述します。名前を構成するすべての単語の 1 文字目を大文字にします。
Customer、SavingsAccount
コンパイル・ユニット・ファイル クラスまたはインターフェースの名前を使用します。 ファイルに複数のクラスがある場合は、主要なクラスの名前を使用します。末尾に "java" の拡張子を付加して、ソース・コード・ファイルであることを示します。
Customer.java、
SavingsAccount.java、
Singleton.java
コンポーネント/
ウィジェット
フルスペルの英語でコンポーネントの用途を記述し、コンポーネントのタイプを末尾に付加します。
okButton、customerList、
fileMenu
コンストラクター クラス名を使用します。
Customer()、SavingsAccount()
デストラクター Java にはデストラクターがありませんが、オブジェクトがガーベッジ・コレクションされる前に finalize() メンバー関数が呼び出されます。
finalize()
例外 一般的に、"e" の文字で例外を表します。
e
final static フィールド (定数) すべて大文字で表記し、単語の間にアンダースコアーを挿入します。final static の Getter メンバー関数を使用するほうが、 柔軟性が向上するため適切です。
MIN_BALANCE、DEFAULT_DATE
Getter メンバー関数 アクセスするフィールドの名前には接頭辞 "get" を付加します。
getFirstName()、getLastName()、
getWarpSpeeed()
インターフェース フルスペルの英語で、インターフェースがカプセル化する概念を記述します。 すべての単語の 1 文字目を大文字にします。習慣的に接頭辞 "able"、"ible"、"er" を付けますが、必須ではありません。
Runnable、Contactable、
Prompter、Singleton
ローカル変数 フルスペルの英語で記述します。1 文字目を小文字にし、既存のフィールドを隠蔽しないようにします。例えば、"firstName" という名前のフィールドがある場合、 ローカル変数に "firstName" という名前を付けないようにします。
grandTotal、customer、
newAccount
ループ・カウンター 一般的に、ijk の文字や、counter という名前が使用されます。
i、j、k、counter
パッケージ フルスペルの英語で記述します。名前を構成する各単語の 1 文字目を大文字にし、 それ以外はすべて小文字にします。グローバル・パッケージの場合は、インターネット・ドメインの名前の順序を反転し、これにパッケージ名を付加します。
java.awt、
com.ambysoft.www.
persistence.mapping
メンバー関数 フルスペルの英語でメンバー関数の動作を記述します。可能な場合は、名前の先頭に動作を表す動詞句を使用し、先頭の文字は小文字にします。
openFile()、addAccount()
Setter メンバー関数 アクセスするフィールドの名前に接頭辞 "set" を付加します。
setFirstName()、setLastName()、
setWarpSpeed()

11.2    Java の文書化規則

文書化に関するよい経験則は、コードをまだ見ていない場合に、「時間をかけずに効果的にコードを理解するにはどんな情報が必要か」を考えてみることです。

一般概念

11.2.1    Java コメントの種類

次の表は、3 種類の Java コメントと、その使用法に関する提案を示しています。

コメントの種類 使用法
ドキュメンテーション ドキュメンテーション・コメントは、文書化するインターフェース、クラス、メンバー関数、フィールドの宣言の直前に使用します。ドキュメンテーション・コメントは javadoc で処理され、クラスの外部文書が作成されます。以下を参照してください。 /**
顧客 (Customer): 顧客は、サービスや製品の販売先となる個人または組織です。
@author S.W. Ambler
*/
C 形式 C 形式のコメントは、不要になったコードを、開発者が考えを変えた場合に備えて残しておく場合や、デバッグ中に一時的にコードを無効化する場合に使用します。 /*
このコードは、前述のコードで置き換えたために、B. Gustafsson が 1999 年 6 月 4 日にコメント化しました。不要な場合は 2 年後に削除してください。
. . . (ソース・コード)
*/
単一行 単一行コメントは、ビジネス・ロジック、コードの一部、一時変数の宣言を、メンバー関数内で文書化するために使用します。 // 1995 年 2 月に開始された
// Sarek の特別キャンペーンにより、
// $1000 以上のすべての請求に対して
// 5% の割引を適用します。

11.2.2    文書化の対象

次の表は、作成する Java コードの各部分に関して、何を文書化するかについてまとめています。

項目 文書化の対象
引数/
パラメーター
パラメーターのタイプ

パラメーターの用途

制限または事前条件

フィールド /
プロパティー
フィールドの説明

適用できるすべての不変条件

並行性の問題

可視性の決定

クラス クラスの目的

既知のバグ

クラスの開発と保守の履歴

適用できるすべての不変条件

並行性に関する戦略

コンパイル・ユニット クラスで定義されているクラスやインターフェースと、その簡単な説明

ファイル名と識別情報

著作権情報

Getter メンバー関数 遅延初期化を使用している場合は、その理由
インターフェース 目的

適切な使用法と適切でない使用法

ローカル変数 使用法または目的
メンバー関数: 文書 メンバー関数の動作とその理由

メンバー関数に渡す必要のあるパラメーター

メンバー関数の戻り値

既知のバグ

メンバー関数がスローする例外

可視性の決定

メンバー関数がどのようにオブジェクトを変更するか

コード変更の履歴

メンバー関数の呼び出し方法の例

適切な事前条件と事後条件

メンバー関数: 内部コメント 制御構造

コードの実行内容とその理由

ローカル変数

難しいコードまたは複雑なコード

処理順序

パッケージ パッケージの根拠

パッケージに存在するクラス

11.3    Java のコーディング規則 (全般)

Java コードの保守容易性と拡張性に関する重要な規則と標準は多数あります。99.9% の時間は、マシンのためではなく、 仲間の開発者のためにプログラミングを行うことが重要です。また、作成しているコードを、ほかの開発者が理解できるようにすることが最も重要です。

規則の対象 規則
アクセサー・メンバー関数 データベースのフィールドでは、遅延初期化の使用を考慮します。

すべてのフィールドの取得や修正にアクセサーを使用します。

「定数」にはアクセサーを使用します。

コレクションでは、項目の挿入や削除を行うメンバー関数を追加します。

可能な場合は、アクセサーを public ではなく protected にします。

フィールド フィールドは常に private で宣言します。

フィールドに直接アクセスせず、アクセサー・メンバー関数を使用します。

final static フィールド (定数) を使用せずに、アクセサー・メンバー関数を使用します。

名前を隠蔽しないようにします。

static フィールドは常に初期化します。

クラス public と protected のインターフェースをできるだけ使わないようにします。

コーディングを始める前に、クラスの public インターフェースを定義します。

クラスのフィールドとメンバー関数は次の順で宣言します。

  • コンストラクター
  • finalize()
  • public メンバー関数
  • protected メンバー関数
  • private メンバー関数
  • private フィールド
ローカル変数 名前を隠蔽しないようにします。

ローカル変数は 1 行のコードに 1 つ宣言します。

ローカル変数はインライン・コメントで文書化します。

ローカル変数は使用する直前に宣言します。

ローカル変数の目的は 1 つだけにします。

メンバー関数 コードを文書化します。

コードを段落に分けます。

制御構造の前には 1 行、メンバー関数の宣言の前には 2 行の空行を使用します。

30 秒以内に理解できるようにします。

簡潔に、1 行に 1 つのコマンドを記述します。

メンバー関数の可視性をできる限り制限します。

演算の順序を指定します。


12    参考資料

参照コード 参照情報
[AMB98] S.W. Ambler 著 (1998) Building Object Applications That Work: Your Step-By-Step Handbook for Developing Robust Systems with Object Technology. New York: SIGS Books/Cambridge University Press.
[COA97] Coad, P. and Mayfield, M 著 (1997) Java Design: Building Better Apps & Applets. Upper Saddle River, NJ: Prentice Hall Inc.
[DES97] A. DeSoto 著 (1997) Using the Beans Development Kit 1.0 February 1997: A Tutorial. Sun Microsystems.
[GOS96] J. Gosling、B. Joy、G. Steele 著 (1996) The Java Language Specification. Reading, MA: Addison Wesley Longman Inc.
[GRA97] Grand, M 著 (1997) Java Language Reference. Sebastopol, CA: O. Reilly & Associates, Inc.
[KAN97] J. Kanerva 著 (1997) The Java FAQ. Reading, MA: Addison Wesley Longman Inc.
[KOE97] A. Koenig 著 (1997) The Importance--and Hazards--of Performance Measurement. New York: SIGS Publications, Journal of Object-Oriented Programming, January, 1997, 9(8), pp. 58-60.
[LAF97] C. Laffra 著 (1997) Advanced Java: Idioms, Pitfalls, Styles and Programming Tips. Upper Saddle River, NJ: Prentice Hall Inc.
[LEA97] D. Lea 著 (1997) Concurrent Programming in Java: Design Principles and Patterns. Reading, MA: Addison Wesley Longman Inc.
[MCO93] S. McConnell 著 (1993) Code Complete: A Practical Handbook of Software Construction. Redmond, WA: Microsoft Press.
[MEY88] B. Meyer 著 (1988) Object-Oriented Software Construction. Upper Saddle River, NJ: Prentice Hall Inc.
[NAG95] J. Nagler 著 (1995) Coding Style and Good Computing Practices. http://wizard.ucr.edu/~nagler/coding_style.html
[SUN96] Sun Microsystems (1996). javadoc - The Java API Documentation Generator. Sun Microsystems.
[SUN97] Sun Microsystems (1997). 100% Pure Java Cookbook for Java Developers: Rules and Hints for Maximizing the Portability of Java Programs. Sun Microsystems.
[VIS96] Vision 2000 CCS Package and Application Team (1996). Coding Standards for C, C++, and Java. http://v2ma09.gsfc.nasa.gov/coding_standards.html

13    用語集

100% pure: Java アプレット、アプリケーション、パッケージが、Java VM をサポートするすべてのプラットフォームで動作することを示す「承認」。

アクセサー: フィールドの値を変更する、またはフィールドの値を返すメンバー関数。 アクセス修飾子とも呼ばれます。「Getter」と「Setter」を参照。

分析パターン: ビジネスや問題の領域に対する解決策を説明するモデリング・パターン。

アンチパターン: 間違っていることや非常に効率の悪いことを証明することで、一般的な問題を解決する方法。

引数: 「パラメーター」を参照。

BDK: Beans Development Kit。

ブロック: 中括弧で囲まれた、0 以上のステートメントの集合。

中括弧: {} の文字。それぞれ開き括弧と閉じ括弧と呼ばれ、ブロックの開始と終了を示すために使用されます。

クラス: オブジェクトのインスタンス化に使用する定義またはテンプレート。

クラス・テスト: クラスとそのインスタンス (オブジェクト) が定義どおりに動作することを確認する作業。

CMVC: 構成管理とバージョン管理。

コンパイル・ユニット: クラスやインターフェースが宣言されたソース・コード・ファイル。ディスク上の物理的なファイルか、データベースに格納された「仮想的な」ファイルを表します。

コンポーネント: リスト、ボタン、ウィンドウなどのインターフェース・ウィジェット。

定数 Getter: 「定数」の値を返す Getter メンバー関数。定数の値はハード・コーディングされているか、必要に応じて計算されます。

コンストラクター: オブジェクトが作成されるときに、必要な初期化を実行するメンバー関数。

包含: あるオブジェクトがほかのオブジェクトを内に含んでいること。含んでいるオブジェクトと協調して、オブジェクトの動作を実行します。これを実現するには、 内部クラスを使用するか (JDK 1.1 以上)、オブジェクト内に別のオブジェクトのインスタンスを集約します (JDK 1.0 以上)。

CPU: 中央演算装置 (Central Processing Unit)。

C 形式のコメント: コメントを /* と */ で囲む、Java のコメント形式。C/C++ 言語のコメント形式と同じで、 複数行のコメントを作成するときに使用できます。 一般的には、テスト時にコードの不要な部分を「コメント化」するために使用します。

設計パターン: 設計に関する問題の解決策を説明するモデリング・パターン。

デストラクター: C++ のクラス・メンバー関数。不要になったオブジェクトをメモリーから削除するために使用します。 Java は独自にメモリーを管理するため、このようなメンバー関数は必要ありません。ただし、 同様の概念を持つ finalize() というメンバー関数がサポートされています。

ドキュメンテーション・コメント: コメントを /** と */ で囲む、Java のコメント形式。javadoc で処理して、 クラス・ファイルの外部文書を作成できます。インターフェース、クラス、メンバー関数、フィールドの主な文書は、ドキュメンテーション・コメントで記述します。

フィールド: クラスまたはクラスのインターフェースを表す変数。リテラル・データ型またはその他のオブジェクトになります。 インスタンス・フィールドはオブジェクト (インスタンス) を説明し、static フィールドはクラスを説明します。フィールドは、フィールド変数、プロパティーとも呼ばれます。

finalize(): ガーベッジ・コレクション時に、オブジェクトがメモリーから削除される前に自動的に呼び出されるメンバー関数。 このメンバー関数の目的は、開いているファイルを閉じるなど、必要なクリーンアップ作業を行うことです。

ガーベッジ・コレクション: メモリーの自動管理。参照されなくなったオブジェクトを、自動的にメモリーから削除します。

Getter: フィールドの値を返すアクセサー・メンバー関数の一種。Getter を使用して、定数の値を返すことができます。 この方法は、定数を static フィールドとして実装するよりも柔軟であり適切です。

HTML: ハイパーテキスト・マークアップ言語。Web ページを作成するための、業界標準の形式です。

インデント: 「段落化」を参照。

インライン・コメント: 1 行のソース・コードを文書化するための 1 行のコメント。 コメントはコードと同一の行に、コードの後に続けて記述します。C 形式のコメントも利用できますが、この目的では一般的に単一行コメントが使用されます。

インターフェース: メンバー関数とフィールドの両方を含む、共通のシグニチャーの定義。インターフェースを実装するクラスは、 これをサポートする必要があります。インターフェースは、コンポジションによる多態性を促進します。

I/O: 入出力。

不変条件: インスタンスまたはクラスに関する一連のアサーション。オブジェクトやクラスでメンバー関数が呼び出される前後など、 すべての「安定」状態で TRUE になる必要があります。

Java: 業界標準のオブジェクト指向開発言語。インターネット用アプリケーションや、 さまざまなコンピューター・プラットフォームでの動作が必要なアプリケーションの開発に適しています。

javadoc: JDK に用意されているユーティリティー。Java のソース・コード・ファイルを処理して、HTML 形式の外部文書を生成します。 生成された外部文書は、コード・ファイル中のドキュメンテーション・コメントに基づいて、ソース・コード・ファイルの内容を表します。

JDK: Java Development Kit。

遅延初期化: フィールドを初期化する技術。フィールドが最初に必要になったときに、対応する Getter メンバー関数でフィールドを初期化します。 遅延初期化は、フィールドが必ずしも必要でない場合、またはフィールドの保存に多量のメモリーが必要な場合や、フィールドを永続ストレージから読み出す場合に使用されます。

ローカル変数: ブロック (多くの場合はメンバー関数) のスコープ内で定義された変数。 ローカル変数のスコープは、変数が定義されているブロックです。

メンバー関数: クラスやクラスのインスタンスに関連する、実行可能コードの一部。 メンバー関数は、オブジェクト指向における関数と考えてください。

メンバー関数シグニチャー: 「シグニチャー」を参照。

メソッド・テスト: メンバー関数が定義どおりに動作することを確認する作業。

名前の隠蔽: フィールド、変数、引数の名前に、上位のスコープで使用されているのと同じ名前、または類似した名前を使用すること。 最も一般的な例は、ローカル変数にインスタンス・フィールドと同じ名前を使用することです。コードが理解しにくくなり、バグを招きやすいので、名前の隠蔽は避けてください。

多重定義: メンバー関数が、同じクラス (またはサブクラス) で 2 回以上定義されていること。各定義はシグニチャーだけが異なります。

オーバーライド: メンバー関数がサブクラスで再定義されること。シグニチャーは元の定義と同じです。

パッケージ: 関連するクラスのコレクション。

段落化: コード・ブロックのスコープ内にあるコードを 1 単位 (通常は、水平タブ 1 つ分) インデントして、 ブロック外部のコードと区別できるようにすること。 段落化により、コードの読みやすさが向上します。

パラメーター: メンバー関数に渡される引数。パラメーターは、文字列、整数、オブジェクトなどの定義済みのタイプになります。

事後条件: メンバー関数の実行が完了した後に TRUE になるプロパティーまたはアサーション。

事前条件: メンバー関数が正常に動作するための制約。

プロパティー: 「フィールド」を参照。

Setter: フィールドの値を設定するアクセサー・メンバー関数。

シグニチャー: メンバー関数に渡す必要のある、パラメーターのタイプの組み合わせとその順序。 メンバー関数シグニチャーとも呼ばれます。

単一行コメント: // でコメントを開始する Java のコメント形式。C/C++ 言語のコメント形式と同じです。 一般的に、ビジネス・ロジックに関する内部的なメンバー関数文書に使用されます。

タグ: ドキュメンテーション・コメントの特定の部分を示す規則。javadoc で処理され、専門家が作成したようなコメントを生成します。 タグの例として、@see@author などがあります。

テスト・ハーネス: コードをテストするメンバー関数のコレクション。

UML: 統一モデリング言語。業界標準のモデリング記法です。

可視性: クラス、メンバー関数、フィールドのカプセル化レベルを示す技術。public、protected、private のキーワードを使用して、可視性を定義します。

空白: コードに追加するブランク行、空白、タブ。コードの読みやすさが向上します。

ウィジェット: 「コンポーネント」を参照。