コーディングチェックを行います。
配列宣言時、最後の要素の後ろにカンマが「付いていないこと」をチェックします。
int[] a = new int[] {
1,
2,
3,
};
上の文が、このチェックを有効にしたときに正となります。
最後の要素である 3 の後ろにカンマが付いています。
これを付けないと、今後要素を追加しようとしたときに
「3の後ろにカンマを追加して、改行を入れて、要素を追加する」
という手順を踏む必要があり、少々面倒な上にタイピングミスをする可能性も高くなります。
int[] a = new int[] { 0, 1 };
ただし、上のように中括弧同士が同じ行にあるときは
このチェックを行いません。
よって、この文は正となります。
インライン条件文の使用を拒否します。
srt = (i == 1) ? "on" : "off";
上の例で使っている構文が、インライン条件文です。
これは、以下の文と同等の動きをします。
if (i == 1) {
str = "on";
} else {
str = "off";
}
このように、インライン条件文を使うとプログラムがシンプルに書けて便利なのですが
この構文が読みにくいと感じる技術者も多いようです。
読みにくいだけでなく、NeedBraces と同様の理由で
条件文を1行にまとめてしまう事は色々な弊害を引き起こす可能性があります。
equals(Object) と異なる引数を持つ equals メソッドをチェックします。
詳しくは、FindBugsパターン説明 を参照して下さい。
かの有名な "double-checked locking" をチェックします。
if ( theInstance == null ) { // synchronize only if necessary
synchronized( MySingleton.class ) {
if ( theInstance == null ) {
theInstance = new MySingleton();
}
}
}
詳しい理由は知りませんが、このようなロジックを使っても
完全にスレッドセーフなロジックにはならないようです。
Singletonクラスのインスタンス生成方法にはいくつかありますが、
一番簡単で確実なのは以下の方法です。
public class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
この方法ならば、synchronizedを使う必要もありません。
空行をチェックします。
;
これが空行だ(笑)!
equals メソッドが定義されていて hashCode メソッドが定義されていないクラスをチェックします。
これらは通常両方をオーバーライドする必要があります。
詳しくは、FindBugsパターン説明 を参照して下さい。
変更されないローカル変数やメソッドパラメータが final として宣言されているかどうかをチェックします。
これはなかなか厳しいルールです。
現実問題、これをチェックすると膨大な箇所がチェックに引っかかるでしょう。
チェック対象を設定します。
同一クラス内で定義されたフィールドと同名の
ローカル変数やメソッドパラメータが存在するかどうかチェックします。
これは混乱の元ですので、チェックした方が良いでしょう。
意図せずに同名で定義している場合も多いですから。
ただし、ignoreSetter はONにしておくことをお勧めします。
チェック対象を設定します。
チェックの対象から外す名前を正規表現で設定します。
コンストラクタのパラメータをチェック対象から外します。
Setter内で定義されている変数をチェック対象から外します。
間違ったインスタンス化をチェックします。
r = new Boolean(false); // Boolean.FALSE とした方が良い
本来こういった場合はコンストラクタを削除してしまう方が良いのですが
Java標準ライブラリの場合はそうもいかないので
チェックで制御を掛けるしかないのです。
インスタンス化すべきでないクラスを完全限定名、カンマ区切りで設定します。
様々なトークンの使用許可を設定します。
設定可能なトークンはあらゆる範囲に渡って大量に定義されています。
例えば do〜while だったり、float だったり。
使用するプロジェクトや開発要員のスキルに応じて設定するのが良いでしょう。
詳細は不明です。
式内部で特定の演算子使用をチェックします。
チェックする演算子を設定します。
例えば、Assignment (「=」演算子)をチェックすると、
func(i = 2);
のように式内部で = 演算子を使用すると警告が発生します。
マジックナンバー(5などの数値)を直接使用している箇所をチェックします。
チェック対象の型を設定します。
チェック対象から外す数値を設定します。
デフォルトは -1, 0, 1, 2 です。
switch構文内でdefault節が定義されているかどうかチェックします。
switch構文は通常、予想し得る値を全てcase文に記述しますが
現在予想しない値が将来(仕様修正などによって)入ってくる可能性は必ずあります。
このような場合、default節を定義していないと
バグが混入する危険性が高いのです。
for文の増減部に記述された変数を
ブロック内で変更しているかどうかをチェックします。
for (int k = 0; k < 100; k++) {
...
++k; // for文でインクリメントされる値を、ここで明示的に変更している。
}
こういった処理は、あまり好ましくありません。
k がどのように変化するのかがわかりにくいからです。
こういう場合、forを使わずにwhileを使い
常にブロック内部でkを変更するようにします。
こうすることで、kを変更するコードを一箇所にまとめる事が出来ます。
冗長なthrows節の定義をチェックします。
void func() throws FileNotFoundException, IOException;
上の例の場合、 FileNotFoundException は IOException のサブクラスなので
定義しなくても問題ありません。
詳細は不明です。
サブクラスの冗長定義を許可します。
余談ですが、もしCheckstyleレポートにGot an exception - java.lang.RuntimeException:
というエラーが出て困っているようなら、このチェックを無効にすればエラーは出なくなります。
冗長なboolean演算をチェックします。
if (valid() == true) ... // これは単に if (valid()) ... で良い
冗長なbooleanのreturn句をチェックします。
if (valid()) return false; else return true;
上の例は、以下で置き換えられます。
return !valid();
文字列を == や != で比較している箇所をチェックします。
これは通常 equals で比較する必要があります。
ネストしたifブロックの深さをチェックします。
if (...) {
if (...) {
// この部分でネスト数 = 1
if (...) {
// この部分でネスト数 = 2
}
}
}
許可する最大ネスト数を設定します。
デフォルトは 1 です。
ネストしたtryブロックの深さをチェックします。
許可する最大ネスト数を設定します。
デフォルトは 1 です。
オーバーライドした Object.clone() メソッドの中でsuper.clone() を呼び出しているかどうかチェックします。
オーバーライドした Object.finalize() メソッドの中でsuper.finalize() を呼び出しているかどうかチェックします。
不適切なcatch節の記述をチェックします。
Exceptionなどのcatchを不用意に使用することを防止することが目的です。
catch節に出現してはいけないクラス名を完全限定名、カンマ区切りで設定します。
デフォルトは java.lang.Exception, java.lang.Throwable, java.lang.RuntimeException です。
不適切なthrow文の記述をチェックします。
RuntimeExceptionなどを意図的にthrowすることを防止することが目的です。
throwしてはいけないクラス名を完全限定名、カンマ区切りで設定します。
デフォルトは java.lang.Throwable, java.lang.Error, java.lang.RuntimeException です。
パッケージ宣言をチェックします。
具体的には、無名(デフォルト)パッケージの使用を制限します。
JUnit関連のチェックを行います。
詳細は不明です。
1メソッド内でreturn文が出現する回数をチェックします。
許可する最多出現回数を設定します。
デフォルトは 2 です。
チェック対象から外すメソッド名を正規表現で設定します。
使用が不適切なクラスをチェックします。
例えば Hashtable クラスなどは、JDK1.2以前に存在したクラスで
現在では代わりに HashMap を使用することが推奨されています。
チェック対象を設定します。
チェックするクラス名を完全限定名、カンマ区切りで設定します。
チェック対象から外すメソッド名を設定します。
チェックするクラス名を正規表現で設定します。
クラス内の定義順をチェックします。
簡単に順序を紹介すると、
のようになります。
詳細は ここ を参照して下さい。
パラメータへの代入をチェックします。
void func(int i) {
...
i = 20; // パラメータへの代入がチェックされる
}
JavaにはC++でいう参照渡しのようなものは存在しないので
パラメータへ代入してもその結果は呼び出し元に反映されません。
ですので、こういったロジックは紛らわしいので避けた方が良いのです。
フィールドを明示的にデフォルト値に初期化している箇所をチェックします。
boolean r = false; int count = 0; Object obj = null; // これらは全てデフォルト値なので、初期化しなくても結果は同じ
swicth文のdefault節が、他のcase節よりも後ろに出現しているかどうかチェックします。
あらゆるcase節よりも後ろに出現すれば正となります。
abstract以外のクラスにデフォルトのコンストラクタが定義されているかどうかをチェックします。
case文の中にbreak文などが一切定義されていない箇所をチェックします。
case 1:
i = 1;
// ここにbreakが記述されていない
case 2:
i = 2;
break;
case 3: // このような場合はOK
case 4:
i = 3;
break;
一つのファイル内に同値の文字列が複数定義されているかどうかをチェックします。
許可する重複定義箇所の最大数を設定します。
デフォルトは 1 です。つまり、重複は許可されません。
1行に複数の変数定義がある箇所をチェックします。
int i, j;
同一クラス内からのフィールド、メソッド参照に this. の使用を強制させます。
個人的な観点から言えば、このチェックはお勧めできません。
このようにすると、これらのフィールドやメソッドを
スーパークラスに移行するときに this. の記述を消す必要があります。
しかし、この記述は消さなくてもコンパイルエラーにはならないので
必ずといっていいほど消し忘れという事態が発生してしまうでしょう。
その結果、スーパークラスにあるフィールドを this. として
参照することになり、紛らわしくなります。this. を付けないとフィールドかローカル変数か区別できないという人は
IDEを変えましょう。最近のIDEならこれらを色分けしてくれるので
すぐにわかります。
一番良い解決策は、全てのフィールドをprivateで定義して
同一クラス内からのアクセスも全てアクセッサを通すようにすることです。
こうすれば、
(value + 5)
これはローカル変数ですし
(getValue() + 5)
これはフィールドという感じで簡単に判断できます。
フィールドをチェック対象にします。
メソッドをチェック対象にします。
不必要な括弧をチェックします。
i = (20 + j); // この括弧は必要無い
|
|