検知可能なバグの詳細

このページではSpotBugsが標準で検知可能なバグを一覧で紹介しています。

バッドプラクティス (BAD_PRACTICE)

推奨または必須のコーディングプラクティスへの違反です。たとえば,hashCode と equals の問題,Cloneable イディオム,捨てられた例外,Serializable の問題,finalize の誤用などです。 いくつかのグループはバッドプラクティスを気にしないかもしれないが,我々はこの解析が正確になるよう努力しています。

CNT: 既知の定数の雑な値を見つけた (CNT_ROUGH_CONSTANT_VALUE)

コードの明確さともっと良い正確さのために定義済みライブラリ定数を使用することを推奨します。

NP: 戻り型が Boolean のメソッドが明示的に null を返している (NP_BOOLEAN_RETURN_NULL)

Boolean.TRUEBoolean.FALSEnull を返すメソッドはいつ事故が起きてもおかしくないです。 このメソッドは,まるで論理型の値を返すかのように呼び出されます。 コンパイラは Boolean 値のオートアンボクシングを挿入します。 null 値が返されるなら NullPointerException が発生することになります。

SW: Swing メソッドは AWT イベントディスパッチスレッドから呼び出す必要がある (SW_SWING_METHODS_INVOKED_IN_SWING_THREAD)

(From JDC Tech Tip)
に解説されているとおり,Swing のメソッド, show メソッド, setVisible メソッド, pack メソッドは,フレームのための関連したピアを作成します。 ピアの作成で,システムはイベントディスパッチスレッドを作成します。 これが問題になることがあります。なぜなら pack メソッドと validate メソッドがまだ処理中でもイベントディスパッチスレッドがリスナに通知できるからです。 この状況は,2つのスレッドが Swing コンポーネントにアクセスする可能性があり,デッドロックや,その他のスレッドに関する問題になる可能性がある重大な欠陥です。 pack メソッドの呼び出しはコンポーネントを実体化させます。実体化しているときに,イベントディスパッチスレッドがリスナへの通知を開始する可能性があります。

FI: ファイナライザはフィールドを null にするだけ (FI_FINALIZER_ONLY_NULLS_FIELDS)

このファイナライザは,フィールドを null にすること以外に何もしません。 これはまったく無意味であり,オブジェクトがガベージされ,ファイナライズされ,再びガベージされることを要求しています。 finalize メソッドを除去すべきです。

FI: ファイナライザはフィールドを null にする (FI_FINALIZER_NULLS_FIELDS)

このファイナライザは,フィールドを null にしています。 これは通常誤りでガベージコレクタを助けません。オブジェクトはいずれにしろガベージされます。

UI: クラスが拡張されるなら getResource の使い方は安全ではないかもしれない (UI_INHERITANCE_UNSAFE_GETRESOURCE)

このクラスが別のパッケージによって拡張されるなら, this.getClass().getResource(...) の呼び出しは予想外の結果をもたらす可能性があります。

AM: 空の ZIP ファイルエントリの作成 (AM_CREATES_EMPTY_ZIP_FILE_ENTRY)

このコードは putNextEntry メソッドを呼び出して, closeEntry メソッドをすぐにを呼び出しています。 これは空の ZIP ファイルエントリになります。 エントリデータは putNextEntry メソッドと closeEntry メソッドの呼び出しの間で ZIP ファイルに書き込むべきです。

AM: 空の JAR ファイルエントリの作成 (AM_CREATES_EMPTY_JAR_FILE_ENTRY)

このコードは putNextEntry メソッドを呼び出して, closeEntry メソッドをすぐに呼び出しています。 これは空の JAR ファイルエントリになります。 エントリデータは putNextEntry メソッドと closeEntry メソッドの呼び出しの間で JAR ファイルに書き込むべきです。

IMSE: 疑わしい IllegalMonitorStateException のキャッチ (IMSE_DONT_CATCH_IMSE)

IllegalMonitorStateException は,一般的に設計上の欠陥 (ロックを保持していないオブジェクトで wait メソッドまたは notify メソッドを呼び出す) の場合にだけスローされます。

CN: Cloneable を実装していないクラスが clone メソッドを定義している (CN_IMPLEMENTS_CLONE_BUT_NOT_CLONEABLE)

このクラスは, Cloneable を実装していないのに clone メソッドを定義しています。 これが OK (たとえば,サブクラスのクローンの実装を自分自身で制御したい場合です) という状況もありますが意図したことなのか確認してください。

CN: Cloneable を実装したクラスが clone メソッドを定義も使用もしていない (CN_IDIOM)

このクラスは, Cloneable を実装していますが, clone メソッドを定義も使用もしていません。

CN: clone メソッドが super.clone() を呼び出していない (CN_IDIOM_NO_SUPER_CALL)

この非 final クラスは, super.clone() を呼び出さない clone メソッドを定義しています。 クラス A がサブクラス B によって拡張され,サブクラス Bsuper.clone() を呼び出すなら,クラス Bclone メソッドは,型 A のオブジェクトを返す可能性が高いです。 これは clone のための汎用規約に違反します。

すべての clone メソッドが super.clone() を呼び出すなら Object.clone() が呼び出されることが保証され,常に正しい型のオブジェクトが返されます。

DE: 例外を捨てているかもしれないメソッド (DE_MIGHT_DROP)

このメソッドは,例外を捨てているかもしれません。 一般的にキャッチした例外は何らかの方法で処理または報告すべきです。またはメソッドからスローすべきです。

DE: 例外を無視しているかもしれないメソッド (DE_MIGHT_IGNORE)

このメソッドは例外を無視しているかもしれません。 一般的に例外は何らかの方法で処理または報告すべきです。またはメソッドからスローすべきです。

Dm: System.exit(...) を呼び出しているメソッド (DM_EXIT)

System.exit(...) を呼び出すことは,Java 仮想マシン全体をシャットダウンさせてしまいます。 それが適切な場合にだけ使用すべきです。 System.exit(...) の呼び出しは,他のコードによる呼び出しを困難か不可能にします。 その代わりに RuntimeException をスローすることを検討してください。

Nm: Java の後のバージョンのキーワードである識別子を使用している (NM_FUTURE_KEYWORD_USED_AS_IDENTIFIER)

識別子は,Java の後のバージョンのキーワードとして予約されている単語です。 コードを Java の後のバージョンでコンパイルするためには変更する必要があります。

Nm: Java の後のバージョンのキーワードである識別子を使用している (NM_FUTURE_KEYWORD_USED_AS_MEMBER_IDENTIFIER)

この識別子は,Java の後のバージョンのキーワードとして使われます。 このコードと API を参照するどんなコードも,Java の後のバージョンでコンパイルするためには変更する必要があります。

JCIP: 不変クラスのフィールドは final にすべき (JCIP_FIELD_ISNT_FINAL_IN_IMMUTABLE_CLASS)

クラスは, net.jcip.annotations.Immutable または javax.annotation.concurrent.Immutable というアノテーションが付けられています。 アノテーションのルールは,すべてのフィールドが final であることを義務付けます。

Dm: 危険なメソッド runFinalizersOnExit を呼び出しているメソッド (DM_RUN_FINALIZERS_ON_EXIT)

どんな理由があるにせよ決して System.runFinalizersOnExitRuntime.runFinalizersOnExit を呼び出さないでください。 Java ライブラリで最も危険なメソッドの1つです。 -- Joshua Bloch

NP: equals メソッドは null の引数をチェックしていない (NP_EQUALS_SHOULD_HANDLE_NULL_ARGUMENT)

この equals(Object) メソッドの実装は引数として渡されている null をチェックしていないので, java.lang.Object.equals() で定義された規約に違反しています。 すべての equals メソッドは引数に null が渡されたなら false を返すべきです。

FI: 空のファイナライザは削除すべき (FI_EMPTY)

空の finalize メソッドは役に立たないので削除すべきです。

FI: ファイナライザはスーパークラスのファイナライザを無効にしている (FI_NULLIFY_SUPER)

この空の finalize メソッドは,明示的にスーパークラスによって定義されたどんなファイナライザの効果も無効にします。 スーパークラスのために定義されたどんなファイナライザアクションも実行されません。 これが意図したことではない場合,メソッドを削除してください。

FI: ファイナライザはスーパークラスのファイナライザを呼び出しているだけ (FI_USELESS)

この finalize メソッドは,スーパークラスの finalize メソッドを呼び出しているだけです。 冗長なので削除してください。

FI: ファイナライザはスーパークラスのファイナライザを呼び出していない (FI_MISSING_SUPER_CALL)

この finalize メソッドは,スーパークラスの finalize メソッドを呼び出していません。 したがって,スーパークラスのために定義されたどんなファイナライザアクションも実行されません。 super.finalize() の呼び出しを追加してください。

FI: ファイナライザの明示的な呼び出し (FI_EXPLICIT_INVOCATION)

このメソッドには明示的にオブジェクトで finalize メソッドの呼び出しがあります。 ファイナライザは Java 仮想マシンによって1度だけ実行されることになっているので,これは間違った考えです。

参照によってつながった複数のオブジェクトがファイナライズ可能になると,Java 仮想マシンはすべてのオブジェクトの finalize メソッドを呼び出します。 おそらく異なるスレッドで同時にです。 したがって,クラス Xfinalize メソッドの中から X によって参照されているオブジェクトの finalize メソッドを呼び出すのは,とりわけ間違った考えです。 なぜなら,オブジェクトが既に別のスレッドによってファイナライズされているかもしれないからです。

Eq: equals メソッドは互換性のないオペランドをチェックしている (EQ_CHECK_FOR_OPERAND_NOT_COMPATIBLE_WITH_THIS)

この equals メソッドは,引数が互換性のない型 (すなわちスーパタイプでもなく, equals メソッドを定義しているクラスのスーパータイプでもサブタイプでもないクラス) なのか確かめています。 たとえば, Foo クラスの equals メソッドはそのように見えるかもしれません。

public boolean equals(Object o) {
    if (o instanceof Foo)
        return name.equals(((Foo)o).name);
    else if (o instanceof String)
        return name.equals(o);
    else return false;
}

これは対称的で推移的である equals メソッドを実現するのはとても難しいので,バッドプラクティスと見なされています。 プロパティがなければまったく予想していない振る舞いが起こりえます。

Eq: equals メソッドはサブタイプのために失敗する (EQ_GETCLASS_AND_CLASS_CONSTANT)

このクラスは,サブクラスによる継承によって壊れる equlas メソッドがあります。 equals メソッドは,クラスリテラルを引数のクラスと比較しています (たとえば, Foo クラスで Foo.class == o.getClass() のような判定を行っています)。 this.getClass() == o.getClass() の方がより良いです。

Eq: 共変な equals メソッドの定義 (EQ_SELF_NO_OBJECT)

このクラスは,共変な equals メソッドを定義しています。 java.lang.Objectequals メソッドを正しくオーバーライドするためには equals メソッドのパラメータの型は, java.lang.Object でなければなりません。

Co: 共変な compareTo メソッドの定義 (CO_SELF_NO_OBJECT)

このクラスは,共変な compareTo メソッドを定義しています。 Comparable インタフェースの compareTo メソッドを正しく実装するためには compareTo メソッドのパラメータの型は, java.lang.Object でなければなりません。

Co: compareTo()/compare() は Integer.MIN_VALUE を返す (CO_COMPARETO_RESULTS_MIN_VALUE)

いくつかの状況下では,この compareTo または compare メソッドは Integer.MIN_VALUE を返します。非常に悪いプラクティスです。 compareTo メソッドの戻り値で重要なことは結果の符号だけです。 しかし,結果の符号を無効にすることを期待して, compareTo メソッドの戻り値を無効にすることがあります。 返された値が Integer.MIN_VALUE の場合を除いてです。 Integer.MIN_VALUE よりも-1を返してください。

Co: compareTo()/compare() は間違って float または double 値を処理する (CO_COMPARETO_INCORRECT_FLOATING)

このメソッドはこのようなパターンを使用して double または float 値を比較しています : val1 > val2 ? 1 : val1 < val2 ? -1 : 0。 このパターンは,-0.0 や NaN の値が正しく処理されたないため,不正なソート結果や破損したコレクション(比較された値がキーとして使われる場合)が生成される可能性があります。 Double.compare または Float.compare メソッドを使用して,すべての特殊なケースを正確に処理することを検討してください。

RV: compareTo()/compare() の結果を無効にする (RV_NEGATING_RESULT_OF_COMPARETO)

このコードは compareTo または compare メソッドの戻り値を無効にしています。 これは疑わしいかバッドプログラミングプラクティスです。戻り値が Integer.MIN_VALUE なので,戻り値を無効にすることは結果の符号を無効にしません。 結果を無効にするのではなくオペランドの順序を逆にすることによって,同じ意図した結果を得ることができます。

ES: String オブジェクトを == や != を使用して比較している (ES_COMPARING_STRINGS_WITH_EQ)

このコードは参照等価性のために ==!= を使用して java.lang.String オブジェクトを比較しています。 両方の文字列がソースファイルの定数か, String.intern() を使用して正準化されていないかぎり,同じ文字列は2つの異なる String オブジェクトによって表されるかもしれません。 その代わりに equals(Object) メソッドを使用することを検討してください。

ES: String パラメータを == や != を使用して比較している (ES_COMPARING_PARAMETER_STRING_WITH_EQ)

このコードは参照等価性のために ==!= を使用して java.lang.String パラメータを比較しています。 文字列定数または正準化された文字列だけをメソッドに渡すことを呼び出し元に要求することは,不必要に脆弱であり,測定可能な性能の向上につながることはほとんどありません。 その代わりに equals(Object) メソッドを使用することを検討してください。

Eq: compareTo(...) メソッドを定義して Object.equals() を使用しているクラス (EQ_COMPARETO_USE_OBJECT_EQUALS)

このクラスは, compareTo(...) メソッドを定義していますが, equals メソッドは java.lang.Object から継承しています。 一般的にequals メソッドが true を返す場合に限り, compareTo メソッドは0を返すべきです。 これが違反されるなら奇妙で予測できない失敗が PriorityQueue などのクラスで発生します。 J2SE 5.0では, PriorityQueue.remove()compareTo メソッドを使用しますが,Java SE 6では, equals メソッドを使用します。

Comparable インタフェースの compareTo メソッドの JavaDoc を引用します。

必須というわけではありませんが, (x.compareTo(y)==0) == (x.equals(y)) であることが強く推奨されます。 一般的にComparable インタフェースを実装しているクラスで,この条件に違反するクラスは明確にこの事実を示す必要があります。 「注:このクラスは equals と一貫性のない自然順序付けを持ちます」などと明示することをお勧めします。

HE: hashCode メソッドを定義して Object.equals() を使用しているクラス (HE_HASHCODE_USE_OBJECT_EQUALS)

このクラスは, hashCode メソッドを定義していますが, equals メソッドは java.lang.Object から継承しています (オブジェクトの参照比較で等価性を判定します)。 これは「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode メソッドの汎用規約に従っているかもしれませんが, おそらく, hashCode メソッドをオーバーライドすることによって意図されたことではありません。 (hashCode メソッドをオーバーライドすることは,オブジェクトの同一性が単純な参照等価性よりも複雑な規約に基づくことを意味します)。

このクラスのインスタンスが HashMap/HashTable に決して代入されるだろうと思わないなら推奨される hashCode メソッドの実装は次のようになります。

public int hashCode() {
    assert false : "hashCodeが呼び出されることは想定されていません。";
    return 42; // 任意の定数
}

HE: hashCode メソッドを定義していますが equals メソッドは定義していないクラス (HE_HASHCODE_NO_EQUALS)

このクラスは, hashCode メソッドを定義していますが, equals メソッドは定義していません。 これは「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode メソッドの汎用規約に違反するかもしれません。

HE: equals メソッドを定義して Object.hashCode() を使用しているクラス (HE_EQUALS_USE_HASHCODE)

このクラスは, equals(Object) をオーバーライドしていますが, hashCode メソッドは java.lang.Object から継承しています (同一性ハッシュコード (Java 仮想マシンによってオブジェクトに代入された任意の値) を返します)。 したがって,「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode メソッドの汎用規約に違反するかもしれません。

このクラスのインスタンスが HashMap/HashTable に決して代入されるだろうと思わないなら推奨される hashCode メソッドの実装は次のようになります。

public int hashCode() {
    assert false : "hashCodeが呼び出されることは想定されていません。";
    return 42; // 任意の定数
}

HE: equals メソッドを継承して Object.hashCode() を使用しているクラス (HE_INHERITS_EQUALS_USE_HASHCODE)

このクラスは,抽象スーパークラスから equals(Object) メソッドを継承して, java.lang.Object から hashCode メソッドを継承しています (同一性ハッシュコード (Java 仮想マシンによってオブジェクトに代入された任意の値) を返します)。 したがって,「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode メソッドの汎用規約に違反するかもしれません。

hashCode メソッドを定義したくないまたはオブジェクトが HashMap/Hashtable に決して格納されないだろうと思っているなら UnsupportedOperationException をスローする hashCode() メソッドを定義してください。

HE: equals メソッドは定義していますが hashCode メソッドは定義していないクラス (HE_EQUALS_NO_HASHCODE)

このクラスは, equals(Object) メソッドをオーバーライドしていますが, hashCode メソッドはオーバーライドしていません。 したがって,「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode メソッドの汎用規約に違反するかもしれません。

Eq: 抽象クラスは共変な equals メソッドを宣言している (EQ_ABSTRACT_SELF)

このクラスは,共変な equals メソッドを定義しています。 java.lang.Objectequals メソッドを正しくオーバーライドするためには equals メソッドのパラメータの型は, java.lang.Object でなければなりません。

Co: 抽象クラスは共変な compareTo メソッドを定義している (CO_ABSTRACT_SELF)

このクラスは,共変な compareTo メソッドを定義しています。 Comparable インタフェースの compareTo メソッドを正しく実装するためには compareTo メソッドのパラメータの型は, java.lang.Object でなければなりません。

IC: スーパークラスは初期化中にサブクラスを使用している (IC_SUPERCLASS_USES_SUBCLASS_DURING_INITIALIZATION)

クラスは,初期化中にサブクラスを積極的に使用しています。サブクラスはこの時点ではまだ初期化されていません。
たとえば,次のコードにおいて, foonull です。

public class CircularClassInitialization {
    static class InnerClassSingleton extends CircularClassInitialization {
        static InnerClassSingleton singleton = new InnerClassSingleton();
    }

    static CircularClassInitialization foo = InnerClassSingleton.singleton;
}

SI: スタティックイニシャライザは,すべての static final フィールドが代入される前にインスタンスを作成する (SI_INSTANCE_BEFORE_FINALS_ASSIGNED)

すべての static final フィールドが初期化される前にスタティックイニシャライザがクラスのインスタンスを作成します。

It: Iterator.next() が NoSuchElementException をスローできない (IT_NO_SUCH_ELEMENT)

このクラスは, java.util.Iterator を実装しています。 しかしながら, next メソッドは java.util.NoSuchElementException をスローできません。 next メソッドは,それ以上要素を返すことができないときは NoSuchElementException をスローするように変更すべきです。

ME: 列挙型フィールドは public で可変である (ME_MUTABLE_ENUM_FIELD)

可変 public フィールドが public 列挙型の中に定義されています。 したがって,フィールドは悪意のあるコードや別のパッケージによって思いがけず変更される可能性があります。 可変列挙型フィールドが遅延初期化で使用されるかもしれないとしても外界へ暴露するバッドプラクティスです。 このメソッドを final およびパッケージプライベートとして宣言することを考えてください。

ME: public 列挙型メソッドが無条件にフィールドを設定する (ME_ENUM_FIELD_SETTER)

無条件に列挙型フィールドを設定している public 列挙型で public メソッドを宣言しています。 したがって,フィールドは悪意のあるコードや別のパッケージによって思いがけず変更される可能性があります。 可変列挙型フィールドが遅延初期化で使用されるかもしれないとしても外界へ暴露するバッドプラクティスです。 このメソッドを除去するかパッケージプライベートとして宣言することを考えてください。

Nm: メソッド名は小文字から始めるべき (NM_METHOD_NAMING_CONVENTION)

メソッド名は,最初の文字は小文字にし,それに続く各単語の最初の文字を大文字にした動詞にすべきです。

Nm: フィールド名は小文字から始めるべき (NM_FIELD_NAMING_CONVENTION)

final ではないフィールドの名前は,最初の文字は小文字にし,それに続く各単語の最初の文字を大文字にすべきです。

Nm: クラス名は実装されたインタフェースの単純名を遮るべきではない (NM_SAME_SIMPLE_NAME_AS_INTERFACE)

このクラスまたはインタフェースは,インタフェースが異なるパッケージであるということを除いて実装された/拡張されたインタフェースと同一の単純名です (たとえば, alpha.Foobeta.Foo を継承しているような状況です)。 これは非常に紛らわしく,参照関係を解決するために import 文を見なければならなかったり,スーパークラスのメソッドをオーバーライドしないで誤ってメソッドを定義する状況を作り出します。

Nm: クラス名はスーパークラスの単純名を遮るべきではない (NM_SAME_SIMPLE_NAME_AS_SUPERCLASS)

このクラスは,スーパークラスが異なるパッケージであるということを除いて,スーパークラスと同一の単純名です (たとえば, alpha.Foobeta.Foo を拡張します)。 これは非常に紛らわしく,参照関係を解決するために import 文を見なければならなかったり,スーパークラスのメソッドをオーバーライドしないで誤ってメソッドを定義する状況を作り出します。

Nm: クラス名は大文字から始めるべき (NM_CLASS_NAMING_CONVENTION)

クラス名は,最初の文字とそれに続く各単語の最初の文字を大文字にした名詞にすべきです。 クラス名は単純でわかりやすいようにしてください。 頭文字や略語 (URLやHTMLなどのように略語がロング形式よりもはるかに広く使われている場合を除く) の使用は避けてください。

Nm: 非常に紛らわしい名前のメソッド (多分意図的) (NM_VERY_CONFUSING_INTENTIONAL)

参照されたメソッドは,大文字と小文字だけが異なる名前があります。 大文字と小文字が同一ならメソッドの1つが他のメソッドをオーバーライドするので,非常に紛らわしいです。 他のメソッドの存在から,これらのメソッドの両方の存在が意図的で,確実に混乱させていると思われます。 APIの凍結によって両方とも持たざるを得ない場合を除き,それらのうちの1つを除去しようと努力すべきです。

Nm: パラメータの間違ったパッケージのためにスーパークラスのメソッドをオーバーライドしていないメソッド (NM_WRONG_PACKAGE_INTENTIONAL)

パラメータの型が正確にスーパークラスで対応するパラメータの型と合致していないので,サブクラスのメソッドはスーパークラスの類似したメソッドをオーバーライドしていません。
たとえば次のようなコードです。

import alpha.Foo;

public class A {
    public int f(Foo x) { return 17; }
}
----
import beta.Foo;

public class B extends A {
    public int f(Foo x) { return 42; }
    public int f(alpha.Foo x) { return 27; }
}

クラス B で定義された f(Foo) メソッドは,クラス Af(Foo) メソッドをオーバーライドしません。 これは引数の型 Foo が違うパッケージだからです。

この場合,サブクラスがスーパークラスのメソッドと同一のシグネチャでメソッドを定義しているので,おそらく理解できます。 しかしながら,そのようなメソッドは非常に紛らわしいです。 類似しているが同一ではないシグネチャのメソッドを除去するか,非推奨にすることを強く検討すべきです。

Nm: 紛らわしい名前のメソッド (NM_CONFUSING)

参照されたメソッドは,大文字と小文字だけが異なる名前があります。

Nm: 例外クラスのように命名されているが,クラスは Exception から派生されていない (NM_CLASS_NOT_EXCEPTION)

このクラスは,例外クラスから派生されていないのにクラス名が「Exception」で終わっています。 このクラスのユーザが混乱するでしょう。

RR: InputStream.read() の戻り値を無視しているメソッド (RR_NOT_CHECKED)

このメソッドは,複数バイトを返す可能性がある java.io.InputStream.read() (またはそのバリエーション) の戻り値を無視しています。 戻り値がチェックされないと呼び出し元は要求したバイト数よりも少ないバイト数を読み出した場合,正しく処理できません。 これは潜在的なバグで,多くのプログラムでは,入力ストリームからの読み出しは,通常要求した完全なデータ量を読み出しますが,散発的に失敗することがあります。

RR: InputStream.skip() の戻り値を無視しているメソッド (SR_NOT_CHECKED)

このメソッドは,複数バイトをスキップする可能性がある java.io.InputStream.skip() の戻り値を無視しています。 戻り値がチェックされないと呼び出し元は要求したバイト数よりも少ないバイト数しかスキップしなかった場合,正しく処理できません。 これは潜在的なバグで,多くのプログラムでは,入力ストリームからのスキップは,通常要求した完全なデータ量をスキップをしますが,散発的に失敗することがあります。 しかしながら,バッファードストリーム での skip メソッドはバッファのデータをスキップするので要求されたバイト数のスキップは常に失敗します。

Se: Serializable なクラスのスーパークラスで,引数なしコンストラクタを定義していない (SE_NO_SUITABLE_CONSTRUCTOR)

このクラスは Serializable インタフェースを実装していますが,そのスーパークラスは実装していません。 そのようなオブジェクトが直列化復元されるとき,スーパークラスのフィールドはスーパークラスの引数なしコンストラクタを呼び出すことによって初期化される必要があります。 スーパークラスには引数なしコンストラクタがないので,直列化と直列化復元は実行時に失敗します。

Se: Externalizable なクラスが引数なしコンストラクタを定義していない (SE_NO_SUITABLE_CONSTRUCTOR_FOR_EXTERNALIZATION)

このクラスは, Externalizable インタフェースを実装していますが,publicな引数なしコンストラクタを定義していません。 Externalizable オブジェクトが直列化復元されるときは,最初にpublicな引数なしコンストラクタを呼び出すことによって構築される必要があります。 このクラスにはpublicな引数なしコンストラクタがないので,直列化と直列化復元は実行時に失敗します。

Se: Comparator は Serializable を実装していない (SE_COMPARATOR_SHOULD_BE_SERIALIZABLE)

このクラスは Comparator インタフェースを実装しています。 Serializable インタフェースも実装する必要があるのか検討すべきです。 コンパレータが TreeMap のような順序付きコレクションを構築するために使われるなら,コンパレータが直列化可能な場合だけ, TreeMap は直列化可能です。 大部分のコンパレータがほとんど状態を持たないとしても直列化可能にすることは簡単で良い防衛的なプログラミングです。

SnVI: Serializable なクラスが serialVersionUID を定義していない (SE_NO_SERIALVERSIONID)

このクラスは Serializable インタフェースを実装していますが, serialVersionUID フィールドを定義していません。 .class オブジェクトへの参照を追加するのと同じくらい簡単な変更でクラスに合成フィールドを追加します。 それは,残念ながら暗黙の serialVersionUID を変えます (たとえば, String.class への参照を追加すると, class$java$lang$String という static フィールドを生成します)。 また,バイトコードコンパイラへの異なるソースコードは,クラスオブジェクトまたは内部クラスを参照するために生成される合成変数のために異なる命名規則を使用するかもしれません。 バージョンを横断する Serializable の相互運用性を保証するために明示的に serialVersionUID を追加することを検討してください。

Se: readResolve メソッドの戻り値の型が Object で宣言されていない (SE_READ_RESOLVE_MUST_RETURN_OBJECT)

readResolve メソッドが直列化機構で認識されるためには戻り値の型が Object で宣言されなければなりません。

Se: 直列化復元によって設定されない transient フィールド (SE_TRANSIENT_FIELD_NOT_RESTORED)

このクラスには複数の場所で更新されるフィールドがあります。したがって,このクラスの状態の一部だと思われます。 しかしながら,フィールドは transient と宣言しているので, readObject/readResolve で値が設定されません。 クラスの直列化復元されたインスタンスにはデフォルト値が設定されます。

Se: serialVersionUID が final ではない (SE_NONFINAL_SERIALVERSIONID)

このクラスは, final ではない serialVersionUID フィールドを定義しています。 直列化を目的としてバージョン UID を指定することを意図しているならフィールドは final とすべきです。

Se: serialVersionUID が static ではない (SE_NONSTATIC_SERIALVERSIONID)

このクラスは, static ではない serialVersionUID フィールドを定義しています。 直列化を目的としてバージョン UID を指定することを意図しているならフィールドは static とすべきです。

Se: serialVersionUID が long ではない (SE_NONLONG_SERIALVERSIONID)

このクラスは, long ではない serialVersionUID フィールドを定義しています。 直列化を目的としてバージョン UID を指定することを意図しているならフィールドは long とすべきです。

Se: 直列化可能クラスの非 transient で非直列化可能なインスタンスフィールド (SE_BAD_FIELD)

この直列化可能クラスは, transientSerializablejava.lang.Object でもない非プリミティブ型のインスタンスフィールドを定義して, Externalizable インタフェースまたは readObject メソッドと writeObject メソッドを実装するように見えません。 また, Externalizable インタフェースも実装していなくて, readObject メソッドも writeObject メソッドも定義していません。 非直列化可能オブジェクトがこのフィールドに格納されるならクラスのオブジェクトは正しく直列化復元されません。

Se: 直列化可能な内部クラス (SE_INNER_CLASS)

この直列化可能なクラスは内部クラスです。内部クラスを直列化しようとすると関連した外部クラスのインスタンスも直列化します。 外部クラスのインスタンスは直列化可能なので失敗しません。しかし,意図していたよりももっと多くのデータを直列化するかもしれません。 できれば,内部クラスを static にして問題を解決すべきです。

Se: 非直列化可能クラスに直列化可能な内部クラスがある (SE_BAD_FIELD_INNER_CLASS)

この直列化可能クラスは,非直列化可能クラスの内部クラスです。 内部クラスを直列化しようとすると関連する外部クラスのインスタンスを結びつけようとするので,実行時エラーの原因になります。

できれば,内部クラスを static にして問題を解決すべきです。 外部クラスの直列化は動作可能かもしれませんが,内部クラスのインスタンスを直列化することは,外部クラスのインスタンスも常に直列化することを意味します。 本当に望むことですか。

Se: 非直列化可能な値を直列化可能クラスのインスタンスフィールドに格納している (SE_BAD_FIELD_STORE)

非直列化可能な値を直列化可能クラスの 非 transient フィールドに格納しています。

RV: 例外的戻り値を無視しているメソッド (RV_RETURN_VALUE_IGNORED_BAD_PRACTICE)

このメソッドはチェックされていない値を返しています。 戻り値は異常か予想外の実行結果を示す可能性があるのでチェックすべきです。 たとえば, File.delete() はファイルをうまく削除できなかったなら,例外をスローするのではなく false を返します。 結果をチェックしないなら例外的戻り値を返すメソッドの呼び出しで予想外の振る舞いの合図に気づきません。

NP: null を返すかもしれない toString メソッド (NP_TOSTRING_COULD_RETURN_NULL)

この toString メソッドは,いくつかの条件で null を返すと思われます。 仕様を寛大に読むとこれが許されると解釈できるかもしれませんが,それはおそらく間違った考えで,他のコードが壊れる原因になる可能性があります。 null ではなく空の文字列,または,いくつかの他の適切な文字列を返してください。

NP: null を返すかもしれない clone メソッド (NP_CLONE_COULD_RETURN_NULL)

この clone メソッドは,いくつかの条件で null を返すと思われます。 しかし, clone メソッドは決して null を返すのは許されません。 この経路が到達できないことを確信しているなら,代わりに AssertionError をスローしてください。

OS: ストリームのクローズに失敗するかもしれないメソッド (OS_OPEN_STREAM)

このメソッドは,入出力ストリームオブジェクトを作成していますが,任意のフィールドに割り当てたり,クローズする可能性のある別のメソッドに渡したり,返すことはなく,メソッドからのすべての経路でクローズするように見えません。 これはファイルディスクリプタリークの原因になることがあります。 ストリームがクローズされることを確実にするために finally ブロックを使用することは一般的に良い考えです。

OS: 例外経路でストリームのクローズに失敗するかもしれないメソッド (OS_OPEN_STREAM_EXCEPTION_PATH)

このメソッドは,入出力ストリームオブジェクトを作成していますが,任意のフィールドに割り当てたり,クローズする可能性のある別のメソッドに渡したり,返すことはなく,メソッドからのすべての例外経路でクローズするように見えません。 これはファイルディスクリプターリークの原因になることがあります。 ストリームがクローズされることを確実にするために finally ブロックを使用することは一般的に良い考えです。

RC: 定数の疑わしい参照比較 (RC_REF_COMPARISON_BAD_PRACTICE)

このメソッドは,参照値を == または != 演算子を使用して定数と比較しています。 一般的にこの型のインスタンスを比較する正しい方法は equals メソッドです。 等価で識別可能なインスタンスを作成する可能性がありますが異なるオブジェクトなので == で比較しないでください。 一般的に参照によって比較されるべきではないクラスの例は, java.lang.Integerjava.lang.Float などです。

RC: Boolean 値の疑わしい参照比較 (RC_REF_COMPARISON_BAD_PRACTICE_BOOLEAN)

このメソッドは, == または != 演算子を使用して2つの Boolean 値を比較しています。 一般的には2つの Boolean 値 (Boolean.TRUEBoolean.FALSE) だけですが, new Boolean(b) コンストラクタを使用して他の Boolean オブジェクトを作成する可能性があります。 そのようなオブジェクトを回避することは最高です。 しかし,それらが存在するなら, Boolean オブジェクトの等価性をチェックするために .equals(...) ではなく == または != を使用しているなら異なる結果をもたらします。

FS: 書式文字列は n よりも %n を使用すべき (VA_FORMAT_STRING_USES_NEWLINE)

この書式文字列は改行文字 (\n) が含まれています。 一般的に書式文字列には %n を使用することがより望ましいです。%n は,プラットフォーム特有の行セパレータを作り出します。

BIT: ビット演算の符号をチェックする (BIT_SIGNED_CHECK)

このメソッドは, ((event.detail & SWT.SELECTED) > 0) のような式で比較しています。 ビット演算をより大きい演算子で比較することは,予想外の結果 (もちろん, SWT.SELECTED の値による) の原因になる可能性があります。 SWT.SELECTED が負数であるなら,これはバグの候補です。 SWT.SELECTED が負ではないとしても, > 0 の代わりに != 0 を使用することが良いプラクティスであると思われます。

ODR: データベースリソースのクローズに失敗するかもしれないメソッド (ODR_OPEN_DATABASE_RESOURCE)

このメソッドは,データベースリソース (たとえば,データベースコネクションや行セット) を作成していますが,どんなフィールドにも代入していないか,他のメソッドにも渡していないか,戻り値にもしていません。 そして,メソッドからのすべての経路でオブジェクトをクローズするように見えません。 メソッドからのすべての経路でデータベースリソースのクローズが失敗すると性能低下になることがあります。 データベースとの通信で問題があるアプリケーションの原因になる可能性があります。

ODR: 例外経路でデータベースリソースのクローズに失敗するかもしれないメソッド (ODR_OPEN_DATABASE_RESOURCE_EXCEPTION_PATH)

このメソッドは,データベースリソース (たとえば,データベースコネクションや行セット) を作成していますが,どんなフィールドにも代入していないか,他のメソッドにも渡していないか,戻り値にもしていません。 そして,メソッドからのすべての例外経路でオブジェクトをクローズするように見えません。 メソッドからのすべての経路でデータベースリソースのクローズが失敗すると性能低下になることがあります。 データベースとの通信で問題があるアプリケーションの原因になる可能性があります。

ISC: static メソッドだけを提供するクラスの不必要なインスタンス化 (ISC_INSTANTIATE_STATIC_CLASS)

このクラスは, static メソッドだけを提供するクラスのオブジェクトを作成しています。 このオブジェクトは作成する必要はありません。修飾子として直接クラス名を使用する static メソッドにアクセスしてください。

DMI: Random オブジェクトが作成され1度しか使われない (DMI_RANDOM_USED_ONLY_ONCE)

このコードは java.util.Random オブジェクトを作成して1つの乱数を生成するために使用して捨てています。 これはあまり良くない品質の乱数を作り出し,効率が悪いです。 できれば, Random オブジェクトを1つだけ作成して保存されるようにコードを書き直してください。 そして,毎回新しい乱数は既存の Random オブジェクトを呼び出して取得することが必要です。

生成された乱数が推測可能ではないことが重要なら,乱数ごとに新しい Random オブジェクトを作成してはいけません (値はあまりに簡単に推測可能です)。 その代わりに java.security.SecureRandom の使用を強く検討すべきです (そして必要とされる乱数ごとに新しい SecureRandom のオブジェクトを作成することを回避します)。

BC: equals メソッドは引数の型を仮定すべきではない (BC_EQUALS_METHOD_SHOULD_WORK_FOR_ALL_OBJECTS)

equals(Object o) メソッドは, o の型についてどんな仮定もするべきではありません。 othis と同じ型ではないなら単に false を返すべきです。

J2EE: HttpSession への非直列化可能オブジェクトの格納 (J2EE_STORE_OF_NON_SERIALIZABLE_OBJECT_INTO_SESSION)

このコードは HttpSession に非直列化可能オブジェクトを格納していると思われます。 このセッションが不活性化されるか移行したなら,エラーを招きます。

GC: 検査されない型への総称呼び出し (GC_UNCHECKED_TYPE_IN_GENERIC_CALL)

総称型パラメータからの特定の型が予想される Object 型をコンパイルするとき,総称型コレクションメソッドへの呼び出しは引数を渡します。 したがって,標準の Java 型システムも静的解析もパラメータとして渡されているオブジェクトが適切な型かどうかに関する有用な情報を提供できません。

PZ: 繰り返しでエントリオブジェクトを再利用しない (PZ_DONT_REUSE_ENTRY_OBJECTS_IN_ITERATORS)

このクラスは, IteratorMap.Entry で基底 Map のビューを返すことを許可された両方の entrySet メソッドがあります。 この巧妙なアイデアは, Map 実装で使用されましたが,厄介なコーディングミスの可能性を取り込みました。 Map mentrySet のためのそのような反復子を返すならば, c.addAll(m.entrySet()) はひどく間違っているでしょう。 OpenJDK 1.7 の すべての Map 実装はこれを回避するために書き直されました。

DMI: エントリセットの要素を加えることは,Entry オブジェクトの再利用のために失敗するかもしれない (DMI_ENTRY_SETS_MAY_REUSE_ENTRY_OBJECTS)

entrySet メソッドは,一つの Entry オブジェクトを再利用し,反復中に返される基底 Map のビューを返すことが許可されています。 Java 1.6 の時点で, IdentityHashMapEnumMap の両方がそうしました。 そのような Map を通して繰り返すとき,エントリ値は次の繰り返しへ進むまでが有効です。 たとえば, addAll メソッドにそのような entrySet を渡そうと試みるのは,ひどく間違っているでしょう。

DMI: コレクションを消去するために removeAll メソッドを使用しない (DMI_USING_REMOVEALL_TO_CLEAR_COLLECTION)

コレクション c からすべての要素を除去したいなら, c.removeAll(c) ではなく c.clear を使用してください。 コレクションを消去するために c.removeAll(c) を呼び出すことは,それほど明確ではなく,タイプミスからの誤りに影響されやすく,効率的ではなく,いくつかのコレクションでは, ConcurrentModificationException をスローするかもしれません。

正確性 (CORRECTNESS)

バグの可能性 - おそらく,開発者が意図していなかったコードになっている明らかなコーディングミスです。 我々は低い誤検出率のために努力します。

CN: スーパークラスのメソッドが @OverridingMethodsMustInvokeSuper で修飾されていますが, オーバーライドしているメソッドはスーパークラスのメソッドを呼び出していません。 (OVERRIDING_METHODS_MUST_INVOKE_SUPER)

スーパークラスのメソッドが @OverridingMethodsMustInvokeSuper で修飾されていますが, オーバーライドしているメソッドはスーパークラスのメソッドを呼び出していません。

NP: Optional の戻り型を持つメソッドが明示的に null を返す (NP_OPTIONAL_RETURN_NULL)

Optional の戻り型 (java.util.Optional または com.google.common.base.Optional) の使い方で明示的に null を返すのは設計が望ましくないことを意味します。 null 値をこのようなケースで返すことは契約違反で,多分クライアントコードを破壊するでしょう。

NP: 非 null フィールドは初期化されていない (NP_NONNULL_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR)

フィールドは,非 null としてマークされていますが,コンストラクタで書き込まれていません。 フィールドは,コンストラクタの間,ほかの場所で初期化されるか,または使用する前に常に初期化されるかもしれません。

VR: 解決できないクラス,メソッドへの参照 (VR_UNRESOLVABLE_REFERENCE)

このクラスは,解析されているライブラリに対して解決されないクラスまたはメソッドを参照しています。

IL: 明らかな無限ループ (IL_INFINITE_LOOP)

このループは,例外をスローする以外の方法で終了させることができないように思われます。

IO: オブジェクト出力ストリームへの追加は失敗に終わる (IO_APPENDING_TO_OBJECT_OUTPUT_STREAM)

このコードはファイルを追加モードで開いて,オブジェクト出力ストリームの中で結果をラップしています。 これはファイルに格納された既存のオブジェクト出力ストリームに追加できないでしょう。 オブジェクト出力ストリームに追加したいなら,オブジェクト出力ストリームを開いておく必要があります。

追加モードでファイルを開き,オブジェクト出力ストリームで書き込むことができる唯一の状況は, ファイルを読み出すときにランダムアクセスモードで開き,追加を開始するところまでバイトオフセットをシークすると計画した場合です。

IL: 明らかな無限再帰ループ (IL_INFINITE_RECURSIVE_LOOP)

このメソッドは,無条件で自分自身を呼び出します。これはスタックオーバーフローになる無限再帰ループを示しています。

IL: コレクションは自分自身を追加している (IL_CONTAINER_ADDED_TO_ITSELF)

コレクションは,自分自身を追加しています。その結果,hashCode を計算すると StackOverflowException をスローします。

RpC: 条件テストの繰り返し (RpC_REPEATED_CONDITIONAL_TEST)

このコードには条件テストが2回,つまり,1つめの条件テストが正しいとき,2つめの条件テストが実行されます (たとえば, x == 0 || x == 0)。 多分,2つめの条件テストは何か他のことを意図しています (たとえば, x == 0 || y == 0)。

FL: 浮動小数点精度を使用した計算をしている (FL_MATH_USING_FLOAT_PRECISION)

このメソッドは,浮動小数点精度を使用して計算をしています。浮動小数点精度は非常に不正確です。 たとえば, 16777216.0f + 1.0f = 16777216.0f。 その代わりに double の使用を検討してください。

CAA: おそら互換性のない要素をく共変配列に格納している (CAA_COVARIANT_ARRAY_ELEMENT_STORE)

配列に格納していてる値の型が配列型と一致していません。 実際の配列型が宣言された変数またはフィールドの型よりも狭くなっていて,この割り当てがオリジナルの配列型を満たしていないことが解析でわかっています。 この割り当ては実行時に ArrayStoreException を引き起こすことがあります。

Dm: EasyMock メソッドへの役に立たない/無意味な呼び出し (DMI_VACUOUS_CALL_TO_EASYMOCK_METHOD)

この呼び出しは EasyMock メソッドにどんなオブジェクトも渡さないので何もしません。

Dm: ScheduledThreadPoolExecutor の最大プールサイズを変えようとする無駄な試み (DMI_FUTILE_ATTEMPT_TO_CHANGE_MAXPOOL_SIZE_OF_SCHEDULED_THREAD_POOL_EXECUTOR)

ScheduledThreadPoolExecutorThreadPoolExecutor から継承されますが継承されたチューニングメソッドの一部は有用ではありません。 特に,corePoolSize スレッドとアンバウンド形式のキューを使用する固定サイズプールとして動作するので,maximumPoolSize の調整は有用な効果がありません。
(Javadoc)

DMI: 正確に表されない double から構築された BigDecimal (DMI_BIGDECIMAL_CONSTRUCTED_FROM_DOUBLE)

このコードは10進数の数にうまく変換されない double 値から BigDecimal を作成しています。 たとえば,Java で new BigDecimal(0.1) と書くと,0.1と正確に等しい BigDecimal (スケールが1でスケールなしの値が1) が作成されると思うかもしれませんが, 実際には0.1000000000000000055511151231257827021181583404541015625と等しくなります。

おそらく BigDecimal.valueOf(double d) メソッドの使用が望ましいです。BigDecimal (たとえば, BigDecimal.valueOf(0.1) は0.1を与えます) を作成するためには double の文字列表現を使用します。

Dm: コアプールサイズが0の ScheduledThreadPoolExecutor の作成 (DMI_SCHEDULED_THREAD_POOL_EXECUTOR_WITH_ZERO_CORE_THREADS)

コアプールサイズが0の ScheduledThreadPoolExecutor は決して何も実行しません。 最大プールサイズへの変更は無視されます。
(Javadoc)

Dm: ランタイムリテンションなしで,アノテーションの存在を調べるためにリフレクションを使用することはできない (DMI_ANNOTATION_IS_NOT_VISIBLE_TO_REFLECTION)

アノテーションに @Retention(RetentionPolicy.RUNTIME) アノテーションが付いていなければ,リフレクション (たとえば, isAnnotationPresent(...) メソッド) を使用して観測することができません。

NP: null の引数をチェックしていないメソッド (NP_ARGUMENT_MIGHT_BE_NULL)

このメソッドへのパラメータが null かどうか確かめるために常にチェックされるべき値として特定されました。 しかし, null チェックをしないで, null 値が利用されています。

RV: 符号付き整数の乱数の絶対値を計算する間違った試み (RV_ABSOLUTE_VALUE_OF_RANDOM_INT)

このコードは符号付き整数の乱数を生成して絶対値を計算しています。 乱数ジェネレータで返される数が Integer.MIN_VALUE なら結果は同様に負です (Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE なので)。 (同じ問題は long 値でも同様に起きます)。

RV: 符号付き32ビットハッシュコードの絶対値を計算する間違った試み (RV_ABSOLUTE_VALUE_OF_HASHCODE)

このコードはハッシュコードを生成して絶対値を計算しています。 ハッシュコードが Integer.MIN_VALUE なら結果は同様に負です (Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE なので)。

文字列の2^32個に1個は Integer.MIN_VALUE のハッシュコードを持っていて,「polygenelubricants」,「GydZG_」,「DESIGNING WORKHOUSES」が該当します。

RV: 0から1の乱数値は整数値0に丸められる (RV_01_TO_INT)

0から1の乱数値は整数値0に丸められます。 おそらく整数に丸められる前に何か他のことによって乱数値を乗算したかったか,または Random.nextInt(n) メソッドを使いたかったのでしょう。

Dm: Math.max と Math.min の間違った組み合わせ (DM_INVALID_MIN_MAX)

このコードは Math.min(0, Math.max(100, value)) のような構文を使用して境界値を制限しようとしています。 しかしながら,定数の順序が間違っています。 Math.min(100, Math.max(0, value)) とすべきです。 結果としてこのコードは常に同じ結果 (もし値が NaN なら NaN) を作り出します。

Eq: equals メソッドはクラスオブジェクトではなくクラス名を比較している (EQ_COMPARING_CLASS_NAMES)

このメソッドは,クラス名を比較することによって,2つのオブジェクトが同じクラスなのか確かめています。 異なるクラスローダによってロードされたクラスなら,同じ名前で異なるクラスがある可能性があります。 クラスオブジェクトが同じなのか確かめてください。

Eq: equals メソッドは常に true を返す (EQ_ALWAYS_TRUE)

このクラスは,常に true を返す equals メソッドを定義しています。 これは想像力に富むが,あまり良い方法とはいえません。さらに, equals メソッドが対称的ではないことを意味します。

Eq: equals メソッドは常に false を返す (EQ_ALWAYS_FALSE)

このクラスでは,常に false を返す equlas メソッドを定義しています。 これはオブジェクトがそれ自身と等価ではないことを意味していて,このクラスの有用な MapSet を作成できません。 より根本的に, equals メソッドの要件の一つである反射性を満たしていないことになります。

おそらく意図されたことは,オブジェクトはそれ自身と等価であるというオブジェクト同一性です。 これは Object クラスから継承される振る舞いです。 異なるスーパークラスから継承される equals メソッドをオーバーライドする必要があるなら次のようなコードが使えます。

public boolean equals(Object o) {
    return this == o;
}

Eq: equals メソッドはスーパークラスの equals メソッドをオーバーライドしているが,対称的ではないかもしれない (EQ_OVERRIDING_EQUALS_NOT_SYMMETRIC)

このクラスはスーパークラスの equals メソッドをオーバーライドする equals メソッドを定義しています。 両方の equals メソッドは,2つのオブジェクトが等しいかどうかの判定で, instanceof を使用しています。 equals メソッドは対称的 (a.equals(b) == b.equals(a)) であることが重要なのでこれは危険を伴っています。 BA のサブタイプなら Aequals メソッドは引数が instanceof A なのかチェックします。 そして, Bequals メソッドは引数が instanceof B なのかチェックします。 これらのメソッドによって定義された同値関係が対称的ではないということです。

Eq: 列挙型は共変な equals メソッドを定義している (EQ_DONT_DEFINE_EQUALS_FOR_ENUM)

このクラスは列挙を定義していて,列挙の等価性はオブジェクト同一性を使用して定義されています。 列挙値のために共変な equals メソッドを定義することは,ひどいバッドプラクティスです。 2つの異なる列挙値が equals メソッドでは「等価ではない」と判定され,共変な equals メソッドでは「等価」と判定されるからです。 共変な equals メソッドを定義しないでください。

Eq: 共変な equals メソッドを定義して,Object.equals(Object) を継承している (EQ_SELF_USE_OBJECT)

このクラスは,共変な equals メソッドを定義していますが, equals(Object) メソッドは java.lang.Object クラスから継承しています。 クラスは, boolean equals(Object) メソッドを定義すべきです。

Eq: Object.equals(Object) をオーバーライドしていない equals メソッドの定義 (EQ_OTHER_USE_OBJECT)

このクラスは, equals メソッドを定義していますが, java.lang.Object クラスの equals(Object) メソッドをオーバーライドしていません。 クラスは, boolean equals(Object) メソッドを定義すべきです。

Eq: equals(Object) メソッドをオーバーライドしていない equals メソッドの定義 (EQ_OTHER_NO_OBJECT)

このクラスは, equals メソッドを定義していますが, java.lang.Object クラスの equals(Object) メソッドをオーバーライドしていません。 その代わりに,スーパークラスから equals(Object) メソッドを継承して, boolean equals(Object) メソッドを定義すべきです。

HE: ハッシュ化されたコンテキストでハッシュ化できないクラスの使用がシグネチャで宣言されている (HE_SIGNATURE_DECLARES_HASHING_OF_UNHASHABLE_CLASS)

メソッド,フィールド,クラスは,ハッシュ可能なクラスが必要なコンテキストで,ハッシュ化できないクラスが使用される総称的なシグネチャを宣言しています。 クラスは, equals メソッドを宣言していますが, hashCode メソッドは java.lang.Object から継承しています。 これは「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode メソッドの汎用規約に従っていないのでハッシュ化できません。

HE: ハッシュデータ構造で hashCode メソッドのないクラスを使用している (HE_USE_OF_UNHASHABLE_CLASS)

このクラスは, equals(Object) メソッドを定義していますが, hashCode メソッドを定義していません。 これは「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode メソッドの汎用規約に従っていません。 このクラスのインスタンスはハッシュデータ構造で使われています。最重要問題を修正する必要があります。

UR: コンストラクタで初期化されていないフィールドを読み出している (UR_UNINIT_READ)

このコンストラクタは,まだ値が代入されていないフィールドを読み出しています。 多くの場合,プログラマがコンストラクタのパラメータの代わりに誤ってフィールドを使うときに起きます。

UR: スーパークラスのコンストラクタから呼び出されるメソッドで初期化されていないフィールドを読み出している (UR_UNINIT_READ_CALLED_FROM_SUPER_CONSTRUCTOR)

このメソッドは,スーパークラスのコンストラクタで呼びされています。この時点では,クラスのフィールドはまだ初期化されていません。

これはたくさんの具象クラスを作るためです。次のクラスを検討してください。

abstract class A {
    int hashCode;
    abstract Object getValue();

    A() {
        hashCode = getValue().hashCode();
    }
}

class B extends A {
    Object value;

    B(Object v) {
        this.value = v;
    }

    Object getValue() {
        return value;
    }
}

B が構築されるとき, B のコンストラクタが value に値を設定する前に, A クラスのコンストラクタが呼び出されます。 したがって, A のコンストラクタが getValue を呼び出すとき, value の初期化されていない値が読み出されます。

Nm: 非常に紛らわしい名前のメソッド (NM_VERY_CONFUSING)

参照されたメソッドは,大文字と小文字だけが異なる名前があります。 大文字と小文字が同一ならメソッドの1つが他のメソッドをオーバーライドするので,非常に紛らわしいです。

Nm: パラメータの間違ったパッケージのためにスーパークラスのメソッドをオーバーライドしていないメソッド (NM_WRONG_PACKAGE)

パラメータの型がスーパークラスで対応するパラメータの型と正確に合致していないので,サブクラスのメソッドはスーパークラスの類似したメソッドをオーバーライドしていません。
たとえば次のようなコードです。

import alpha.Foo;

public class A {
    public int f(Foo x) { return 17; }
}
----
import beta.Foo;

public class B extends A {
    public int f(Foo x) { return 42; }
}

クラス B で定義された f(Foo) メソッドは,クラス Af(Foo) メソッドをオーバーライドしていません。 これは引数の型 Foo が違うパッケージだからです。

Nm: 明らかなメソッドとコンストラクタの混乱 (NM_METHOD_CONSTRUCTOR_CONFUSION)

この正規のメソッドは定義しているクラスと同じ名前です。 これはコンストラクタを意図していた可能性が高いです。もしそうなら void 戻り値の宣言を除去してください。
誤ってメソッドを定義したことが間違いだと気付き,適切なコンストラクタを定義したが,後方互換性のためにこのメソッドを除去できないならメソッドを非推奨にしてください。

Nm: クラスは hashcode() を定義しています。hashCode() にすべきですか? (NM_LCASE_HASHCODE)

このクラスは, hashcode() という名前のメソッドを定義しています。 このメソッドは, java.lang.ObjecthashCode メソッドを (おそらく意図的に) オーバーライドしていません。

Nm: クラスは tostring() を定義しています。toString() にすべきですか? (NM_LCASE_TOSTRING)

このクラスは, tostring() という名前のメソッドを定義しています。 このメソッドは, java.lang.ObjecttoString メソッドを (おそらく意図的に) オーバーライドしていません。

Nm: クラスは equal(Object) を定義しています。equals(Object) にすべきですか? (NM_BAD_EQUAL)

このクラスは, equal(Object) という名前のメソッドを定義しています。 このメソッドは, java.lang.Objectequals(Object) を (おそらく意図的に) オーバーライドしていません。

Se: readResolve メソッドが static メソッドとして宣言されている (SE_READ_RESOLVE_IS_STATIC)

readResolve メソッドが直列化機構で認識されるためには static メソッドとして宣言してはいけません。

Se: 直列化機構のために private にしなければならないメソッド (SE_METHOD_MUST_BE_PRIVATE)

このクラスは, Serializable インタフェースを実装して,カスタム直列化/直列化復元のためのメソッドを定義しています。 しかし,そのメソッドが private として宣言されていないので,直列化/直列化復元 API によって無視されます。

SF: switch 文のフォールスルーのために格納が無効になっている (SF_DEAD_STORE_DUE_TO_SWITCH_FALLTHROUGH)

前の case で格納された値が switch 文のフォールスルーのためにここで上書きされています。 前の case の終わりに break または return を入れるのを忘れた可能性があります。

SF: スローする switch 文のフォールスルーのために格納が無効になっている (SF_DEAD_STORE_DUE_TO_SWITCH_FALLTHROUGH_TO_THROW)

前の case で格納された値が例外がスローされる場所で, switch 文のフォールスルーのためにここで失われています。 前の case の終わりに break または return を入れるのを忘れた可能性があります。

NP: 書き込まれていないフィールドの読み出し (NP_UNWRITTEN_FIELD)

プログラムは,決して null ではない値を書き込むとは思われないフィールドの値を利用しています。 フィールドが解析によって見られないメカニズムを通して初期化されないかぎり,この値を利用すると NullPointerException が発生します。

UwF: null に設定されるだけのフィールド (UWF_NULL_FIELD)

このフィールドに定数値 null を書き込みます。したがって,フィールドの読み出しは null を返します。 誤りをチェックしてください。役に立たないなら除去してください。

UwF: 書き込まれていないフィールド (UWF_UNWRITTEN_FIELD)

このフィールドは決して書き込まれません。このフィールドからの読み出しはデフォルト値を返します。 誤りをチェックしてください (フィールドは初期化すべきでしたか?)。役に立たないなら除去してください。

SIC: 非 static 内部クラスとスレッドローカルのデッドロック (SIC_THREADLOCAL_DEADLY_EMBRACE)

このクラスは内部クラスですが,おそらく static 内部クラスにすべきです。 実際には内部クラスと外部クラスのスレッドローカルとの間にデッドロックの深刻な危険性があります。 内部クラスが static ではないので,外部クラスへの参照を保持します。 スレッドローカルに内部クラスのインスタンスの参照があるなら,内部と外部のインスタンスの両方が到達可能になり,ガベージされません。

RANGE: 配列インデックスは範囲外 (RANGE_ARRAY_INDEX)

配列操作が行なわれていますが,配列インデックスが範囲外なので実行時に ArrayIndexOutOfBoundsException が発生するでしょう。

RANGE: 配列オフセットは範囲外 (RANGE_ARRAY_OFFSET)

メソッドは,配列パラメータとオフセットパラメータで呼び出されていますが,オフセットは範囲外です。 実行時に IndexOutOfBoundsException が発生するでしょう。

RANGE: 配列の長さは範囲外 (RANGE_ARRAY_LENGTH)

メソッドは,配列パラメータと長さパラメータで呼び出されていますが,長さは範囲外です。 実行時に IndexOutOfBoundsException が発生するでしょう。

RANGE: 文字列インデックスは範囲外 (RANGE_STRING_INDEX)

文字列メソッドが呼び出されていますが,指定された文字列インデックスは範囲外です。 実行時に StringIndexOutOfBoundsException が発生するでしょう。

RV: 戻り値を無視しているメソッド (RV_RETURN_VALUE_IGNORED)

このメソッドの戻り値はチェックすべきです。 この警告の共通の原因は,オブジェクトが更新されると思って不変オブジェクトのメソッドを呼び出すことです。
たとえば次のようなコードです。

String dateString = getHeaderField(name);
dateString.trim();

プログラマは, trim メソッドが dateString によって参照される String オブジェクトが更新されると思っています。 しかし, String オブジェクトは不変で, trim メソッドが新しい String オブジェクトを返すのに無視しています。 このコードは次のように修正すべきです。

String dateString = getHeaderField(name);
dateString = dateString.trim();

RV: 作成した例外をスローするのではなく捨てている (RV_EXCEPTION_NOT_THROWN)

このコードは例外 (またはエラー) オブジェクトを作成していますが,何もしていません。
たとえば次のようなコードです。

if (x < 0) {
    new IllegalArgumentException("x must be nonnegative");
}

おそらくプログラマの意図は,作成した例外をスローすることでした。

if (x < 0) {
    throw new IllegalArgumentException("x must be nonnegative");
}

RV: compareTo によって返された特定の値のコードチェック (RV_CHECK_COMPARETO_FOR_SPECIFIC_RETURN_VALUE)

このコードは compareTo または compare メソッドを呼び出して,戻り値が特定の値(たとえば1または-1) なのか確かめています。 これらのメソッドを呼び出すときは特定のゼロ以外の値ではなく,結果の符号だけをチェックすべきです。 多数または大部分の compareTo と比較メソッドは-1,0または1を返しますが,いくつかは他の値を返します。

NP: null 値を利用している (NP_ALWAYS_NULL)

ここで null 値を利用しようとしています。 コードが実行されると NullPointerException が発生します。

NP: 常に null 値のオブジェクトで close メソッドを呼び出している (NP_CLOSING_NULL)

close メソッドは,常に null 値のオブジェクトで呼び出されています。 この文が実行されるなら NullPointerException が発生します。 ここでクローズすべき何かを決してクローズしないという大きな危険性があります。

NP: @Nonnull アノテーションが付けられたフィールドに null を格納している (NP_STORE_INTO_NONNULL_FIELD)

@Nonnull アノテーションが付けられたフィールドに null かもしれない値を格納しています。

NP: null 値を例外経路で利用している (NP_ALWAYS_NULL_EXCEPTION)

例外経路上のここで null 値を利用しています。コードが実行されると NullPointerException が発生します。 現在の SpotBugs は実行不可能な例外経路を刈り取れていないので,誤検出かもしれないことに注意してください。

switch 文の default が多くの場合実行不可能なので SpotBugs が例外経路である default を検討することに注意して下さい。

NP: null 値を利用している可能性がある (NP_NULL_ON_SOME_PATH)

そこで分岐または文が実行されるなら null 値が利用されて NullPointerException が発生します。 もちろん,問題は分岐または文が実行不可能で, NullPointerException が決して発生する可能性がないということかもしれません。 それを決めるのは SpotBugs の能力を超えています。

NP: null 値を例外経路で利用している可能性がある (NP_NULL_ON_SOME_PATH_EXCEPTION)

例外経路上のここで null 値が利用されています。コードが実行されると NullPointerException を引き起こすことがあります。 現在の SpotBugs は実行不可能な例外経路を刈り取れていないので,誤検出かもしれないことに注意してください。

switch 文の default が多くの場合実行不可能なので SpotBugs が例外経路である default を検討することに注意して下さい。

NP: メソッド呼び出しは非 null パラメータに null を渡している (NP_NULL_PARAM_DEREF)

このメソッド呼び出しは非 null メソッドパラメータに null 値を渡しています。 パラメータは,常に非 null とすべきパラメータとしてアノテーションが付けられていたか,解析が常に null 値を利用することを示していました。

NP: 非 null パラメータに null を渡している非仮想メソッドの呼び出し (NP_NULL_PARAM_DEREF_NONVIRTUAL)

null の可能性がある値が 非 null メソッドパラメータに渡されています。 パラメータは,常に非 null とすべきパラメータとしてアノテーションが付けられていたか,解析が常に null 値を利用することを示していました。

NP: メソッド呼び出しは非 null パラメータに null を渡している (NP_NULL_PARAM_DEREF_ALL_TARGETS_DANGEROUS)

すべての既知のターゲットメソッドが非 null であることをパラメータに要求する呼び出し場所で,おそらく null 値を渡しています。 パラメータは,常に非 null とすべきパラメータとしてアノテーションが付けられていたか,解析が常に null 値を利用することを示していました。

NP: メソッド呼び出しは非 null パラメータに null を渡している (NP_NONNULL_PARAM_VIOLATION)

このメソッドは,非 null でなければならないメソッドのパラメータとして null 値を渡しています。 このパラメータは,明示的に @Nonnull アノテーションが付けられていたか,解析が常に null 値を利用することを示していました。

NP: null を返すかもしれないメソッドが @Nonnull 宣言されている (NP_NONNULL_RETURN_VIOLATION)

このメソッドは, null 値を返すかもしれないのにメソッド (またはスーパークラスのメソッド) の戻り値に @Nonnull が宣言されています。

NP: null 値を利用することが保証されている (NP_GUARANTEED_DEREF)

文または分岐が実行されるなら,この時点で値は null であり, null 値を利用する ことが保証されています (実行時例外を含むフォワードパスを除く)。

なお, if (x == null) throw new NullPointerException();x の参照解除として扱われることに注意して下さい。

NP: null 値を例外経路で利用することが保証されている (NP_GUARANTEED_DEREF_ON_EXCEPTION_PATH)

例外経路上の文または分岐が実行されるなら,この時点で値は null であり, null 値を利用することが保証されています (実行時例外を含むフォワードパスを除く)。

DMI: 逆にされたメソッド引数 (DMI_ARGUMENTS_WRONG_ORDER)

このメソッド呼び出しへの引数は,順序が間違っているように見えます。 たとえば,呼び出し Preconditions.checkNotNull("message", message) は,引数を予約しました。チェックされる値は第一引数です。

RCN: 既に利用していた値の null チェック (RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE)

ここで値が null なのかチェックしていますが,既に値を利用していたので null である可能性はありません。 値が null なら以前の利用で NullPointerException が発生していたでしょう。 基本的に,値が null であることを許すのかどうかに関係なく,このコードと以前の値の利用は一致しません。 チェックは冗長か,または以前の値の利用は誤りです。

RC: 疑わしい参照比較 (RC_REF_COMPARISON)

このメソッドは, == または != 演算子を使用して2つの参照値を比較しています。 一般的にこの型のインスタンスを比較する正しい方法は equals メソッドです。 等価で識別可能なインスタンスを作成する可能性がありますが異なるオブジェクトなので == で比較しないでください。 一般的に参照によって比較されるべきではないクラスの例は, java.lang.Integerjava.lang.Float などです。

VA: 可変長引数を期待しているメソッドにプリミティブ型の配列を渡している (VA_PRIMITIVE_ARRAY_PASSED_TO_OBJECT_VARARG)

このコードは可変長引数をとるメソッドにプリミティブ型の配列を渡しています。 これはプリミティブ型の配列を保持するために長さが1の配列を作成してメソッドに渡します。

EC: 参照等価性を使用して異なる型を比較している (EC_UNRELATED_TYPES_USING_POINTER_EQUALITY)

このメソッドは異なる型と思われる2つの参照を比較するために参照等価性を使用しています。 この比較の結果は,常に false です。

EC: equals メソッドを呼び出して異なる型を比較している (EC_UNRELATED_TYPES)

このメソッドは,異なるクラス型の2つの参照で equals(Object) メソッドを呼び出していて,解析が実行時に異なるクラスのオブジェクトになることを示唆しています。 さらに,呼び出されるであろう equals メソッドの検査では,この呼び出しは常に false を返します。 あるいは, equals メソッドが対称 (Object クラスの equals のための契約に必要な性質) ではないことのどちらかを示唆しています。

EC: equals メソッドを使用して配列と非配列を比較している (EC_ARRAY_AND_NONARRAY)

このメソッドは,配列と配列だと思われない参照を比較するために .equals(Object o) を呼び出しています。 比較されているものが違う型なら等しくないことであることが保証されているので,比較はほぼ間違いなく誤りです。 たとえそれらが両方とも配列だったとしても,配列の equals メソッドは2つの配列が同じオブジェクトだと決定するだけです。 配列の内容を比較するためには java.util.Arrays.equals(Object[], Object[]) を使用してください。

EC: equals(null) の呼び出し (EC_NULL_ARG)

このメソッドは, null 値の引数を渡して equals(Object) を呼び出しています。 equals メソッドの規約によると,この呼び出しは常に false を返すはずです。

EC: equals メソッドを呼び出して異なる型のインタフェースを比較している (EC_UNRELATED_INTERFACES)

このメソッドは,どちらも他方のサブタイプではない無関係なインタフェース型の2つの参照で equals(Object) メソッドを呼び出しています。 そして,両方のインタフェースを実装する既知の非抽象クラスがありません。 したがって比較されている2つのオブジェクトは実行時に同じクラスのメンバである可能性が低いです (いくつかのアプリケーションクラスが解析できなかったか,動的クラスローディングが実行時に起こることができた場合を除く)。 equals メソッドの規約によると,異なるクラスのオブジェクトは常に等しくないとして比較すべきです。 したがって, java.lang.Object.equals(Object) によって定義される規約によれば,この比較の結果は実行時に常に false になります。

EC: equals メソッドを呼び出して無関係のクラスとインタフェースを比較している (EC_UNRELATED_CLASS_AND_INTERFACE)

このメソッドは,一方がクラスで他方がインタフェースである2つの参照で equals(Object) メソッドを呼び出しています。 クラスは,そのクラスの非抽象サブクラスも含めてインタフェースを実装していません。 したがって比較されている2つのオブジェクトは実行時に同じクラスのメンバである可能性が低いです (いくつかのアプリケーションクラスが解析できなかったか,動的クラスローディングが実行時に起こることができた場合を除く)。 equals メソッドの規約によると,異なるクラスのオブジェクトは常に等しくないとして比較すべきです。 したがって, java.lang.Object.equals(Object) によって定義される規約によれば,この比較の結果は実行時に常に false になります。

SA: フィールドへの代入ではなくローカル変数への自己代入 (SA_LOCAL_SELF_ASSIGNMENT_INSTEAD_OF_FIELD)

このメソッドにはローカル変数の自己代入があり,ローカル変数とフィールドが同じ名前です。
たとえば次のようなコードです。

    int foo;
    public void setFoo(int foo) {
        foo = foo;
    }

そのような代入は役に立ちません。そうではなく,フィールドに代入するつもりでしたか?

INT: int 値と long 定数との間違った比較 (INT_BAD_COMPARISON_WITH_INT_VALUE)

このコードはint 値と int 値として表される値の範囲外の long 定数を比較しています。 この比較は無意味で,おそらく間違っています。

INT: 符号付きバイトの間違った比較 (INT_BAD_COMPARISON_WITH_SIGNED_BYTE)

符号付バイトのとりうる値の範囲は-128~127です。その範囲外で符号付バイトを値と比較することは無意味で間違っていそうです。 符号付きバイト b を範囲が0~255の符号なしバイトに変換するには 0xff & b を使用してください。

INT: 負ではない値と負の定数またはゼロとの間違った比較 (INT_BAD_COMPARISON_WITH_NONNEGATIVE_VALUE)

このコードは負ではないことが保証されている値と負の定数またはゼロとを比較しています。

BIT: 符号付きバイト値のビット加算 (BIT_ADD_OF_SIGNED_BYTE)

バイト値と明らかに下位8ビットがあるとわかっている値を加算しています。 ビット演算を実行する前にバイト配列からロードされた値は32ビットまで符号拡張されます。 したがって, b[0] の値が 0xff で, x の初期値が 0 だとすると, ((x << 8) + b[0]) は, 0xff が符号拡張で 0xffffffff になるので,結果として 0xffffffff が得られます。

特に,バイト配列を int にパックする次のようなコードはひどく間違っています。

int result = 0;
for(int i = 0; i < 4; i++)
    result = ((result << 8) + b[i]);

その代わりに次のようなイディオムは動作します。

int result = 0;
for(int i = 0; i < 4; i++)
    result = ((result << 8) + (b[i] & 0xff));

BIT: 符号付きバイト値のビット論理和 (BIT_IOR_OF_SIGNED_BYTE)

ロードしたバイト値 (たとえば,バイト配列からロードされた値や戻り値がバイト型のメソッドから返された値) とビット論理和を実行しています。 ビット演算を実行する前にバイト値は32ビットまで符号拡張されます。 したがって, b[0] の値が 0xff で, x の初期値が 0 だとすると, ((x << 8) | b[0]) は, 0xff が符号拡張で 0xffffffff になるので,結果として 0xffffffff が得られます。

特に,バイト配列を int にパックする次のようなコードはひどく間違っています。

int result = 0;
for(int i = 0; i < 4; i++) {
    result = ((result << 8) | b[i]);
}

その代わりに次のようなイディオムは動作します。

int result = 0;
for(int i = 0; i < 4; i++) {
    result = ((result << 8) | (b[i] & 0xff));
}

BIT: 負数を含むビット演算の符号をチェックする (BIT_SIGNED_CHECK_HIGH_BIT)

このメソッドは, CONSTANT が負数のときに ((val & CONSTANT) > 0) のようなビット演算式で比較しています。 ビット演算をより大きい演算子で比較することは,予想外の結果の原因になる可能性があります。比較は期待したようになりません。 > 0 の代わりに != 0 を使用することが良いプラクティスです。

BIT: 互換性のないビットマスク (BIT_AND)

このメソッドは, (e & C) 形式の式を D と比較しています。 定数 C の特定の値と D ために常に等しくないことを比較します。論理エラーかタイプミスかもしれません。

BIT: ((...) & 0) == 0 なのか確かめている (BIT_AND_ZZ)

このメソッドは, (e & 0) 形式の式を0と比較しています。それは,常に等価であることを比較します。論理エラーかタイプミスかもしれません。

BIT: 互換性のないビットマスク (BIT_IOR)

このメソッドは, (e | C) 形式の式を D と比較しています。 定数 CD の特定の値のために常に等しくないことを比較します。論理エラーかタイプミスかもしれません。

通常,このバグは,ビットセットで帰属関係のテストを実行したいコードで発生します。 しかし,ビット論理積演算子 (&) の代わりにビット論理和演算子 (|) を使用しています。

こうしたバグは (e & (A | B)) == C が意図されている間に ((e & A) | B) == C のように解析される (e & A | B) == C のような式で現れるかもしれません。

SA: フィールドの自己代入 (SA_FIELD_SELF_ASSIGNMENT)

このメソッドにはフィールドの自己代入があります。
たとえば次のようなコードです。

int x;
public void foo() {
    x = x;
}

そのような代入は役に立たないので,論理エラーかタイプミスかもしれません。

SA: フィールドの無意味な自己演算 (たとえば,x & x) (SA_FIELD_SELF_COMPUTATION)

このメソッドは,フィールドと同じフィールドへの別の参照との無意味な計算を実行しています (たとえば, x & x または x - x)。 この計算の性質のため,演算は意味をなすとは思われないので,論理エラーかタイプミスかもしれません。 計算をチェックしてください。

SA: 変数の無意味な自己演算 (たとえば,x & x) (SA_LOCAL_SELF_COMPUTATION)

このメソッドは,ローカル変数と同じ変数への別の参照との無意味な計算を実行しています (たとえば, x & x または x - x)。 この計算の性質のため,演算は意味をなすとは思われないので,論理エラーかタイプミスかもしれません。 計算をダブルチェックしてください。

SA: フィールドとそれ自身との自己比較 (SA_FIELD_SELF_COMPARISON)

このメソッドは,フィールドをそれ自身と比較しています。論理エラーかタイプミスかもしれません。 正しいものを比較していることを確認してください。

SA: ローカル変数とそれ自身との自己比較 (SA_LOCAL_SELF_COMPARISON)

このメソッドは,ローカル変数をそれ自身と比較しています。論理エラーかタイプミスかもしれません。 正しいものを比較していることを確認してください。

UMAC: 呼び出し不可能なメソッドが無名クラスで定義されている (UMAC_UNCALLABLE_METHOD_OF_ANONYMOUS_CLASS)

この無名クラスは,直接呼び出されないスーパークラスのメソッドをオーバーライドしていないメソッドを定義しています。 他のクラスのメソッドが無名クラスで宣言されたメソッドを直接呼び出せないので,このメソッドは呼び出し不可能だと思われます。 メソッドは単にデッドコードであるかもしれません。しかし,メソッドがスーパークラスで宣言されるメソッドをオーバーライドすることを意図した可能性もあります。 そして,タイプミスまたは他の誤りのためにメソッドは,実際には意図しているメソッドをオーバーライドしません。

IJU: run メソッドでの JUnit アサーションは JUnit によって通知されない (IJU_ASSERT_METHOD_INVOKED_FROM_RUN_METHOD)

run メソッドで JUnit アサーションが実行されています。失敗した JUnit アサーションは例外をスローします。 したがって,この例外がテストメソッドを実行したスレッド以外のスレッドで発生するなら,例外はスレッドを終了させますが,テストの失敗になりません。

IJU: TestCase は suite メソッドの間違った宣言をしている (IJU_BAD_SUITE_METHOD)

JUnit の TestCase クラスで, suite メソッドを実装しています。 しかしながら, suite メソッドは,

public static junit.framework.Test suite()

public static junit.framework.TestSuite suite()

のどちらかを宣言する必要があります。

IJU: TestCase は super.setup() を呼び出さない setUp メソッドを実装している (IJU_SETUP_NO_SUPER)

JUnit の TestCase クラスで, setUp メソッドを実装しています。 setUp メソッドは, super.setUp() を呼び出すべきなのにそうしていません。

IJU: TestCase は super.tearDown() を呼び出さない tearDown メソッドを実装している (IJU_TEARDOWN_NO_SUPER)

JUnit の TestCase クラスで, tearDown メソッドを実装しています。 tearDown メソッドは, super.tearDown() を呼び出すべきなのにそうしていません。

IJU: TestCase は 非 static な suite メソッドを実装している (IJU_SUITE_NOT_STATIC)

JUnit の TestCase クラスで, suite メソッドを実装しています。 suite メソッドは static として宣言すべきなのにそうしていません。

IJU: TestCase はテストがない (IJU_NO_TESTS)

JUnit の TestCase クラスで,どんなテストメソッドも実装していません。

BOA: スーパークラスの Adapter で実装されるメソッドを誤ってオーバーライドしているクラス (BOA_BADLY_OVERRIDDEN_ADAPTER)

このメソッドは,スーパークラスで実装されているメソッドをオーバーライドしています。 スーパークラスは,java.awt.event や javax.swing.event パッケージで定義されているリスナを実装する Adapter です。 その結果,イベントが発生するときこのメソッドは呼び出されません。

SQL: インデックスが0で ResultSet にアクセスしようとしているメソッド (SQL_BAD_RESULTSET_ACCESS)

インデックスが0で, ResultSetgetXXXupdateXXX メソッドを呼び出しています。 ResultSet のインデックスは1から開始するので,これは常に間違いです。

SQL: インデックスが0で PreparedStatement にアクセスしようとしているメソッド (SQL_BAD_PREPARED_STATEMENT_ACCESS)

インデックスが0で, PreparedStatementsetXXX メソッドを呼び出しています。 インデックスは1から開始するので,これは常に間違いです。

SIO: instanceof 演算子を使用した不必要な型チェック (SIO_SUPERFLUOUS_INSTANCEOF)

オブジェクトが要求する型であるかどうかにかかわらず,静的に判定される instanceof 演算子を使用して型チェックをしています。

BAC: 初期化されていない AppletStub に依存する間違ったアプレットコンストラクタ (BAC_BAD_APPLET_CONSTRUCTOR)

このコンストラクタは, AppletStub に依存する親アプレットでメソッドを呼び出しています。 このアプレットの init メソッドが呼び出されるまで AppletStub は初期化されないので,これらのメソッドは正しく機能しません。

EC: equals(...) メソッドを使用して互換性のない配列を比較している (EC_INCOMPATIBLE_ARRAY_COMPARE)

このメソッドは,互換性のない型の配列を比較するために .equals(Object o) を呼び出しています (たとえば, String[]StringBuffer[]String[]int[]) 。 それらは,決して等価ではありません。 さらに, equals(...) を使用してが配列を比較すると,同じ配列なのか確かめるだけで,配列の内容は無視されます。

EC: 配列の equals メソッド呼び出しは == と等価である (EC_BAD_ARRAY_COMPARE)

このメソッドは,配列で .equals(Object o) を呼び出しています。 配列は, Objectequals メソッドをオーバーライドしないので,配列で equals メソッドを呼び出すことはアドレスを比較することと同じです。 配列の内容を比較するためには java.util.Arrays.equals(Object[], Object[]) を使用してください。 配列のアドレスを比較するために明示的に == を使用して参照等価性をチェックすることは,それほど紛らわしくないでしょう。

STI: interrupted メソッドを呼び出すために不要な currentThread メソッドを呼び出している (STI_INTERRUPTED_ON_CURRENTTHREAD)

このメソッドは, interrupted メソッドを呼び出すために Thread.currentThread() を呼び出しています。 interrupted メソッドは static メソッドなので, Thread.interrupted() を使用するほうが単純明解です。

STI: スレッドインスタンスで static Thread.interrupted() を呼び出している (STI_INTERRUPTED_ON_UNKNOWNTHREAD)

このメソッドは,カレントスレッドではない Thread オブジェクトであるように見える Thread オブジェクトで Thread.interrupted() を呼び出しています。 interrupted メソッドは static なので,作成者が意図したこととは異なるオブジェクトで呼び出されます。

DLS: return 文に無駄なインクリメントがある (DLS_DEAD_LOCAL_INCREMENT_IN_RETURN)

return x++; のような return 文があります。 接頭辞インクリメント/デクリメントは 式の値に影響を与えないので,インクリメント/デクリメントは効果がありません。 この文が正しいことを確かめてください。

DLS: クラスリテラルの無効な代入 (DLS_DEAD_STORE_OF_CLASS_LITERAL)

この命令は変数にクラスリテラルを代入していますが,決して使われません。
The behavior of this differs in Java 1.4 and in Java 5
J2SE 1.4 およびそれ以前のバージョンでは, Foo.class への参照は Foo のためのスタティックイニシャライザが既に実行されていないなら実行することを強制します。 J2SE 5.0 ではそうしません。

より多くの詳細と例と J2SE 5.0 のクラスの強制的な初期化の方法の提案は Sun の article on Java SE compatibility を参照してください。

IP: メソッドで読み取られずに上書きされているパラメータ (IP_PARAMETER_IS_DEAD_BUT_OVERWRITTEN)

このパラメータの初期値は無視され,ここで上書きされています。 これは多くの場合,パラメータへの書き込みが呼び出し元に戻されるという誤った考えを示しています。

MF: フィールドを隠す変数を定義しているメソッド (MF_METHOD_MASKS_FIELD)

このメソッドは,このクラスまたはスーパークラスのフィールドと同じ名前でローカル変数を定義しています。 フィールドから初期化されていない値を読み出す,初期化されていないフィールドをそのままにしておくか,または両方を引き起こすかもしれません。

MF: スーパークラスのフィールドを隠すフィールドを定義しているクラス (MF_CLASS_MASKS_FIELD)

このクラスは,スーパークラスの可視インスタンスフィールドと同じ名前でフィールドを定義しています。 これは紛らわしくて,メソッドがフィールドを更新するかアクセスするなら,間違いを指摘するかもしれません。

FE: NaN への等価性のための絶望的なテスト (FE_TEST_IF_EQUAL_TO_NOT_A_NUMBER)

このコードは浮動小数点が特別な非数値と等価であるか確かめています (たとえば if (x == Double.NaN))。 しかしながら, NaN の特別な意味のため,値は NaN と等価ではありません。 したがって, x == Double.NaN は常に false と評価します。 x という値が特別な非数値であるかどうか確かめるためには Double.isNaN(x) を使用します (または x が浮動小数点精度であるなら Float.isNaN(x))。

ICAST: int 値を long に変換して絶対時間として使用している (ICAST_INT_2_LONG_AS_INSTANT)

このコードは32ビット int 値を64ビット long 値に変換して,絶対時間値を必要とするメソッドパラメータに渡しています。 絶対時間値は,「エポック」(すなわち,1970年1月1日,00:00:00 GMT)としてわかっている標準的な基準時間からのミリ秒数です。
たとえば,エポックからの秒を Date へ変換することを意図した次のメソッド はひどく壊れています。

Date getDate(int seconds) { return new Date(seconds * 1000); }

乗算は32ビット演算を使用して,64ビット値に変換されます。 32ビット値は,64ビットに変換されて,絶対時間値を表すために使用されるとき,1969年12月と1970年1月の日付しか表せません。

上記のメソッドの正しい実装は次のとおりです。

// 失敗,2037年後の日付
Date getDate(int seconds) { return new Date(seconds * 1000L); }

// より良い,すべての日付で動作する
Date getDate(long seconds) { return new Date(seconds * 1000); }

ICAST: 整数値を double にキャストして Math.ceil() に渡している (ICAST_INT_CAST_TO_DOUBLE_PASSED_TO_CEIL)

このコードは整数値 (たとえば, intlong) を倍精度浮動小数点に変換してから,その結果を Math.ceil() に渡しています。 整数を double に変換すると小数部がない数値が得られるので,この演算は常にノーオペレーションになります。 Math.ceil()に渡される値を生成した演算が倍精度浮動小数点演算を使用して実行することを意図した可能性が高いです。

ICAST: 整数値を float にキャストして Math.round() に渡している (ICAST_INT_CAST_TO_FLOAT_PASSED_TO_ROUND)

このコードは整数値を float 精度浮動小数点に変換してから,その結果を Math.round() に渡して引数に最も近い int/long を返します。 整数を float に変換すると小数部がない数値が得られるので,この演算は常にノーオペレーションになります。 Math.round()に渡される値を生成した演算が浮動小数点演算を使用して実行することを意図した可能性が高いです。

NP: null とわかっている値をその型のインスタンスなのか確かめている (NP_NULL_INSTANCEOF)

チェックされている値が null であることが保証されているので, instanceof は常に false を返します。 これは安全で,誤解や論理エラーを指摘していないことを確認してください。

DMI: int に対して Double.longBitsToDouble() を呼び出している (DMI_LONG_BITS_TO_DOUBLE_INVOKED_ON_INT)

Double.longBitsToDouble() の呼び出しで,32ビット int 値が引数として渡されています。 これはほぼ間違いなく意図したことではなく,意図した結果を出す可能性は低いです。

BC: 不可能なキャスト (BC_IMPOSSIBLE_CAST)

このキャストは,常に ClassCastException をスローします。 SpotBugs は, instanceof チェックから型情報を調査して,メソッドからの戻り値とフィールドからロードされた値の型について,より多くの正確な情報を使用します。 したがって,宣言された変数の型にはより多くの正確な情報があるかもしれないしれません。 また,キャストが常に実行時例外をスローするのかを決定するために利用する可能性があります。

BC: 不可能なダウンキャスト (BC_IMPOSSIBLE_DOWNCAST)

このキャストは,常に ClassCastException をスローします。 解析は,キャストしている値の正確な型がわかっていると信じていて,サブタイプへダウンキャストしようとする試みは, ClassCastException のスローによって常に失敗します。

BC: toArray メソッドの結果の不可能なダウンキャスト (BC_IMPOSSIBLE_DOWNCAST_OF_TOARRAY)

このコードは toArray メソッドの呼び出し結果を Object[] ではなく具体的な型のコレクションでキャストしています。

String[] getAsArray(Collection<String> c) {
    return (String[]) c.toArray();
}

これは通常 ClassCastException をスローして失敗します。 ほとんどすべてのコレクションの toArray メソッドは, Object[] を返します。 Collection オブジェクトは宣言された総称型コレクションの参照がないので,本当に何もできません。 コレクションから特定の型の配列を得る正しい方法は, c.toArray(new String[]); または c.toArray(new String[c.size()]); (後者はわずかにより効率的です) を使用することです。 これに対する1つの共通の知られている例外があります。 Arrays.asList(...)によって返されるリストの toArray() メソッドは共変型配列を返します。 たとえば, Arrays.asArray(new String[] { "a" }).toArray()String [] を返します。 SpotBugs はそのようなケースを検出して抑止しようとしますが,見落としているかもしれません。

BC: 常に false を返す instanceof (BC_IMPOSSIBLE_INSTANCEOF)

この instanceof は常に false を返します。これは安全で,誤解や論理エラーを指摘していないことを確認してください。

RE: 正規表現のために使われている "." または "|" (RE_POSSIBLE_UNINTENDED_PATTERN)

String 機能が呼び出されていて, . または | が引数として正規表現を取るパラメータに渡されています。 これは意図したことですか? たとえば

  • s.replaceAll(".", "/") は,すべての文字が '/' 文字に置換された String を返す
  • s.split(".") は,常に長さが0の String 配列を返す
  • "ab|cd".replaceAll("|", "/") は,"/a/b/|/c/d/" を返す
  • "ab|cd".split("|") は,6個の要素がある配列を返す: [, a, b, |, c, d]

RE: 正規表現のための無効な構文 (RE_BAD_SYNTAX_FOR_REGULAR_EXPRESSION)

このコードは正規表現の構文によると無効である正規表現を使用しています。 この文が実行されるとき PatternSyntaxException をスローします。

RE: 正規表現のために使われている File.separator (RE_CANT_USE_FILE_SEPARATOR_AS_REGULAR_EXPRESSION)

このコードは正規表現が必要な場所で, File.separator を使用しています。 これは File.separator がバックスラッシュである Windows プラットフォームでは失敗します。 バックスラッシュは正規表現ではエスケープ文字として解釈されます。 その他の選択肢としては, File.separator の代わりに File.separatorChar=='\\' ? "\\\\" : File.separator を使用できます。

DLS: 上書きされたインクリメント (DLS_OVERWRITTEN_INCREMENT)

このコードはインクリメント演算 (たとえば, i++) を実行してすぐに上書きしています。 たとえば, i = i++ は元の値をインクリメントした値で上書きします。

BSHIFT: 32ビット int の-31から31の範囲を超えた量によるシフト (ICAST_BAD_SHIFT_AMOUNT)

このコードは32ビット int の-31から31の範囲を超えた量でシフトを実行しています。 これの効果は,どのくらいシフトするのかを決めるために整数値の下位5ビット (32で割った余り) を使用することです (たとえば,40ビットでシフトすることは8ビットでシフトすることと同じで,32ビットでシフトすることは0ビットでシフトすることと同じです)。 これはおそらく期待されたことではなく,少なくとも紛らわしいです。

BSHIFT: シフト演算の正しくない構文解析の可能性がある (BSHIFT_WRONG_ADD_PRIORITY)

コードは (x << 8 + y) のような演算を行います。 これは正しいかもしれませんが,おそらく (x << 8) + y を行うことを意図していました。 しかし,シフト演算は優先順位が低いので,実際には x << (8 + y) として構文解析されます。

IM: 整数剰余の結果の整数乗算 (IM_MULTIPLYING_RESULT_OF_IREM)

このコードは整数剰余の結果に整数定数を乗算しています。 紛らわしい演算子の優先順位がないことを確実にしてください。 たとえば, i % 60 * 1000 は, i % (60 * 1000) ではなく (i % 60) * 1000 となります。

DMI: 配列で hashCode メソッドを呼び出している (DMI_INVOKING_HASHCODE_ON_ARRAY)

このコードは配列で hashCode メソッドを呼び出しています。 配列で hashCode メソッドを呼び出すことは, System.identityHashCode と同じ値を返すので,内容と配列の長さを無視します。 配列 a の内容によるハッシュコードを必要とするなら, java.util.Arrays.hashCode(a) を使用してください。

USELESS_STRING: 配列で toString メソッドを呼び出している (DMI_INVOKING_TOSTRING_ON_ARRAY)

このコードは配列で toString メソッドを呼び出しています。「[C@16f0472」のようなかなり役に立たない結果を生成します。 Arrays.toString() を使用して,配列の内容を読み取り可能な文字列に変換することを検討してください。
『Programming Puzzlers』の第3章,パズル12を参照してください。

USELESS_STRING: 名前のない配列で toString メソッドを呼び出している (DMI_INVOKING_TOSTRING_ON_ANONYMOUS_ARRAY)

このコードは無名の配列で toString メソッドを呼び出しています。「[C@16f0472」のようなかなり役に立たない結果を生成します。 Arrays.toString() を使用して,配列の内容を読み取り可能な文字列に変換することを検討してください。
『Programming Puzzlers』の第3章,パズル12を参照してください。

DMI: 月のための間違った定数値 (DMI_BAD_MONTH)

このコードはメソッドに0から11の範囲外の月定数値を渡しています。

DMI: hasNext メソッドで next メソッドを呼び出している (DMI_CALLING_NEXT_FROM_HASNEXT)

hasNext メソッドは, next メソッドを呼び出しています。 hasNext メソッドは,イテレータの状態を変更することになっていないので,ほぼ確実に間違っています。 next メソッドがイテレータの状態を変更することになっています。

QBA: 論理式で boolean リテラル値を代入しているメソッド (QBA_QUESTIONABLE_BOOLEAN_ASSIGNMENT)

このメソッドは, if または while の式の中の boolean 変数に boolean リテラル値 (true または false) を代入しています。 おそらく,これは = による代入ではなく, == を使用して論理比較をすることになっていました。

GC: 型パラメータとメソッド引数に関係がない (GC_UNRELATED_TYPES)

総称型コレクションメソッドへの呼び出しにコレクションのパラメータとは互換性のないクラスの引数があります (すなわち,引数の型は総称型引数に対応するスーパタイプでもサブタイプでもありません)。 したがって,コレクションにはここで使用されたメソッド引数と等価であるどんなオブジェクトも含まれていません。 多分間違った値がメソッドに渡されています。 一般的に2つの無関係なクラスのインスタンスは等価ではありません。 たとえば, FooBar クラスがサブタイプによって関係がないなら, Foo のインスタンスは Bar のインスタンスと等価のはずがありません。 その他の問題で対称的ではない equals メソッドになる可能性が高いです。 たとえば, FooString と等価であるように Foo クラスを定義するなら, StringString だけと等価であるので, equals メソッドは対称的ではありません。

まれに,非対称 equals メソッドを定義して,まだ,何とかそれらのコードを機能させています。 APIのどれも文書化していないか,保証もしていないが, Collection<String>Foo があるかどうか調べたいなら, 引数の equals メソッド (たとえば, Fooクラスの equals メソッド) を使用して等価性をチェックします。

DMI: コレクションへの無意味な呼び出し (DMI_VACUOUS_SELF_COLLECTION_CALL)

この呼び出しは意味がありません。 どんなコレクション cc.containsAll(c) を呼び出すことは常に true であるべきです。 そして, c.retainAll(c) は効果があるはずがありません。

DMI: D'oh! 無意味なメソッド呼び出し (DMI_DOH)

この部分的なメソッド呼び出しは,検査から明らかな理由で意味がありません。

DMI: コレクションは自分自身を含めるべきではない (DMI_COLLECTIONS_SHOULD_NOT_CONTAIN_THEMSELVES)

この総称型コレクションメソッドへの呼び出しはコレクションに自分自身が含まれている場合 (たとえば, s.contains(s)true) にだけ意味があります。 これが本当だとは思えないし,もし本当なら問題の原因になります (たとえば,無限再帰になっているハッシュコードの計算)。 間違ったパラメータが渡されている可能性が高いです。

TQ: 型修飾子がない値が修飾子を必要とする場所で使われている (TQ_UNKNOWN_VALUE_USED_WHERE_ALWAYS_STRICTLY_REQUIRED)

値が型修飾子アノテーションを必要とする方法で使われています。型修飾子は厳密なので,ツールは適切なアノテーションを指定していない値を拒絶します。

厳密なアノテーションを持つように値を矯正するには,戻り値に厳密なアノテーションを付ける識別関数を定義してください。 これはアノテーションが付けられていない値を厳密な型修飾子アノテーションを持つ値に変える唯一の方法です。

TQ: 互換性のない型修飾子による比較値 (TQ_COMPARING_VALUES_WITH_INCOMPATIBLE_TYPE_QUALIFIERS)

型修飾子アノテーションを指定した値がその修飾子のない値と比較しています。

より正確に, when=ALWAYS を指定した型修飾子アノテーションが付けられた値が同じ型修飾子で when=NEVER を指定する値と比較しています。

たとえば, @NonNegative は型修飾子アノテーション @Negative(when=When.NEVER) の略称とします。 次のコードは return 文が @NonNegative 値を要求するが, @Negative としてマークされている値を受け取るのでこの警告を生成します。

public boolean example(@Negative Integer value1, @NonNegative Integer value2) {
    return value1.equals(value2);
}

TQ: 型修飾子アノテーションが付けられた値がその修飾子を付けてはならない値を必要とする場所で使われている (TQ_ALWAYS_VALUE_USED_WHERE_NEVER_REQUIRED)

型修飾子アノテーションが付けられた値がその修飾子を付けてはならない値を必要とする場所で使われています。

より正確に, when=ALWAYS を指定した型修飾子アノテーションが付けられた値が到達することが保証されているか同じ型修飾子で when=NEVER を指定する場所で使用しています。

たとえば, @NonNegative は型修飾子アノテーション @Negative(when=When.NEVER) の略称とします。 次のコードは return 文が @NonNegative 値を要求するが @Negative としてマークされている値を受け取るのでこの警告を生成します。

public @NonNegative Integer example(@Negative Integer value) {
    return value;
}

TQ: 型修飾子アノテーションが付けられていない値がその修飾子が付けられた値を必要とする場所で使われている (TQ_NEVER_VALUE_USED_WHERE_ALWAYS_REQUIRED)

型修飾子アノテーションが付けられていない値がその修飾子が付けられた値を必要とする場所で使われています。

より正確に, when=NEVER を指定した型修飾子アノテーションが付けられた値が同じ型修飾子で when=ALWAYS を指定する場所で使用されています。

TQ: 型修飾子を付けていないかもしれない値がその型修飾子を必要とする方法で常に使われている (TQ_MAYBE_SOURCE_VALUE_REACHES_ALWAYS_SINK)

型修飾子によって示された値のインスタンスではない可能性としてアノテーションが付けられた値です。 値は,その型修飾子によって示された値を必要とする方法で使われることが保証されています。

TQ: 型修飾子を付けているかもしれない値がその型修飾子を禁止する方法で常に使われている (TQ_MAYBE_SOURCE_VALUE_REACHES_NEVER_SINK)

型修飾子によって示された値のインスタンスである可能性としてアノテーションが付けられた値です。 値は,その型修飾子によって示された値を禁止する方法で使われることが保証されています。

FB: SpotBugs からの予期しない/望ましくない警告 (FB_UNEXPECTED_WARNING)

SpotBugs は, @NoWarning アノテーションが付けられたことにより予期しない/望ましくない警告を生成しました。

FB: 失われた SpotBugs からの予期した/望ましい警告 (FB_MISSING_EXPECTED_WARNING)

SpotBugs は, @ExpectedWarning アノテーションが付けられたことにより予期した/望ましい警告が生成されませんでした。

実験用 (EXPERIMENTAL)

実験用で完全に精査されていないバグパターンです。

SKIPPED: 解析するにはあまりにも大きいクラス (SKIPPED_CLASS_TOO_BIG)

このクラスは効率的に処理できないほど大きいです。また,エラーのために完全に解析されませんでした。

TEST: 未知のバグパターン (UNKNOWN)

警告が記録されたのに SpotBugs はこのバグパターンの説明を見つけることができなかったので警告について説明できません。 これは SpotBugs かその設定のバグの場合だけで発生させるべきです。 または解析プラグインを使用して生成されるなら,プラグインは現在ロードされていません。

TEST: テスト (TESTING)

このバグパターンは,新しい不完全に実装されたバグディテクタによって生成されるだけです。

TEST: テスト1 (TESTING1)

このバグパターンは,新しい不完全に実装されたバグディテクタによって生成されるだけです。

TEST: テスト2 (TESTING2)

このバグパターンは,新しい不完全に実装されたバグディテクタによって生成されるだけです。

TEST: テスト3 (TESTING3)

このバグパターンは,新しい不完全に実装されたバグディテクタによって生成されるだけです。

OBL: ストリームやリソースのクリーンアップに失敗するかもしれないメソッド (OBL_UNSATISFIED_OBLIGATION)

このメソッドは,ストリーム,データベースオブジェクト,またはクリーンアップ操作を明示的に必要としている他のリソースのクリーンアップ (クローズする,片付ける) に失敗するかもしれません。

一般的にメソッドがストリープや他のリソースを開いたなら,メソッドはストリームやリソースがメソッドが戻る前にクリーンアップされることを確認するために try-finally ブロックを使用すべきです。

このバグパターンは,OS_OPEN_STREAM と ODR_OPEN_DATABASE_RESOURCE と基本的に同じですが異なる (そして,うまくいけばより良い) 静的解析技術に基づいています。 私たちは,このバグパターンの有効性についてのフィードバックを得ることに関心があります。 どちらかの方法でフィードバックを送ってください。

特に,このバグパターンの誤検出抑制探索法は詳細にわたって調整されていないので,誤検出についてのレポートは我々の助けになります。

解析技術の説明は,Weimer と Necula による Finding and Preventing Run-Time Error Handling Mistakes を参照してください。

OBL: チェック例外でストリームやリソースのクリーンアップに失敗するかもしれないメソッド (OBL_UNSATISFIED_OBLIGATION_EXCEPTION_EDGE)

このメソッドは,ストリーム,データベースオブジェクト,またはクリーンアップ操作を明示的必要としている他のリソースのクリーンアップ (クローズする,片付ける) に失敗するかもしれません。

一般的にメソッドがストリープや他のリソースを開いたなら,メソッドはストリームやリソースがメソッドが戻る前にクリーンアップされることを確認するために try-finally ブロックを使用すべきです。

このバグパターンは,OS_OPEN_STREAM と ODR_OPEN_DATABASE_RESOURCE と基本的に同じですが異なる (そして,うまくいけばより良い) 静的解析技術に基づいています。 私たちは,このバグパターンの有効性についてのフィードバックを得ることに関心があります。 どちらかの方法でフィードバックを送ってください。

特に,このバグパターンの誤検出抑制探索法は詳細にわたって調整されていないので,誤検出についてのレポートは我々の助けになります。

解析技術の説明は,Weimer と Necula による Finding and Preventing Run-Time Error Handling Mistakes を参照してください。

LG: ロガーの変更は OpenJDK の弱参照が原因で潜在的に失われる (LG_LOST_LOGGER_DUE_TO_WEAK_REFERENCE)

OpenJDK は,潜在的非互換性を取り入れました。特に, java.util.logging.Logger は振る舞いが変更されています。 強参照を使用する代わりに弱参照を内部的に使用しています。 これは妥当な変更ですが,残念ながらいくつかのコードは古い振る舞いに依存しています。ロガーの構成を変更すると,ロガーへの参照が削除されます。 これは,ガベージコレクタが自由にそのメモリを再利用できることを意味します。つまり,ロガーの構成が失われます。
たとえば,次を検討してください。

public static void initLogging() throws Exception {
    Logger logger = Logger.getLogger("edu.umd.cs");
    logger.addHandler(new FileHandler()); // ロガーの構成の変更
    logger.setUseParentHandlers(false); // 別のロガーの構成の変更
}

ロガーの参照は,メソッドの終わり (メソッドは脱出しません) で失われるので, initLogging の呼び出しの後でガベージコレクションの循環があるなら,ロガー構成は失われます (なぜなら Logger は弱参照を保持するだけなので)。

public static void main(String[] args) throws Exception {
    initLogging(); // ファイルハンドラーをロガーに追加する
    System.gc(); // ロガーの構成が失われる
    Logger.getLogger("edu.umd.cs").info("Some message"); // 期待したようにファイルに記録されません
}

Ulf Ochsenfahrt と Eric Fellheimer

国際化 (I18N)

国際化とロケールに関係があるコードの欠陥です。

Dm: 呼び出したメソッドの Locale パラメータの使用を検討する (DM_CONVERT_CASE)

文字列がプラットフォームのデフォルトエンコーディングを使用して大文字,小文字に変換されています。 国際文字で使われると不適切な変換になることがあります。

  • String.toUpperCase(Locale l)
  • String.toLowerCase(Locale l)

Dm: デフォルトエンコーディングへの依存 (DM_DEFAULT_ENCODING)

byte から String (または String から byte) への変換で,デフォルトプラットフォームエンコーディングが適切だと仮定するメソッドの呼び出しを発見しました。 これはアプリケーションの振る舞いがプラットフォーム間で異なる原因となります。代替 API を使用して,文字セット名または Charset オブジェクトを明示的に指定して下さい。

悪意のあるコード脆弱性 (MALICIOUS_CODE)

信頼できないコードからの攻撃に対して脆弱なコードです。

DP: doPrivileged ブロック内で呼び出すべきメソッド (DP_DO_INSIDE_DO_PRIVILEGED)

このコードはセキュリティ許可チェックが必要なメソッドを呼び出しています。 このコードにセキュリティ許可が与えられるとしても,セキュリティ許可を持たないコードによって呼び出されるなら doPrivileged ブロックの中で呼び出す必要があります。

DP: doPrivileged ブロック内で作成されるべきクラスローダ (DP_CREATE_CLASSLOADER_INSIDE_DO_PRIVILEGED)

このコードはクラスローダを作成していますが,セキュリティ管理がインストールされるなら許可が必要です。 このコードがセキュリティ許可がないコードによって呼び出されるなら,クラスローダの作成は doPrivileged ブロックの中で行う必要があります。

FI: ファイナライザは public ではなく protected にすべき (FI_PUBLIC_SHOULD_BE_PROTECTED)

このクラスの finalize メソッドは public ではなく, protected にすべきです。

MS: 配列を返すことによって内部表現を暴露するかもしれない public static メソッド (MS_EXPOSE_REP)

public static メソッドは,クラスの 静的な状態の一部である配列の参照を返します。 このメソッドを呼び出すどんなコードも,基底配列を自由に変更できます。 解決策は,配列のコピーを返すことです。

EI: 可変オブジェクトへの参照を返すことによって内部表現を暴露するかもしれないメソッド (EI_EXPOSE_REP)

オブジェクトのフィールドに格納された可変オブジェクトの参照を返すと,オブジェクトの内部表現を暴露します。 インスタンスが信頼できないコードによってアクセスされるなら,可変オブジェクトのチェックされていない変更がセキュリティや他の重要なプロパティを危うくするでしょう。 何か違うことをする必要があります。オブジェクトの新しいコピーを返すことは,多くの状況でより良いアプローチです。

EI2: 可変オブジェクトへの参照を取り込むことによって内部表現を暴露するかもしれないメソッド (EI_EXPOSE_REP2)

このコードはオブジェクトの内部表現に外部の可変オブジェクトの参照を格納しています。 インスタンスが信頼できないコードによってアクセスされるなら,可変オブジェクトのチェックされていない変更がセキュリティや他の重要なプロパティを危うくするでしょう。 何か違うことをする必要があります。オブジェクトのコピーを格納することは,多くの状況でより良いアプローチです。

MS: static フィールドに可変オブジェクトを格納することによって,内部の静的状態を暴露するかもしれないメソッド (EI_EXPOSE_STATIC_REP2)

このコードは static フィールドに外部の可変オブジェクトを格納しています。 可変オブジェクトのチェックされていない変更がセキュリティや他の重要なプロパティを危うくするでしょう。 何か違うことをする必要があります。オブジェクトのコピーを格納することは,多くの状況でより良いアプローチです。

MS: インタフェースから移動してパッケージプロテクテッドにすべきフィールド (MS_OOI_PKGPROTECT)

インタフェースに定義された static final フィールドが配列や Hashtable などの可変オブジェクトを参照しています。 この可変オブジェクトは悪意のあるコードや別のパッケージによって思いがけず変更される可能性があります。 脆弱性を回避するためにフィールドをクラスに移動して,パッケージプロテクテッドにする必要があります。

MS: final かつパッケージプロテクテッドにすべきフィールド (MS_FINAL_PKGPROTECT)

この可変 static フィールドは悪意のあるコードや別のパッケージによって思いがけず変更される可能性があります。 脆弱性を回避するためにフィールドを final および/またはパッケージプロテクテッドにします。

MS: final にすべきフィールド (MS_SHOULD_BE_FINAL)

final ではない public static フィールドは悪意のあるコードや別のパッケージによって思いがけず変更される可能性があります。 脆弱性を回避するためにフィールドを final にします。

MS: final ではないフィールドはリファクタリングすべき (MS_SHOULD_BE_REFACTORED_TO_BE_FINAL)

final ではない public static フィールドは悪意のあるコードや別のパッケージによって思いがけず変更される可能性があります。 脆弱性を回避するためにフィールドを final にします。 しかしながら,スタティックイニシャライザには複数のフィールドへの書き込みがあるので,何らかのリファクタリングを必要とするでしょう。

MS: パッケージプロテクテッドにすべきフィールド (MS_PKGPROTECT)

この可変 static フィールドは悪意のあるコードや別のパッケージによって思いがけず変更される可能性があります。 脆弱性を回避するためにフィールドをパッケージプロテクテッドにします。

MS: 可変 Hashtable のフィールド (MS_MUTABLE_HASHTABLE)

この static final フィールドは Hashtable を参照しているので,悪意のあるコードや別のパッケージによって思いがけずアクセスされる可能性があります。 このコードはHashtable の内容を自由に変更できます。

MS: 可変配列のフィールド (MS_MUTABLE_ARRAY)

この static final フィールドは配列を参照しているので,悪意のあるコードや別のパッケージによって思いがけずアクセスされる可能性があります。 このコードは配列の内容を自由に変更できます。

MS: 可変コレクションのフィールド (MS_MUTABLE_COLLECTION)

可変コレクションのインスタンスが static final フィールドに割り当てられています。 したがって,悪意のあるコードや別のパッケージによって思いがけず変更される可能性があります。 脆弱性を避けるために Collections.unmodifiableSet/List/Map などでこのフィールドをラップすることを検討してください。

MS: パッケージプロテクテッドにすべき可変コレクションのフィールド (MS_MUTABLE_COLLECTION_PKGPROTECT)

可変コレクションのインスタンスが static final フィールドに割り当てられています。 したがって,悪意のあるコードや別のパッケージによって思いがけず変更される可能性があります。 フィールドは脆弱性を避けるためにパッケージプロテクテッドにできます。 脆弱性を避けるために Collections.unmodifiableSet/List/Map などでこのフィールドをラップすることを検討してください。

MS: final ではないフィールドは悪意のあるコードから保護できない (MS_CANNOT_BE_FINAL)

この可変 static フィールドは悪意のあるコードや別のパッケージによって思いがけず変更される可能性があります。 残念ながらこのような使い方は簡単に解決できません。

マルチスレッドの正確性 (MT_CORRECTNESS)

スレッド,ロック,volatile に関係があるコードの欠陥です。

AT: 並行抽象の呼び出しシーケンスはアトミックではないかもしれない (AT_OPERATION_SEQUENCE_ON_CONCURRENT_ABSTRACTION)

このコードには並行抽象化 (たとえば,並行ハッシュマップ) の呼び出しシーケンスがあります。 これらの呼び出しはアトミックに実行されません。

STCAL: static Calendar フィールド (STCAL_STATIC_CALENDAR_INSTANCE)

たとえ JavaDoc にそれに関する手がかりがないとしても, Calendar はマルチスレッドでの使用は本質的に安全でありません。 正しい同期化をしないでスレッド境界の向こうで1つのインスタンスを共有することは,アプリケーションの動作が不安定になります。 JDK 5.0に比べて JDK 1.4 のほうが問題が表面化するように思われ,おそらく sun.util.calendar.BaseCalendar.getCalendarDateFromFixedDate()ArrayIndexOutOfBoundsExceptionsIndexOutOfBoundsExceptions がランダムに発生します。

直列化問題も経験するかもしれません。

インスタンスフィールドを使用することを推奨します。

詳細については, JDK Bug #6231579JDK Bug #6178997 を参照してください。

STCAL: static DateFormat フィールド (STCAL_STATIC_SIMPLE_DATE_FORMAT_INSTANCE)

JavaDoc に書かれているように DateFormat はマルチスレッドでの使用は本質的に安全ではありません。 正しい同期化をしないでスレッド境界の向こうで1つのインスタンスを共有することは,アプリケーションの動作が不安定になります。

直列化問題も経験するかもしれません。

インスタンスフィールドを使用することを推奨します。

詳細については, JDK Bug #6231579JDK Bug #6178997 を参照してください。

STCAL: static Calendar の呼び出し (STCAL_INVOKE_ON_STATIC_CALENDAR_INSTANCE)

たとえ JavaDoc にそれに関する手がかりがないとしても, Calendar はマルチスレッドでの使用は本質的に安全ではありません。 ディテクタは, static フィールドから得られた Calendar のインスタンスの呼び出しを発見しました。 これは疑わしく見えます。

詳細については, JDK Bug #6231579JDK Bug #6178997 を参照してください。

STCAL: static DateFormat の呼び出し (STCAL_INVOKE_ON_STATIC_DATE_FORMAT_INSTANCE)

JavaDoc に書かれているように DateFormat はマルチスレッドでの使用は本質的に安全ではありません。 ディテクタは, static フィールドから得られた DateFormat のインスタンスの呼び出しを発見しました。 これは疑わしく見えます。

詳細については, JDK Bug #6231579JDK Bug #6178997 を参照してください。

NP: 同じフィールドでの同期化と null チェック (NP_SYNC_AND_NULL_CHECK_FIELD)

フィールドは同期化しているので,おそらく null ではないと思われます。 null のフィールドを同期化すると NullPointerException がスローされるので, null チェックは無意味になります。 別のフィールドで同期化したほうがよいです。

VO: 配列への volatile 参照は,配列要素を volatile として扱わない (VO_VOLATILE_REFERENCE_TO_ARRAY)

配列に volatile 参照を宣言していますが,あなたが望むものではないかもしれません。 配列への volatile 参照は,配列への参照の読み出し,書き込みは volatile として扱われますが,配列要素は volatile として扱われません。 配列要素を volatile として扱いたいのであれば,J2SE 5.0で提供された java.util.concurrent パッケージのアトミック配列クラスを使用する必要があります。

VO: volatile フィールドへのインクリメントはアトミックではない (VO_VOLATILE_INCREMENT)

このコードは volatile フィールドをインクリメントしています。 volatile フィールドのインクリメントはアトミックではありません。 複数のスレッドが同時にフィールドをインクリメントすると,インクリメントが失われる可能性があります。

Dm: Condition で呼び出された wait メソッドを監視している (DM_MONITOR_WAIT_ON_CONDITION)

このメソッドは, java.util.concurrent.locks.Condition オブジェクトで wait メソッドを呼び出しています。 Condition オブジェクトを待機させるためには Condition インタフェースで定義された await メソッドを使用すべきです。

Dm: デフォルトの空の run メソッドを使用して作成されたスレッド (DM_USELESS_THREAD)

このメソッドは, Thread クラスから派生した run メソッドを指定していないか, Runnable オブジェクトを渡すことなく,スレッドを作成しています。 このスレッドは,時間の無駄です。

DC: フィールドのダブルチェックの可能性 (DC_DOUBLECHECK)

このメソッドにはダブルチェックロッキングのインスタンスがあるかもしれません。このイディオムは,Java のメモリモデルでは正しくありません。
詳細は, http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html を参照してください。

DC: 部分的に初期化されたオブジェクトを暴露する可能性がある (DC_PARTIALLY_CONSTRUCTED)

ダブルチェックロッキングと共に遅延初期化フィールドを使用するメソッドのようです。 フィールドが正しく volatile として宣言される間にオブジェクトの内部構造がフィールドに割り当てられた後で変更される可能性があります。 したがって,他のスレッドが部分的に初期化されたオブジェクトを見るかもしれません。

この問題を直すために,最初にローカル変数をオブジェクトに格納して,完全に構築した後で volatile フィールドを保存することを考えてください。

DL: 正準化した文字列の同期化 (DL_SYNCHRONIZATION_ON_SHARED_CONSTANT)

このコードは正準化した文字列で同期化しています。

private static String LOCK = "LOCK";
...
synchronized(LOCK) {
    ...
}
...

文字列定数は正準化され,Java 仮想マシンによってロードされたすべてのクラス全体で共有されます。 このコードは,他のコードがロックしている可能性があるものをロックしています。 これはブロックとデッドロックの振る舞いを診断するのが非常に奇妙で困難になる可能性があります。
詳細は, http://www.javalobby.org/java/forums/t96352.htmlhttp://jira.codehaus.org/browse/JETTY-352 を参照してください。

CERT CON08-J. Do not synchronize on objects that may be reused を参照してください。

DL: Boolean の同期化 (DL_SYNCHRONIZATION_ON_BOOLEAN)

Boolean のようなボクシングされたプリミティブ型の定数で同期化しています。

private static Boolean inited = Boolean.FALSE;
...
synchronized(inited) {
    if (!inited) {
        init();
        inited = Boolean.TRUE;
    }
}
...

一般には2つの Boolean オブジェクトだけが存在しています。 このコードは他の無関係なコードと同じオブジェクトで同期化している可能性があるので,無応答やデッドロックの原因になります。

CERT CON08-J. Do not synchronize on objects that may be reused を参照してください。

DL: ボクシングされたプリミティブの同期化 (DL_SYNCHRONIZATION_ON_BOXED_PRIMITIVE)

このコードは Integer のようなボクシングされたプリミティブの定数で同期化しています。

private static Integer count = 0;
...
synchronized(count) {
    count++;
}
...

Integer オブジェクトはキャッシュして共有できます。 他の無関係なコードと同じオブジェクトで同期化している可能性があるので,無応答やデッドロックの原因になります。

CERT CON08-J. Do not synchronize on objects that may be reused を参照してください。

DL: ボクシングされたプリミティブ値の同期化 (DL_SYNCHRONIZATION_ON_UNSHARED_BOXED_PRIMITIVE)

このコードは明らかに共有されていない Integer のようなボクシングされたプリミティブ型で同期化しています。

private static final Integer fileLock = new Integer(1);
...
synchronized(fileLock) {
    .. do something ..
}
...

このコードは fileLock を次のように宣言するとより良くなります。

private static final Object fileLock = new Object();

既存のコードとしては間違っていないかもしれないが,紛らわしいので将来リファクタリングすべきかもしれません。 たとえば,IntelliJ の "Remove Boxing" のようなリファクタリングは Java 仮想マシンを通して共有される正準化された Integer オブジェクトを使用するように置き換えてしまい,非常に紛らわしい振る舞いと潜在的デッドロックの原因になります。

WL: クラスリテラルではなく getClass で同期化している (WL_USING_GETCLASS_RATHER_THAN_CLASS_LITERAL)

このインスタンスメソッドは, this.getClass() で同期化しています。 このクラスがサブクラス化されるなら,サブクラスはおそらく意図したことではないサブクラスのためにクラスオブジェクトで同期化します。 たとえば, java.awt.Label の次のコードを検討してください。

private static final String base = "label";
private static int nameCounter = 0;

String constructComponentName() {
    synchronized (getClass()) {
        return base + nameCounter++;
    }
}

Label のサブクラスは同じサブクラスで同期化しません。データレースを生じさせます。 代わりに,このコードは Label.class で同期化すべきです。

private static final String base = "label";
private static int nameCounter = 0;

String constructComponentName() {
    synchronized (Label.class) {
        return base + nameCounter++;
    }
}

Jason Mehrens によって寄贈されたバグパターン

ESync: 空の synchronized ブロック (ESync_EMPTY_SYNC)

このコードには空の synchronized ブロックがあります。

synchronized() {
}

空の synchronized ブロックは巧妙で正しく使用するのは困難です。 空の synchronized ブロックはわざとらしくて決して良い解決策ではありません。

MSF: 可変サーブレットフィールド (MSF_MUTABLE_SERVLET_FIELD)

Web サーバは,一般的にサーブレットや JSP クラスのインスタンスを1つだけ作成します (すなわち,シングルトンとして扱います)。 複数のスレッドが複数同時のリクエストに応えるためにそのインスタンスでメソッドを呼び出します。 したがって,一般に可変インスタンスフィールドは競合状態を作ります。

IS: 一貫性のない同期化 (IS2_INCONSISTENT_SYNC)

このクラスのフィールドは,同期化に関して一貫性なくアクセスされるように見えます。 このバグレポートは,バグパターンディテクタが次のように判断したことを示します。

  • クラスは,ロックされたアクセスとアンロックされたアクセスが混在していて,
  • クラスは, javax.annotation.concurrent.NotThreadSafe アノテーションが付けられていなくて,
  • 少なくとも1つのロックされたアクセスがクラス自身のメソッドの1つによって実行され,
  • 読み出しの2倍の重み付けをした書き込みで,非同期フィールドのアクセス (読み出しと書き込み) 数がすべてのアクセスのわずか1/3

このバグパターンに合致する一般的なバグは,スレッドセーフを意図したクラスでメソッドを同期化させることを忘れていることです。

「非同期アクセス」というラベルがついているノードを選択すると,ディテクタが同期化しないでフィールドにアクセスしたと信じているコードの場所を表示できます。

不正確ないろいろな原因がこのディテクタにあることに注意してください。 たとえば,ディテクタはロックを保持されるすべての状況を静的に検出できるわけではありません。 また,ディテクタがロックされたアクセスとアンロックされたアクセスの区別が正確なときでも,問題のコードは依然として正しいかもしれません。

NN: 裸の notify メソッド (NN_NAKED_NOTIFY)

notify メソッドまたは notifyAll メソッドへの呼び出しは可変オブジェクト状態にどんな (明らかな) 付随的な変更ももたらされませんでした。 一般的に別のスレッドが期待しているいくつかの条件が真になったので,モニタで notify メソッドが呼び出されます。 しかしながら,意味がある条件のために両方のスレッドに見えるヒープオブジェクトを含まなければなりません。

可変オブジェクトの状態変更が通知があるメソッドを呼び出したメソッドで起こったかもしれないので,このバグが必ずしもエラーを示すというわけではありません。

Ru: スレッドで run メソッドを呼び出している (RU_INVOKE_RUN)

このメソッドは,スレッドで 明示的に run メソッドを呼び出しています。 一般的にクラスは新しいスレッドで自己の run メソッドを呼び出してもらうために Runnable インタフェースを実装します。 その場合は, Thread.start() を呼び出すのが正しいです。

SP: スピンロックをしているメソッド (SP_SPIN_ON_FIELD)

このメソッドは,フィールドを読み出すループで回り続けます。 コンパイラがフィールドの読み出しをループの外に出すかもしれません。コードを無限ループに変えます。 正しい同期化 (wait/notify を呼び出すように含む) を使うようにクラスを変更すべきです。

TLW: 2つ以上のロックを保持して wait メソッドを呼び出している (TLW_TWO_LOCK_WAIT)

2つ以上のロックを保持して,モニタで待機させるとデッドロックを引き起こすことがあります。 wait メソッドを呼び出すと,待機しているオブジェクトのロックを解除するだけで,その他のロックは解除しません。 これは必ずしもバグではありませんが厳密に調べる価値があります。

UW: wait メソッドの無条件呼び出し (UW_UNCOND_WAIT)

このメソッドには条件制御フローによってガードされない java.lang.Object.wait() の呼び出しがあります。 このコードは wait メソッドを呼び出す前に待機するつもりだった条件が既に満たされていないことを確かめるべきです。 どんな前の通知も無視されます。

UG: 同期化していない get メソッド,同期化している set メソッド (UG_SYNC_SET_UNSYNC_GET)

このクラスには類似した名前の get メソッドと set メソッドがあり,set メソッドは同期化していて,get メソッドは同期化していません。 get メソッドの呼び出し元がオブジェクトの一貫した状態を必ずしも見るというわけではないので,実行時に間違った振る舞いの原因になることがあります。 get メソッドは同期化すべきです。

IS: 並行アクセスに対してガードされていないフィールド (IS_FIELD_NOT_GUARDED)

このフィールドは, net.jcip.annotations.GuardedBy または javax.annotation.concurrent.GuardedBy というアノテーションが付けられていますが,アノテーションに違反するような方法でアクセスできます。

ML: フィールドを同期化でガードしようとする無駄な試み (ML_SYNC_ON_FIELD_TO_GUARD_CHANGING_THAT_FIELD)

このメソッドは,フィールドの同時更新に対して同期化でガードしようとしています。しかし,フィールドをガードするとフィールドではなく,フィールドが参照するオブジェクトのロックを獲得します。 これはあなたが必要とする相互排除ができないかもしれません。 他のスレッドは (他の目的のための) 参照されたオブジェクトのロックを獲得するかもしれません。
このパターンの例は次のようになります。

private Long myNtfSeqNbrCounter = new Long(0);
private Long getNotificationSequenceNumber() {
     Long result = null;
     synchronized(myNtfSeqNbrCounter) {
         result = new Long(myNtfSeqNbrCounter.longValue() + 1);
         myNtfSeqNbrCounter = new Long(result.longValue());
     }
     return result;
}

ML: 更新されるフィールドで同期化しているメソッド (ML_SYNC_ON_UPDATED_FIELD)

このメソッドは,可変フィールドから参照されたオブジェクトで同期化しています。 異なるスレッドが異なるオブジェクトで同期化しているかもしれないので,有用な意味を持っている可能性が低いです。

WS: writeObject メソッドは同期化しているがその他のメソッドは同期化していないクラス (WS_WRITEOBJECT_SYNC)

このクラスには同期化している writeObject メソッドがあります。 しかしながら,クラスのその他のメソッドは同期化していません。

RS: readObject メソッドを同期化しているクラス (RS_READOBJECT_SYNC)

この直列化可能クラスは同期化している readObject メソッド を定義しています。 直列化復元によって作成されるオブジェクトは1つのスレッドによってだけ到達可能です。 したがって, readObject メソッドは同期化する必要がありません。 readObject メソッドそのものが別のスレッドに見えるようになるオブジェクトの原因になっているなら非常に疑わしいコーディングスタイルの例です。

SC: Thread.start() を呼び出しているコンストラクタ (SC_START_IN_CTOR)

コンストラクタがスレッドを開始しています。クラスが拡張され,サブクラスが作られるなら間違っていそうです。 なぜなら,サブクラスのコンストラクタでスレッドが開始される前にスーパークラスのスレッドが開始されてしまうためです。

Wa: wait メソッドがループの中にない (WA_NOT_IN_LOOP)

このメソッドは,ループの中にない java.lang.Object.wait() を呼び出しています。 モニタが複数の条件のために使われるなら,呼び出し元が待機するつもりだった条件は実際には発生しないかもしれません。

Wa: Condition.await() がループの中にない (WA_AWAIT_NOT_IN_LOOP)

このメソッドは,ループの中にない java.util.concurrent.await() (またはそのバリエーション) を呼び出しています。 オブジェクトが複数の条件のために使われるなら,呼び出し元が待機するつもりだった条件は実際には発生しないかもしれません。

No: notifyAll メソッドではなく notify メソッドを使用している (NO_NOTIFY_NOT_NOTIFYALL)

このメソッドは, notifyAll メソッドではなく notify メソッドを呼び出しています。 モニターは,複数の条件で使われることがよくあります。 notify メソッドの呼び出しは1つのスレッドを起こすだけで起こされたスレッドは呼び出し元が満たした待機条件の1つではないかもしれないことを意味しています。

UL: すべての経路でロックが解除されないメソッド (UL_UNRELEASED_LOCK)

このメソッドは,JSR-166(java.util.concurrent) のロックを獲得していますが,メソッドからのすべての経路で解除していません。 一般的に JSR-166 のロックを使用するための正しいイディオムは次のようになります。

Lock l = ...;
l.lock();
try {
    // do something
} finally {
    l.unlock();
}

UL: すべての例外経路でロックが解除されないメソッド (UL_UNRELEASED_LOCK_EXCEPTION_PATH)

このメソッドは,JSR-166(java.util.concurrent) のロックを獲得していますが,メソッドからのすべての例外経路で解除していません。 一般的に JSR-166 のロックを使用するための正しいイディオムは次のようになります。

Lock l = ...;
l.lock();
try {
    // do something
} finally {
    l.unlock();
}

MWN: 不整合な wait メソッド (MWN_MISMATCHED_WAIT)

このメソッドは,オブジェクトで明らかにロックを保持することなく, Object.wait() を呼び出しています。 保持されるロックがない状態で, wait メソッドを呼び出すことは, IllegalMonitorStateException をスローすることになります。

MWN: 不整合な notify メソッド (MWN_MISMATCHED_NOTIFY)

このメソッドは,オブジェクトで明らかにロックを保持することなく Object.notify()Object.notifyAll() を呼び出しています。 保持されるロックがない状態で, notify メソッドや notifyAll メソッドを呼び出すことは, IllegalMonitorStateException をスローすることになります。

LI: static フィールドの間違った遅延初期化 (LI_LAZY_INIT_STATIC)

このメソッドには volatile ではない static フィールドの非同期な遅延初期化があります。 コンパイラやプロセッサが命令を並べ替えるかもしれないので,メソッドが複数のスレッドによって呼び出されるなら,スレッドは完全に初期化されたオブジェクトを参照することは保証されません。 この問題を修正するためにフィールドを volatile にできます。
詳細は, Java Memory Model web site を参照してください。

LI: 更新される static フィールドの間違った遅延初期化 (LI_LAZY_INIT_UPDATE_STATIC)

このメソッドには static フィールドの非同期な遅延初期化があります。 フィールドが設定されると,その場所に格納されているオブジェクトはさらに更新またはアクセスされます。フィールドの設定は,他のスレッドにすぐに見えます。 フィールドを設定するメソッドのさらなるアクセスがオブジェクトの初期化に役立つなら, 完全に初期化されるまで他のスレッドが格納されたオブジェクトにアクセスすることを防がないかぎり,非常に深刻なマルチスレッドバグがあります。

たとえメソッドが複数のスレッドによって決して呼び出されないと確信していても, フィールドに設定する値が完全に設定/初期化されるまで, static フィールドを設定しないほうが良いかもしれません。

JLM: java.util.concurrent のインスタンスで同期化している (JLM_JSR166_UTILCONCURRENT_MONITORENTER)

このメソッドは,java.util.concurrent パッケージのクラス (またはサブクラス) のインスタンスで同期化しています。 これらのクラスのインスタンスは, synchronized による同期とは違う独自の並行制御メカニズムを持っています。 たとえば, AtomicBoolean で同期しても,他のスレッドが AtomicBoolean を変更することを防げません。

そのようなコードは正しいかもしれませんが,将来コードを維持しなければならない人々を混乱させるかもしれないので慎重にレビューし文書化すべきです,

JLM: util.concurrent 抽象化でモニタスタイルの wait メソッドを使用している (JML_JSR166_CALLING_WAIT_RATHER_THAN_AWAIT)

このメソッドは, await() メソッド, signal メソッド, signalAll メソッドを提供するオブジェクト (たとえば,util.concurrent の Condition オブジェクト) で, wait メソッド, notify メソッド, notifyAll メソッドを呼び出しています。 これはおそらくあなたが望むことではなく,たとえそれを望むとしても,他の開発者が非常に混乱することを理解して,設計を変更することを検討すべきです。

JLM: Lock で同期化している (JLM_JSR166_LOCK_MONITORENTER)

このメソッドは, java.util.concurrent.locks.Lock を実装したオブジェクトで同期化しています。 そのようなオブジェクトは synchronized (...) 構文よりも acquire()/release() を使用してロックとロックの解除をします。

SWL: ロックを保持して Thread.sleep() を呼び出しているメソッド (SWL_SLEEP_WITH_LOCK_HELD)

このメソッドは,ロックを保持して, Thread.sleep() を呼び出しています。 他のスレッドがロックを獲得するために待機しているかもしれないので,ひどい性能とスケーラビリティ,またはデッドロックの原因になるかもしれません。 ロックで wait メソッドを呼び出すことはかなり良い考えで,ロックを解除して他のスレッドが実行するのを許可します。

RV: putIfAbsent の戻り値は無視されて putIfAbsent に渡した値は再利用された (RV_RETURN_VALUE_OF_PUTIFABSENT_IGNORED)

putIfAbsent メソッドは,1つの値が与えられたキー (非存在が成功するかどうかの第一の値) と関連することを確認するために使われます。 戻り値を無視して,渡された値への参照を保持するなら,マップ内のキーに関連付けられていない値を保持する危険性があります。 どれを使用するかが重要で,マップに格納されていないものを使うとプログラムは正しく動作しません。

偽のランダムノイズ (NOISE)

偽のランダムノイズ: ソフトウェアで実際のバグを発見するのではなく,データマイニング実験のコントロールとして役に立つことを意図しています。

NOISE: null ポインタ間接参照に関する偽の警告 (NOISE_NULL_DEREFERENCE)

偽の警告です。

NOISE: メソッド呼び出しに関する偽の警告 (NOISE_METHOD_CALL)

偽の警告です。

NOISE: フィールド参照に関する偽の警告 (NOISE_FIELD_REFERENCE)

偽の警告です。

NOISE: 演算に関する偽の警告 (NOISE_OPERATION)

偽の警告です。

性能 (PERFORMANCE)

必ずしも間違っているというわけではないが,効率が悪いかもしれないコードです。

HSC: 複数のクラスファイルにわたって複製されている巨大な文字列定数 (HSC_HUGE_SHARED_STRING_CONSTANT)

巨大な文字列定数が複数のクラスファイルにわたって複製されています。 final フィールドが文字列定数で初期化され,Java 言語によって他のクラスからの final フィールドへのすべての参照がクラスファイルにインライン化されるからです。

JDK はこのバグを解決してサイズを1MB減らすことができました。
詳細は, JDK bug 6447475 を参照してください。

Dm: URL の equals メソッドと hashCode メソッドはブロックする (DMI_BLOCKING_METHODS_ON_URL)

URLequals メソッドと hashCode メソッドは,ドメイン名の解決を行うので,ひどい性能になる可能性があります。
詳細は, http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html を参照してください。
その代わりに java.net.URI を使用することを検討してください。

Dm: URL の Map や Set はひどい性能になる (DMI_COLLECTION_OF_URLS)

このメソッドまたはフィールドは, URLMapSet を使用しています。 URLequalshashCode は,ドメイン名の解決を行うので,ひどい性能になります。
詳細は, http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html を参照してください。
その代わりに java.net.URI を使用することを検討してください。

Dm: 効率が悪い new String(String) コンストラクタを呼び出しているメソッド (DM_STRING_CTOR)

new String(String) コンストラクタの使用はメモリを浪費します。 そのようにして構築されたオブジェクトと パラメータとして渡された String は機能的に区別がつかないからです。 引数の String をそのまま使用してください。

Dm: 効率が悪い new String() コンストラクタを呼び出しているメソッド (DM_STRING_VOID_CTOR)

引数がないコンストラクタを使用して,新しい java.lang.String() オブジェクトを作成するとメモリを浪費します。 そのようにして作成されたオブジェクトと空の文字列定数 "" は機能的に区別がつかないからです。 Javaは,同一の文字列定数が同じ String オブジェクトによって表されることを保証します。 したがって,直接空の文字列定数を使用すべきです。

Dm: String の toString メソッドを呼び出しているメソッド (DM_STRING_TOSTRING)

String.toString() を呼び出すのは冗長です。String を使用してください。

Dm: 明示的なガベージコレクション (DM_GC)

明示的にガベージコレクションを呼び出しています。ベンチマークの特定の用途を除いて非常に疑わしいです。

過去に, close メソッドや finalize メソッドでガベージコレクタを明示的に呼び出していた状況は,巨大なパフォーマンスブラックホールの原因となりました。 ガベージコレクションは高くつきます。何百,何千ものガベージコレクションを強制する状況は,システムの停滞をもたらすでしょう。

Dm: 効率が悪い Boolean コンストラクタを呼び出しているメソッド (DM_BOOLEAN_CTOR)

java.lang.Boolean の新しいインスタンスを作成するとメモリを浪費します。 Boolean オブジェクトは不変で,2つの有用な値 (Boolean.TRUEBoolean.FALSE) があります。 その代わりに Boolean.valueOf メソッド (または J2SE 5.0 のオートボクシング) を使用して Boolean オブジェクトを作成してください。

Bx: 効率が悪い Number コンストラクタを呼び出しているメソッド (DM_NUMBER_CTOR)

new Integer(int) の使用は,常に新しいブジェクトになることが保証されています。 これに対して, Integer.valueOf(int) は,コンパイラ,クラスライブラリ,Java 仮想マシンで値がキャッシュされます。 キャッシュに格納された値を使用することはインスタンスの作成を回避し,コードはより高速になります。

-128から127までの値は対応するキャッシュされたインスタンスを持つことが保証されています。 そして, valueOf メソッドの使用は,コンストラクタを使用するより約3.5倍高速です。 定数範囲外の値は,両方のスタイルの性能は同じです。

クラスが J2SE 5.0より前の Java 仮想マシンとの互換性が不要なら, LongIntegerShortCharacterByte のインスタンスを作成するときは,オートボクシングか valueOf メソッドを使用してください。

Bx: 効率が悪い浮動小数点 Number コンストラクタを呼び出しているメソッド (DM_FP_NUMBER_CTOR)

new Double(double) の使用は,常に新しいブジェクトになることが保証されています。 これに対して, Double.valueOf(double) は,コンパイラ,クラスライブラリ,Java 仮想マシンで値がキャッシュされます。 キャッシュに格納された値を使用することはインスタンス生成を回避し,コードはより高速になります。

クラスが J2SE 5.0より前の Java 仮想マシンとの互換性が不要なら,オートボクシングか DoubleFloatvalueOf メソッドを使用してください。

Bx: toString メソッドを呼び出すためだけにボクシングされたプリミティブを割り当てている (DM_BOXED_PRIMITIVE_TOSTRING)

ボクシングされたプリミティブが toString メソッドを呼び出すためだけに割り当てられています。 それよりもプリミティブ値を引数にとる statictoString メソッドを使用したほうが効率的です。

置換前置換後
new Integer(1).toString() Integer.toString(1)
new Long(1).toString() Long.toString(1)
new Float(1.0).toString() Float.toString(1.0)
new Double(1.0).toString() Double.toString(1.0)
new Byte(1).toString() Byte.toString(1)
new Short(1).toString() Short.toString(1)
new Boolean(true).toString()Boolean.toString(true)

Bx: プリミティブを解析するためのボクシング/アンボクシング (DM_BOXED_PRIMITIVE_FOR_PARSING)

ボクシングされたプリミティブがボクシングされていないプリミティブ値を抽出するために String から生成されています。 static parseXXX メソッドを呼び出す方が効率的です。

Bx: プリミティブが比較でボクシングされている (DM_BOXED_PRIMITIVE_FOR_COMPARE)

ボクシングされたプリミティブが単に compareTo メソッドを呼び出すために作られています。 直接プリミティブで働く static compare メソッド (doublefloat は Java 1.4から,他のプリミティブ型は Java 1.7から) を使うほうがより効率的です。

Bx: プリミティブ値が3項演算子のためにアンボクシングされて,型変換される (BX_UNBOXED_AND_COERCED_FOR_TERNARY_OPERATOR)

ラップされたプリミティブ値は,3項演算子 (b ? e1 : e2) の評価の一部として,別のプリミティブ型にアンボクシングされて変換されます。 Java 言語仕様では, e1e2 がラップされた数値なら値はアンボクシングされ,共通の型へと変換/型変換されます (たとえば, e1Integer で, e2Float なら e1 はアンボクシング (int に変換) され, float に変換され,ボクシング (Float に変換) されます)。 JLS セクション15.25を参照してください。

Bx: ボクシングされた値がアンボクシングされて,すぐに再ボクシングされる (BX_UNBOXING_IMMEDIATELY_REBOXED)

ボクシングされた値がアンボクシングされて,すぐに再ボクシングされます。

Bx: プリミティブ値がボクシングされて,すぐにアンボクシングされる (BX_BOXING_IMMEDIATELY_UNBOXED)

プリミティブ値がボクシングされて,すぐにアンボクシングされます。 おそらくアンボクシングされた値が必要な場所で手動でボクシングをしているためです。 その結果,コンパイラにボクシングの機能を取り消すことを強制しています。

Bx: プリミティブ値がプリミティブ型の型変換をするためにボクシングされて,アンボクシングされる (BX_BOXING_IMMEDIATELY_UNBOXED_TO_PERFORM_COERCION)

プリミティブ値がコンストラクタでボクシングされて,すぐに異なるプリミティブ型に変換されます (たとえば new Double(d).intValue())。 直接プリミティブ型の型変換を実行してください (たとえば (int) d)。

Dm: クラスオブジェクトを得るためだけにインスタンスを作成しているメソッド (DM_NEW_FOR_GETCLASS)

メソッドは,クラスオブジェクトを得るためにインスタンスを生成して getClass メソッドを呼び出しています。 クラスリテラル (Foo.class) を使うほうが簡単です。

Dm: 整数の乱数を生成するためには nextDouble メソッド ではなく nextInt メソッドを使用する (DM_NEXTINT_VIA_NEXTDOUBLE)

java.util.Random のインスタンス r で, 0 から n-1 の乱数を生成したいのであれば, (int)(r.nextDouble() * n) ではなく r.nextInt(n) を使用します。

nextInt メソッドへの引数は整数でなければなりません。 たとえば,-99から0までの乱数を生成したいなら, -r.nextInt(100) を使用してください。

SS: 読み出されないフィールド (SS_SHOULD_BE_STATIC)

このクラスにはコンパイル時に静的な値に初期化されるインスタンス final フィールドがあります。 static フィールドにすることを検討してください。

UuF: 未使用のフィールド (UUF_UNUSED_FIELD)

このフィールドは決して使用されません。クラスから除去することを検討してください。

UrF: 読み出されないフィールド (URF_UNREAD_FIELD)

このフィールドは決して読み出されません。クラスから除去することを検討してください。

SIC: static 内部クラスにすべき (SIC_INNER_SHOULD_BE_STATIC)

このクラスは内部クラスなのにそれを作成したオブジェクトへの埋め込まれた参照を使用していません。 この参照はより大きなクラスのインスタンスを作成して,不必要に作成オブジェクトへの参照を存続しておくことがあります。 できれば,クラスは static にすべきです。

SIC: static 内部クラスにリファクタリングできるかもしれない (SIC_INNER_SHOULD_BE_STATIC_NEEDS_THIS)

このクラスは内部クラスなのにそれを作成したオブジェクトへの埋め込まれた参照を使用していません。 この参照はより大きなクラスのインスタンスを作成して,不必要に長く作成オブジェクトへの参照を存続しておくかもしれません。 できれば,クラスは static 内部クラスにすべきです。 外部オブジェクトへの参照が内部クラスのインスタンスを構築する間必要なので内部クラスのコンストラクタに外部インスタンスへの参照を渡すようにリファクタリングする必要があります。

SIC: 名前付き static 内部クラスにリファクタリングできるかもしれない (SIC_INNER_SHOULD_BE_STATIC_ANON)

このクラスは内部クラスなのにそれを作成したオブジェクトへの埋め込まれた参照を使用していません。 この参照はより大きなクラスのインスタンスを作成して,不必要に作成オブジェクトへの参照を存続しておくことがあります。 できれば,クラスは static 内部クラスにすべきです。 無名内部クラスは static にできないので,名前付き内部クラスにリファクタリングする必要があります。

UPM: private メソッドは決して呼び出されない (UPM_UNCALLED_PRIVATE_METHOD)

この private メソッドは,決して呼び出されません。 メソッドがリフレクションによって呼び出されるかもしれないが,決して使われないなら除去すべきです。

SBSC: ループの中で + を使用して文字列を連結しているメソッド (SBSC_USE_STRINGBUFFER_CONCATENATION)

このメソッドは,ループの中で + を使用して String を構築していると思われます。 各々の繰り返しにおいて, StringStringBuffer/StringBuilder に変換,追加され, String へ変換されます。 各々の繰り返しで文字列が再コピーされ,増大すると繰り返しの数で二次コストの原因になる可能性があります。

StringBuffer (または J2SE 5.0の StringBuilder) を明示的に使うとより良い性能を得られます。

たとえば,

// This is bad
String s = "";
for (int i = 0; i < field.length; ++i) {
    s = s + field[i];
}

// This is better
StringBuffer buf = new StringBuffer();
for (int i = 0; i < field.length; ++i) {
    buf.append(field[i]);
}
String s = buf.toString();

IIL: ループの中で NodeList.getLength() を呼び出しているメソッド (IIL_ELEMENTS_GET_LENGTH_IN_LOOP)

メソッドは,ループの中で NodeList.getLength() を呼び出し, NodeList は, getElementsByTagName の呼び出しによって作られます。 NodeList は長さを格納しませんが,毎回とても最適ではない方法で計算されます。 ループの前に変数に長さを格納することを検討してください。

IIL: ループの中で prepareStatement を呼び出しているメソッド (IIL_PREPARE_STATEMENT_IN_LOOP)

メソッドは,ループの中で Connection.prepareStatement に不変の引数を渡して呼び出しています。 PreparedStatement を複数回実行する必要があるなら,それぞれのループの繰り返しで再生成する理由がありません。 ループの外に呼び出しを移動します。

IIL: ループの中で Pattern.compile を呼び出しているメソッド (IIL_PATTERN_COMPILE_IN_LOOP)

メソッドは,ループの中で Pattern.compile に不変の定数を渡して呼び出しています。 Pattern を複数回使用する必要があるなら,それぞれのループの繰り返しでコンパイルする理由がありません。 ループの外に呼び出しを移動するか static final フィールドにします。

IIL: ループの中で正規表現をコンパイルしているメソッド (IIL_PATTERN_COMPILE_IN_LOOP_INDIRECT)

メソッドは,ループの中で同じ正規表現を生成しているので,繰り返しごとにコンパイルされます。 ループの外で Pattern.compile を使用して正規表現をプリコンパイルするのが最適でしょう。

IIO: String.indexOf(String) の非効率的な使用 (IIO_INEFFICIENT_INDEX_OF)

このコードは String.indexOf() に長さ1の文字列定数を渡しています。String.indexOf() の整数実装を使うほうが効率的です。 たとえば, myString.indexOf(".") の代わりに myString.indexOf('.') を呼び出します。

IIO: String.lastIndexOf(String) の非効率的な使用 (IIO_INEFFICIENT_LAST_INDEX_OF)

このコードは String.lastIndexOf() に長さ1の文字列定数を渡しています。String.lastIndexOf() の整数実装を使うほうが効率的です。 たとえば, myString.lastIndexOf(".") の代わりに myString.lastIndexOf('.') を呼び出します。

ITA: 長さが0の配列の引数で toArray メソッドを使用しているメソッド (ITA_INEFFICIENT_TO_ARRAY)

このメソッドは, Collection 派生クラスの toArray メソッドを使用して長さが0の配列の引数を渡しています。 myCollection.toArray(new Foo[myCollection.size()]) を使用するほうがより効率的です。 渡される配列がコレクションの要素のすべてを格納できるくらいの大きさなら,設定されて,そのまま返されます。 これは結果として返す2番目の配列 (リフレクションによって) を作成する必要を回避します。

WMI: entrySet イテレータではなく効率が悪い keySet イテレータを使用している (WMI_WRONG_MAP_ITERATOR)

このメソッドは, keySet イテレータから取り出されたキーを使用して,マップエントリの値にアクセスしています。 MapentrySet イテレータを使用したほうが Map.get(key) ルックアップを回避するのでより効率的です。

UM: 定数値で Math クラスの static メソッドを呼び出しているメソッド (UM_UNNECESSARY_MATH)

このメソッドは,定数値で java.lang.Mathstatic メソッドを呼び出しています。 このメソッドの結果は静的に判定でき,より高速で,ときには定数を使用するほうがより正確です。
検出されるメソッドは,次のとおりです。

メソッド パラメータ
abs -any-
acos 0.0 or 1.0
asin 0.0 or 1.0
atan 0.0 or 1.0
atan2 0.0
cbrt 0.0 or 1.0
ceil -any-
cos 0.0
cosh 0.0
exp 0.0 or 1.0
expm1 0.0
floor -any-
log 0.0 or 1.0
log10 0.0 or 1.0
rint -any-
round -any-
sin 0.0
sinh 0.0
sqrt 0.0 or 1.0
tan 0.0
tanh 0.0
toDegrees 0.0 or 1.0
toRadians 0.0

IMA: 所有クラスの private メンバ変数にアクセスしているメソッド (IMA_INEFFICIENT_MEMBER_ACCESS)

この内部クラスのメソッドは,所有クラスの private メンバ変数への読み書きか,所有クラスの private メソッドを呼び出しています。 コンパイラはこの private メンバにアクセスするための特別なメソッドを生成しなければなりないので,効率を悪化させる原因になります。 メンバ変数またはメソッドの保護を緩和することは,コンパイラが正常なアクセスとして扱うのを許可します。

セキュリティ (SECURITY)

リモートから悪用可能なセキュリティ脆弱性を引き起こすかもしれない信頼できない入力を使用しています。

XSS: 反射型クロスサイトスクリプティング脆弱性がエラーページにあるサーブレット (XSS_REQUEST_PARAMETER_TO_SEND_ERROR)

このコードはサーブレットのエラーページに HttpServletResponse.sendError を使用して HTTP パラメータを直接書き込んでいます。 信頼できない入力を返すことは反射型 XSS(クロスサイトスクリプティング) 脆弱性を可能にします。
詳細は, http://en.wikipedia.org/wiki/Cross-site_scripting を参照してください。

SpotBugs は,XSS の最も露骨で自明なケースだけを探します。 SpotBugs が何かを見つけたなら,ほぼ間違いなく SpotBugs が報告しない多くの脆弱性があるでしょう。 XSS を心配するなら,商用の静的解析ツールかペネトレーションテストツールの使用を真剣に検討すべきです。

XSS: 反射型クロスサイトスクリプティング脆弱性があるサーブレット (XSS_REQUEST_PARAMETER_TO_SERVLET_WRITER)

このコードはサーブレットの出力に HTTP パラメータを直接書き込んでいます。これは反射型 XSS(クロスサイトスクリプティング) 脆弱性を可能にします。
詳細は, http://en.wikipedia.org/wiki/Cross-site_scripting を参照してください。

SpotBugs は,XSS の最も露骨で自明なケースだけを探します。 SpotBugs が何かを見つけたなら,ほぼ間違いなく SpotBugs が報告しない多くの脆弱性があるでしょう。 XSS を心配するなら,商用の静的解析ツールかペネトレーションテストツールの使用を真剣に検討すべきです。

XSS: 反射型クロスサイトスクリプティング脆弱性がある JSP (XSS_REQUEST_PARAMETER_TO_JSP_WRITER)

このコードはJSP の出力に HTTP パラメータを直接書き込んでいます。これは XSS(クロスサイトスクリプティング) 脆弱性を可能にします。
詳細は, http://en.wikipedia.org/wiki/Cross-site_scripting を参照してください。

SpotBugs は,XSS の最も露骨で自明なケースだけを探します。 SpotBugs が何かを見つけたなら,ほぼ間違いなく SpotBugs が報告しない多くの脆弱性があるでしょう。 XSS に関して心配しているなら商用の静的解析ツールかペネトレーションテストツールの使用を真剣に検討すべきです。

HRS: HTTP レスポンス分割脆弱性 (HRS_REQUEST_PARAMETER_TO_HTTP_HEADER)

このコードはHTTP ヘッダに HTTP パラメータを直接書き込んでいます。これは HRS(HTTP レスポンス分割) 脆弱性を可能にします。
詳細は, http://en.wikipedia.org/wiki/HTTP_response_splitting を参照してください。

SpotBugs は,HRS の最も露骨で自明なケースだけを探します。 SpotBugs が何かを見つけたなら,ほぼ間違いなく SpotBugs が報告しない多くの脆弱性があるでしょう。 HRS を心配するなら,商用の静的解析ツールかペネトレーションテストツールの使用を真剣に検討すべきです。

PT: サーブレットの絶対パストラバーサル (PT_ABSOLUTE_PATH_TRAVERSAL)

ソフトウェアは,制限されたディレクトリ内にあるパス名を構築するためにHTTPリクエストのパラメータを使いますが,パラメータはそのディレクトリの外にある場所に解決できる「/abs/path」のような絶対パスシーケンスを適切に無効にしていません。
詳細は, http://cwe.mitre.org/data/definitions/36.html を参照してください。

SpotBugs は,絶対パストラバーサルの最も露骨で自明なケースだけを探します。 SpotBugs が何かを見つけたなら,ほぼ間違いなく SpotBugs が報告しない多くの脆弱性があるでしょう。 絶対パストラバーサルを心配するなら,商用の静的解析ツールかペネトレーションテストツールの使用を真剣に検討すべきです。

PT: サーブレットの相対パストラバーサル (PT_RELATIVE_PATH_TRAVERSAL)

ソフトウェアは,制限されたディレクトリ内にあるパス名を構築するためにHTTPリクエストのパラメータを使いますが,パラメータはそのディレクトリの外にある場所に解決できる「.」のようなシーケンスを適切に無効にしていません。
詳細は, http://cwe.mitre.org/data/definitions/23.html を参照してください。

SpotBugs は,相対パストラバーサルの最も露骨で自明なケースだけを探します。 SpotBugs が何かを見つけたなら,ほぼ間違いなく SpotBugs が報告しない多くの脆弱性があるでしょう。 相対パストラバーサルを心配するなら,商用の静的解析ツールかペネトレーションテストツールの使用を真剣に検討すべきです。

Dm: ハードコードされた定数データベースパスワード (DMI_CONSTANT_DB_PASSWORD)

このコードはハードコードされた定数パスワードを使用してデータベース接続を作成しています。 ソースコードかコンパイルされたコードへアクセスできる人なら誰でも簡単にパスワードを知ることができてしまいます。

Dm: 空のデータベースパスワード (DMI_EMPTY_DB_PASSWORD)

このコードは空白または空のパスワードを使用してデータベース接続を作成しています。 これはデータベースがパスワードによって保護されていないことを示しています。

SQL: SQL の Statement の execute または addBatch メソッドに定数ではない文字列を渡している (SQL_NONCONSTANT_STRING_PASSED_TO_EXECUTE)

このメソッドは,動的に生成されるように思われる文字列で,SQL 文 の execute または addBatch メソッドを呼び出しています。 その代わりに PreparedStatement を使用することを検討してください。 効率的で,SQL インジェクション攻撃に強いです。

SQL: PreparedStatement が定数ではない文字列から生成されている (SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING)

このコードは定数ではない文字列から SQL の PreparedStatement を作成しています。 ユーザからのチェックされていない汚染されたデータがこの文字列を作る際に使われるなら, PreparedStatement で予想外で望ましくない何かをするために SQL インジェクションが使われる可能性があります。

危ないコード (STYLE)

紛らわしいコード,異常なコード,またはエラーを引き起こす方法で書かれたコードです。 たとえば,ローカル変数への無効な代入,switch 文のフォールスルー,未確認のキャスト,null とわかっている値の冗長な null チェックなどです。 より多くの誤検出を受け入れました。 SpotBugs の以前のバージョンでは,このカテゴリは Style として知られていました。

CAA: フィールドへの共変配列代入 (CAA_COVARIANT_ARRAY_FIELD)

共変型の配列がフィールドに割り当てられています。 紛らわしくて,次のコードのように他の型の参照が後で配列に格納されるなら,実行時に ArrayStoreException を引き起こすことがあります。

Number[] arr = new Integer[10];
arr[0] = 1.0;

作成した配列の型またはフィールド型を変更することを検討してください。

CAA: 共変配列がメソッドから返される (CAA_COVARIANT_ARRAY_RETURN)

共変型の配列がメソッドから返されます。 呼び出し元のコードが返された配列に他の型の参照を格納しようとするなら,実行時に ArrayStoreException を引き起こすことがあります。

作成した配列の型またはメソッドの戻り型を変更することを検討してください。

CAA: ローカル変数への共変配列代入 (CAA_COVARIANT_ARRAY_LOCAL)

共変型の配列がローカル変数に割り当てられています。 紛らわしくて,次のコードのように他の型の参照が後で配列に格納されるなら,実行時に ArrayStoreException を引き起こすことがあります。

Number[] arr = new Integer[10];
arr[0] = 1.0;

作成した配列の型またはローカル変数型を変更することを検討してください。

Dm: サポートされていないメソッドの呼び出し (DMI_UNSUPPORTED_METHOD)

このメソッド呼び出しのすべてのターゲットは UnsupportedOperationException をスローします。

Dm: Thread オブジェクトが Runnable が期待されているところに渡されている (DMI_THREAD_PASSED_WHERE_RUNNABLE_EXPECTED)

Thread オブジェクトが Runnable が期待されているメソッドへのパラメータとして渡されています。 これはかなり異常で,論理エラーを示すか,予想外の振る舞いの原因になることがあります。

NP: readLine メソッドの結果が null なのか確かめないで値を利用している (NP_DEREFERENCE_OF_READLINE_VALUE)

readLine メソッドの結果が null なのか確かめないで値を利用しています。 readLine メソッドは,それ以上読み出すテキスト行がなければ null を返すので, NullPointerException が発生します。

NP: readLine メソッドの結果をすぐに利用している (NP_IMMEDIATE_DEREFERENCE_OF_READLINE)

readLine メソッドの結果をすぐに利用しています。 readLine メソッドは,それ以上読み出すテキスト行がなければ null を返すので, NullPointerException が発生します。

RV: 符号付き32ビット整数の乱数の剰余 (RV_REM_OF_RANDOM_INT)

このコードは符号付き整数の乱数を生成して別の値を法とする剰余を計算しています。 乱数は負になり,剰余演算の結果も負になります。これが意図したことであることを確実にしてください。 その代わりに Random.nextInt(int) の使用を強く検討してください。

RV: ハッシュコードの剰余は負かもしれない (RV_REM_OF_HASHCODE)

このコードはハッシュコードを計算して別の値を法とする剰余を計算しています。 ハッシュコードは負になり,剰余演算の結果も負なります。

計算結果が負ではないことを確認したいなら,コードを変更する必要があるかもしれません。 除数が2の累乗であることがわかっているなら,代わりにビット演算を使用できます (すなわち, x.hashCode()%n の代わりに x.hashCode()&(n-1) を使用してください)。 これはおそらく,剰余を計算するより高速です。 除数が2の累乗であるということをわかっていないなら,剰余演算の結果の絶対値を取得してください (すなわち Math.abs(x.hashCode()%n))。

Eq: 異常な equals メソッド (EQ_UNUSUAL)

このクラスの equals メソッドは,引数の型が this オブジェクトの型と互換性があるこをチェックするために我々が認識しているパターンで何もしていません。 このコードは何も間違っていないかもしれませんが,レビューする価値があります。

Eq: スーパークラスの equals メソッドをオーバーライドしていないクラス (EQ_DOESNT_OVERRIDE_EQUALS)

このクラスは, equals メソッドを定義しているクラスを拡張してフィールドを追加していますが, equals メソッドを定義していません。 したがって,このクラスのインスタンスの等価性は,サブクラスと追加されたフィールドの同一性を無視します。 これが意図したことで,しかも, equals メソッドをオーバーライドする必要がないことを確実にしてください。 たとえ equals メソッドをオーバーライドする必要がないとしても,サブクラスのための equals メソッドが super.equals(o) を呼び出して結果を返すという事実を実証するためにいずれにしろ, equals メソッドをオーバーライドすることを検討してください。

NS: 非短絡論理の疑わしい使用 (NS_NON_SHORT_CIRCUIT)

このコードは短絡論理 (&&||) ではなく非短絡論理 (&|) を使用していると思われます。 非短絡論理は,左辺を知ることによって結果を推論できたとしても両側の式が評価されます。 これは効率が悪く,右辺の評価でエラーが発生するケースを左辺でガードしているなら,結果としてエラーになる可能性があります。

詳細については, The Java Language Specification を参照してください。

NS: 潜在的な非短絡論理の危険な使用 (NS_DANGEROUS_NON_SHORT_CIRCUIT)

このコードは短絡論理 (&&||) ではなく非短絡論理 (&|) を使用していると思われます。 さらに,左辺値によって右辺を評価したくない (例外のスローや演算が高くつく副作用があるため) と思っているのかもしれません。 非短絡論理は,左辺を知ることによって結果を推論できたとしても両側の式が評価されます。 これは効率が悪く,右辺の評価でエラーが発生するケースを左辺でガードしているなら,結果としてエラーになる可能性があります。

詳細については, The Java Language Specification を参照してください。

IC: 初期化が循環している (IC_INIT_CIRCULARITY)

バグインスタンスによって参照される2つのクラスのスタティックイニシャライザで循環が検出されました。 さまざまな予想外の振る舞いはそのような循環に起因することがあります。

IA: 潜在的な継承されたメソッドなのか外部のメソッドなのかあいまいなメソッドの呼び出し (IA_AMBIGUOUS_INVOCATION_OF_INHERITED_OR_OUTER_METHOD)

内部クラスは,継承されたメソッドか外部クラスで定義されたメソッドなのかどちらとも解釈できるメソッドを呼び出しています。 たとえば, foo(17) を呼び出します。それはスーパークラスと外部のメソッドの両方で定義されています。 Java のセマンティックスでは,継承したメソッドを呼び出しますが,これは意図したことではないかもしれません。

本当に継承されたメソッドを呼び出すつもりなら super を付けて (例:super.foo(17)) 呼び出してください。 そうすれば,外部クラスのメソッドではなく継承されたメソッドを呼び出したいことがこのコードを読む人と SpotBugs に明確になります。

this.foo(17) を呼び出す場合は,継承されたメソッドが呼び出されます。 しかしながら,SpotBugs はクラスファイルを見るだけなので, this.foo(17)foo(17) の呼び出しの違いを見分けることができません。 潜在的なあいまいな呼び出しについて文句を言うでしょう。

Se: サブクラスで継承できない private な readResolve メソッド (SE_PRIVATE_READ_RESOLVE_NOT_INHERITED)

このクラスは, privatereadResolve メソッドを定義しています。 そのため,このメソッドはサブクラスで継承できません。 これが意図したことなら間違っていないかもしれませんが確認するためにレビューすべきです。

Se: Serializable ではないクラスの transient フィールド (SE_TRANSIENT_FIELD_OF_NONSERIALIZABLE_CLASS)

フィールドは, transient と宣言していますが,クラスは直列化可能ではないので,まったく効果がありません。 クラスが transient だったときの名残かもしれません,または直列化機構を誤解しているのかもしれません。

SF: 1つの case が次の case へと通り抜ける switch 文を見つけた (SF_SWITCH_FALLTHROUGH)

このメソッドには1つの case が次の case へと通り抜ける switch 文があります。 通常は, breakreturn でこの case を終わらせる必要があります。

SF: default がない switch 文を見つけた (SF_SWITCH_NO_DEFAULT)

このメソッドには default がない switch 文があります。 通常は, default を用意する必要があります。

解析は生成されたバイトコードを見るだけなので, defaultswitch 文の終わりにあって,他のケースに break 文が含まれていないなら誤検出のトリガーとなります。

UuF: 未使用の public または protected フィールド (UUF_UNUSED_PUBLIC_OR_PROTECTED_FIELD)

このフィールドは決して使用されません。 フィールドが publicprotected なので,多分,それは解析の一部として見えないクラスで使用されることを意図しています。 そうでなければ,クラスから除去することを検討してください。

UrF: 読み出されない public または protected フィールド (URF_UNREAD_PUBLIC_OR_PROTECTED_FIELD)

このフィールドは決して読み出されません。 フィールドが publicprotected なので,多分,それは解析の一部として見えないクラスで使用されることを意図しています。 そうでなければ,クラスから除去することを検討してください。

QF: 複雑か巧妙か間違ったインクリメントの for ループ (QF_QUESTIONABLE_FOR_LOOP)

本当にこの for ループが正しい変数をインクリメントしていますか? 別の変数が for ループによって初期化されてチェックされるように見えます。

NP: 書き込まれていない public または protected フィールドの読み出し (NP_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD)

プログラムは,決して null 値ではない値を書き込むと思われない public または protected フィールドの null 値を利用しています。 フィールドが解析によって見られないメカニズムを通して初期化されないかぎり,この値を利用すると NullPointerException が発生します。

UwF: コンストラクタで初期化されていないフィールドを null チェックなしで null 値を利用している (UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR)

このフィールドは,どんなコンストラクタの中でも決して初期化されません。したがって,オブジェクトが構築された後, null である可能性があります。 どこかほかで,値がロードされて, null チェックなしで null 値が利用されます。 フィールドが初期化される前に利用されると NullPointerException が発生するので,誤りか疑わしい設計かもしれません。

UwF: 書き込まてれいない public または protected フィールド (UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD)

この public または protected フィールドは書き込まれていません。このフィールドからの読み出しはデフォルト値を返します。 誤りをチェックしてください (フィールドは初期化すべきでしたか?)。役に立たないなら除去してください。

UC: 役に立たない空ではない void メソッド (UC_USELESS_VOID_METHOD)

我々の解析は,この空ではない void メソッドが実際に有用な仕事を行わないことを示しています。 確認してください。おそらくそのコードが間違っているか,またはボディを完全に除去できます。

我々はできる限り誤検出を減らそうと努力しているが,いくつかのケースでは警告は間違っているかもしれません。 よくある誤検出例です。

  • メソッドは,副作用を持つかもしれないクラスのロードをトリガーすることを意図している
  • メソッドは,暗黙のわかりにくい例外をスローするように意図されている

UC: 条件は効果がない (UC_USELESS_CONDITION)

この条件は前に絞られた関係している変数の値と同じ結果を常に作り出します。 おそらく何かほかのことを意味していたのか,あるいは条件を除去できます。

UC: 条件は変数型のために効果がない (UC_USELESS_CONDITION_TYPE)

この条件は関係している変数の型範囲のために同じ結果を常に作り出します。 おそらく何かほかのことを意味していたのか,あるいは条件を除去できます。

UC: 役に立たないオブジェクトを作成した (UC_USELESS_OBJECT)

我々の解析でオブジェクトが役に立たないことを示しています。 作成され,変更されていますが,値はメソッドの外に出ないし,副作用をもたらしません。 間違いかオブジェクトが使われることを意図していたかのどちらか,あるいは除去できます。

この解析はめったに誤検出することはありません。よくある誤検出のケースです。

  • 暗黙のうちに曖昧な例外をスローした
  • コードを一般化してスタブとして使用された
  • 弱/ソフト参照オブジェクトへの強い参照を持っていた

UC: 役に立たないオブジェクトをスタックで作成した (UC_USELESS_OBJECT_STACK)

このオブジェクトは副作用を持たない変更を行うために作成されています。 おそらく何かほかのことを意味していたのか,あるいはオブジェクトを除去できます。

RV: メソッドは戻り値を無視しています。これは間違いではないですか? (RV_RETURN_VALUE_IGNORED_INFERRED)

このコードはメソッドを呼び出して,戻り値を無視しています。 戻り値は,メソッドが呼び出される型と同じ型です。そして,我々の解析から戻り値が重要であるかもしれないように見えます (たとえば, String.toLowerCase() の戻り値を無視するような)。

我々は,戻り値を無視することがメソッド本体の単純な解析から悪い考えかもしれないと推測しています。 このメソッドの戻り値を無視することが重要であるか許容できるかどうかに関して,SpotBugs に指示する @CheckReturnValue アノテーションが使えます。

戻り値を無視することが間違いではないか決めるために厳密に調査してください。

RV: 副作用がないメソッドの戻り値は無視される (RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT)

このコードはメソッドを呼び出して戻り値を無視しています。 しかしながら,解析はメソッド (もしあればサブクラスの実装も含む) が戻り値以外の効果をもたらさないことを示しています。 この呼び出しは除去できます。

我々は,できる限り誤検出を減らそうとしていますが,いくつかのケースではこの警告が間違っているかもしれません。 よくある誤検出です。

  • メソッドは,オーバライドされ解析対象外の他のプロジェクトで副作用がもたらされるように設計されている
  • メソッドは,副作用をもたらすかもしれないクラスローダをトリガーするように呼び出されている
  • メソッドは,例外を取得するために呼び出されている

我々の仮定が正しくないと感じるなら,SpotBugs にこのメソッドの戻り値が無視されることを許容するように指示する @CheckReturnValue アノテーションを使用することができます。

RV: String.indexOf の結果が正かどうか確かめている (RV_CHECK_FOR_POSITIVE_INDEXOF)

このメソッドは String.indexOf を呼び出して結果が正かどうか確かめています。 結果が負かどうか確かめるほうがはるかに一般的です。チェックされる部分文字列が String の先頭以外の場所で出現するときだけ正になります。

RV: readLine メソッドの結果を null ではないのか確かめた後で捨てている (RV_DONT_JUST_NULL_CHECK_READLINE)

readLine メソッドの戻り値を null ではないのか確かめた後で捨てています。 ほとんどすべての状況で,結果が null ではないなら戻り値を使用したいでしょう。 再び readLine メソッドを呼び出すと異なる行が得られます。

NP: パラメータは 非 null でなければならないが null 可能としてマークされている (NP_PARAMETER_MUST_BE_NONNULL_BUT_MARKED_AS_NULLABLE)

このパラメータは,常に 非 null にすることを要求する方法で使われていますが,パラメータには明示的に Nullable アノテーションが付けられています。 パラメータかアノテーションのどちらかの使い方が間違っています。

NP: null になっている可能性があるメソッドの戻り値を利用している (NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE)

メソッドからの戻り値を null チェックしないで利用しています。メソッドの戻り値は null なのかチェックすべきです。 コードが実行されると NullPointerException を引き起こすことがあります。

NP: null 値を実行不可能かもしれない分岐で利用している可能性がある (NP_NULL_ON_SOME_PATH_MIGHT_BE_INFEASIBLE)

そこで分岐または文が実行されるなら, null 値が利用されて NullPointerException が発生します。 もちろん,問題は分岐または文が実行不可能で, NullPointerException が決して発生する可能性がないということかもしれません。 それを決めるのは SpotBugs の能力を超えています。 この値が既に null であることを検査したという事実からこれは明確な可能性です。

NP: null とわかっている値のロード (NP_LOAD_OF_KNOWN_NULL_VALUE)

ここで参照されている変数は,以前に null なのかチェックしているため null であることがわかっています。 これは有効ですが,間違いかもしれません (多分異なる変数を参照することを意図していました。あるいは,以前の null チェックで null ではないのか確かめるべきでした)。

PZLA: null ではなく長さが0の配列を返すことを検討する (PZLA_PREFER_ZERO_LENGTH_ARRAYS)

結果がないこと (すなわち,結果の空のリスト) を示すために null 参照ではなく長さが0の配列 を返すことは,多くの場合より良い設計です。 このように,メソッドのクライアントは明示的に null チェックをする必要はありません。

一方,「この質問に対する答えがない」ことを示すために null を使用することはおそらく適切です。 たとえば, File.listFiles() は,ファイルがないディレクトリを与えられた場合は空のリストを返し,ファイルがディレクトリではないなら null を返します。

UCF: 役に立たない制御フロー (UCF_USELESS_CONTROL_FLOW)

このメソッドには分岐するのかどうかに関係なく,制御フローが同じ場所へと続く,役に立たない制御フロー文があります。
たとえば,これは 空の if 文が原因になります。

if (argv.length == 0) {
    // TODO: handle this case
}

UCF: 次の行へ続くだけの役に立たない制御フロー (UCF_USELESS_CONTROL_FLOW_NEXT_LINE)

このメソッドには分岐するのかどうかに関係なく,制御フローが同じか次の行へと続く,役に立たない制御フロー文があります。
多くの場合,不注意に if 文の本体を空文を使用したことが原因になります。

if (argv.length == 1);
    System.out.println("Hello, " + argv[0]);

RCN: null とわかっている値の冗長な null チェック (RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE)

このメソッドには null とわかっている値の冗長な null チェックがあります。

RCN: null ではないことがわかっている値の冗長な null チェック (RCN_REDUNDANT_NULLCHECK_OF_NONNULL_VALUE)

このメソッドには null ではないことがわかっている値の冗長な null チェックがあります。

RCN: 2つの null 値の冗長な比較 (RCN_REDUNDANT_COMPARISON_TWO_NULL_VALUES)

このメソッドには両方とも明らかに null とわかっている2つの参照の冗長な比較があります。

RCN: 非 null 値と null 値との冗長な比較 (RCN_REDUNDANT_COMPARISON_OF_NULL_AND_NONNULL_VALUE)

このメソッドには null ではないことがわかっている参照と null とわかっている別の参照との比較があります。

SA: ローカル変数の自己代入 (SA_LOCAL_SELF_ASSIGNMENT)

このメソッドにはローカル変数の自己代入があります。
たとえば次のようなコードです。

public void foo() {
    int x = 3;
    x = x;
}

そのような代入は役に立たないので,論理エラーかタイプミスかもしれません。

INT: 1を法とする整数の剰余 (INT_BAD_REM_BY_1)

どんな式 (exp % 1) も常に0を返すことが保証されています。 そうではなく, (exp & 1) または (exp % 2) を意味していましたか?

INT: 整数値の無意味な比較 (INT_VACUOUS_COMPARISON)

常に同じ値を返す整数の比較があります (たとえば x <= Integer.MAX_VALUE)。

INT: 整数値の無意味なビットマスク演算 (INT_VACUOUS_BIT_OPERATION)

どんな有用な仕事もしない整数ビット演算 (AND,OR,XOR) です (たとえば v & 0xffffffff)。

SA: ローカル変数の二重代入 (SA_LOCAL_DOUBLE_ASSIGNMENT)

このメソッドにはローカル変数の二重代入があります。
たとえば次のようなコードです。

public void foo() {
    int x,y;
    x = x = 17;
}

変数に同じ値を2回代入することは役に立たないので,論理エラーかタイプミスかもしれません。

SA: フィールドの二重代入 (SA_FIELD_DOUBLE_ASSIGNMENT)

このメソッドにはフィールドの二重代入があります。
たとえば次のようなコードです。

int x,y;
public void foo() {
    x = x = 17;
}

フィールドに2回代入することは役に立たないので,論理エラーかタイプミスかもしれません。

DLS: return 文に役に立たない代入がある (DLS_DEAD_LOCAL_STORE_IN_RETURN)

この文は, return 文でローカル変数に代入をしています。この代入は効果がありません。 この文が正しいことを確かめてください。

DLS: ローカル変数への無効な代入 (DLS_DEAD_LOCAL_STORE)

この命令はローカル変数に値を代入していますが,値は読み出されないか以降の命令でも使われません。 多くの場合,計算された値が決して使われないので,これは誤りを示します。

Sun の javac コンパイラが final なローカル変数のためにしばしば無効な格納を生成することに注意してください。 SpotBugs は,バイトコードベースのツールなので誤検出をなくす簡単な方法がありません。

DLS: フィールドを遮るローカル変数への無効な代入 (DLS_DEAD_LOCAL_STORE_SHADOWS_FIELD)

この命令は,ローカル変数に値を代入していますが,値は読み出されないか以降の命令でも使われません。 多くの場合,計算された値が決して使われないので,これは誤りを示します。 フィールドがローカル変数と同じ名前です。そうではなく,フィールドに代入するつもりでしたか?

DLS: ローカル変数への無効な null 代入 (DLS_DEAD_LOCAL_STORE_OF_NULL)

このコードはローカル変数に null を代入していますが代入された値は読み出されていません。 この代入はガベージコレクタを手伝うために導入されたのかもしれませんが,Java SE 6 ではもはや必要とされないか有用ではありません。

REC: 例外がスローされないのに例外をキャッチしている (REC_CATCH_EXCEPTION)

このメソッドは,例外オブジェクトをキャッチする try-catch ブロックを使用していますが,例外は try ブロックの中でスローされません。また,実行時例外は明示的にキャッチされません。 それぞれの catch ブロックが同一である多くの例外型をキャッチすることの短縮形として try { ... } catch (Exception e) { something } を使用することが共通のバグパターンです。 しかし,この構文は誤って実行時例外も同様にキャッチするので,潜在的なバグを隠します。

より良いアプローチは,明示的にキャッチするよりもスローされる特定の例外をスローします。 または,次に示すように明示的に RuntimeException をキャッチ,再スローして,非実行時例外をキャッチします。

try {
    ...
} catch (RuntimeException e) {
    throw e;
} catch (Exception e) {
    ... deal with all non-runtime exceptions ...
}

FE: 浮動小数点の等価性のためのテスト (FE_FLOATING_POINT_EQUALITY)

この演算は,等価性のために2つの浮動小数点値を比較しています。 浮動小数点の計算は丸めを伴うかもしれないので計算された floatdouble の値は正確ではないかもしれません。 通貨のような正確でなければならない値のために BigDecimal のような固定精度型を使用することを検討してください。 正確である必要がない値のためにいくつかの範囲の中で等価性のために比較することを検討してください。 たとえば, if (Math.abs(x - y) < .0000001)
詳細は Java 言語仕様4.2.4を参照してください。

CD: クラス間の循環依存関係のテスト (CD_CIRCULAR_DEPENDENCY)

このクラスは,他のクラスと循環依存関係があります。 それぞれが他のクラスの正確な構築に依存していて,クラスの構築を難しくしています。 難しい依存関係を断つためにインタフェースの使用を検討してください。

RI: スーパークラスと同じインタフェースを実装しているクラス (RI_REDUNDANT_INTERFACES)

このクラスは,スーパークラスによっても実装されるインタフェースを実装することを宣言しています。 スーパークラスがインタフェースを実装するので,これは冗長です。デフォルトですべてのサブクラスもこのインタフェースを実装します。 このクラスが作成されてから継承階層が変わったことを指摘するかもしれません。インタフェースの実装の所有権を考慮すべきです。

MTIA: Struts Action を拡張したクラスでのインスタンス変数の使用 (MTIA_SUSPECT_STRUTS_INSTANCE_FIELD)

Struts Action クラスを拡張したクラスで,インスタンス変数を使用しています。 Struts Action クラスの1つのインスタンスだけが Struts フレームワークによって作成され,マルチスレッドによって使われるので,このパラダイムは極めて問題があり,推奨できません。 ローカル変数を使用することだけを検討してください。 モニタを除いて書き込まれるインスタンスフィールドだけが報告されます。

MTIA: Servlet クラスを拡張したクラスでのインスタンス変数の使用 (MTIA_SUSPECT_SERVLET_INSTANCE_FIELD)

Servlet クラスを拡張したクラスで,インスタンス変数を使用しています。 Servlet クラスの1つのインスタンスだけが Java EE フレームワークによって作成され,マルチスレッドによって使われるので,このパラダイムは極めて問題があり,推奨できません。 ローカル変数を使用することだけを検討してください。

PS: 公開インタフェースで同期化とセマフォを暴露するクラス (PS_PUBLIC_SEMAPHORES)

このクラスは,自分自身 (this 参照) で, wait メソッド, notify メソッド, notifyAll メソッド とともに同期化しています。 このクラスを使用するクライアントクラスは,同期化のためのオブジェクトとしてこのクラスのインスタンスをさらに使用するかもしれません。 2つのクラスが同期化のために同じオブジェクトを使用するので,マルチスレッドの正確性は疑わしいです。 公開参照で同期化もセマフォメソッドの呼び出しもすべきではありません。 同期化の制御には内部の公開されないメンバ変数を使用することを検討してください。

ICAST: 整数乗算の結果を long にキャストしている (ICAST_INTEGER_MULTIPLY_CAST_TO_LONG)

このコードは次のように整数の乗算を実行してから結果を long に変換しています。

long convertDaysToMilliseconds(int days) { return 1000*3600*24*days; }

long を使用して乗算をすれば,結果がオーバーフローするという可能性を回避できます。
たとえば次のように修正できます。

long convertDaysToMilliseconds(int days) { return 1000L*3600*24*days; }

または

static final long MILLISECONDS_PER_DAY = 24L*3600*1000;
long convertDaysToMilliseconds(int days) { return days * MILLISECONDS_PER_DAY; }

ICAST: 整数の除算の結果を double または float にキャストしている (ICAST_IDIV_CAST_TO_DOUBLE)

このコードは整数の除算の結果を double または float にキャストしています。 整数で除算をすることは,ゼロに最も近い整数値まで結果を切り捨てます。 結果が double にキャストされたという事実は,この精度が維持されるべきだったことを示唆しています。 おそらく意味されたことは,除算を実行する前にオペランドの1つまたは両方を double にキャストすることでした。
次に例を示します。

int x = 2;
int y = 5;
// Wrong: yields result 0.0
double value1 = x / y;

// Right: yields result 0.4
double value2 = x / (double) y;

BC: 具象コレクションへの疑わしいキャスト (BC_BAD_CAST_TO_CONCRETE_COLLECTION)

このコードは抽象コレクション (たとえば, CollectionListSet) を特定の具象実装 (たとえば, ArrayListHashSet) にキャストしています。 これは正しくないかもしれません。そして,将来の時点で他の具象実装への切り替えをとても困難にするので,脆弱なコードになるかもしれません。 そうするための特別な理由がないかぎり抽象コレクションクラスを使用してください。

BC: 未チェック/未確認のキャスト (BC_UNCONFIRMED_CAST)

このキャストはチェックされていません。すべての型のインスタンスをキャストする型へキャストできるわけではありません。 プログラムのロジックがこのキャストが失敗しないことを確実に確認してください。

BC: メソッドからの戻り値の未チェック/未確認のキャスト (BC_UNCONFIRMED_CAST_OF_RETURN_VALUE)

このコードはメソッドの戻り値の未確認のキャストを実行しています。 コードは,キャストが安全であることが保証されるようにメソッドを呼び出しているかもしれませんが,SpotBugs はキャストが安全であることを検証できません。 プログラムのロジックがこのキャストが失敗しないことを確実に確認してください。

BC: 常に true を返す instanceof (BC_VACUOUS_INSTANCEOF)

この instanceof は常に true を返します (テストしている値が null ではないかぎり)。 これは安全で,誤解や論理エラーを指摘していないことを確認してください。 本当に null なのか値をテストしたいなら,多分, instanceof ではなく null テストをしたほうが良く,より明確になります。

BC: 抽象コレクションへの疑わしいキャスト (BC_BAD_CAST_TO_ABSTRACT_COLLECTION)

このコードは Collection を抽象コレクションにキャストしています (たとえば ListSetMap)。 オブジェクトがキャストする型であるということが保証されていることを確認してください。 必要とするコレクションの反復処理ができるなら Set または List にキャストする必要はありません。

IM: 負数で機能しない奇数チェック (IM_BAD_CHECK_FOR_ODD)

このコードは x % 2 == 1 を使用して値が負数なのか確かめていますが,負数 (たとえば, (-5) % 2 == -1) なので機能しません。 奇数チェックを意図しているなら, x & 1 == 1 または x % 2 != 0 を使用することを検討してください。

IM: 平均の計算はオーバーフローする可能性がある (IM_AVERAGE_COMPUTATION_COULD_OVERFLOW)

このコードは除算か符号付き右シフトを使用して2つの整数の平均を計算して,結果を配列の添字として使用しています。 平均値が非常に大きいならオーバーフローする可能性があります (結果として負の平均の計算になる)。 結果が負ではないことを意図していたなら,その代わりに符号なし右シフトを使用できます。 つまり, (low+high)/2 ではなく (low+high) >>> 1 を使用してください。

このバグは,二分探索とマージソートの多くの以前の実装で存在します。 Martin Buchholz が JDK ライブラリのバグを発見して修正しています。 Joshua Bloch が バグパターンとして公表しました

BSHIFT: 符号なし右シフトを short/byte にキャストしている (ICAST_QUESTIONABLE_UNSIGNED_RIGHT_SHIFT)

このコードは符号なしキャストの実行結果を short または byte にキャストしています。結果の上位ビットは捨てられます。 上位ビットが捨てられるので,符号付きと符号なし右シフト (シフトのサイズによって) との違いがないかもしれません。

DMI: ハードコードされた絶対パス名への参照がある (DMI_HARDCODED_ABSOLUTE_FILENAME)

このコードはハードコードされた絶対パス名を使用して File オブジェクトを構築しています (たとえば new File("/home/dannyc/workspace/j2ee/src/share/com/sun/enterprise/deployment");)。

DMI: substring(0) の呼び出しは元の値を返す (DMI_USELESS_SUBSTRING)

このコードは文字列で substring(0) を呼び出していますが,元の値を返します。

ST: インスタンスメソッドから static フィールドへの書き込み (ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD)

このインスタンスメソッドは, static フィールドに書き込みをしています。 複数のインスタンスが操作されているなら,正しくさせるのは難しいです。一般的にバッドプラクティスです。

DMI: ObjectOutput に書き込まれる非直列化可能オブジェクト (DMI_NONSERIALIZABLE_OBJECT_WRITTEN)

このコードは ObjectOutput.writeObject に非直列化可能オブジェクトを渡していると思われます。 このオブジェクトが本当に非直列化可能なら,エラーを招きます。

DB: 2つの分岐のために同じコードを使用しているメソッド (DB_DUPLICATE_BRANCHES)

このメソッドは,条件分岐の2つの分岐を実装するために同じコードを使用しています。これがコーディングミスではないことを確認してください。

DB: switch 文の2つの case のために同じコードを使用しているメソッド (DB_DUPLICATE_SWITCH_CLAUSES)

このメソッドは, switch 文の2つの case を実装するために同じコードを使用しています。 複製コードの case かもしれないし,コーディングミスかもしれません。

XFB: XMLインタフェースの特定の実装のインスタンスを作成しているメソッド (XFB_XML_FACTORY_BYPASS)

このメソッドは,XMLインタフェースの特定の実装のインスタンスを作成しています。 提供されたファクトリクラスを使用してオブジェクトを作成して実行時に実装を変更できるようにすることが望ましいです。
詳細は,次を参照してください。

  • javax.xml.parsers.DocumentBuilderFactory
  • javax.xml.parsers.SAXParserFactory
  • javax.xml.transform.TransformerFactory
  • org.w3c.dom.Document.createXXXX

USM: 親クラスのメソッドに過剰に委譲しているメソッド (USM_USELESS_SUBCLASS_METHOD)

この派生メソッドは,単に受け取られる正確なパラメータを渡している同じスーパークラスのメソッドを呼び出すだけです。 このメソッドは,付加価値が与えられないので除去できます。

USM: 実装されたインタフェースで既に定義された抽象メソッド (USM_USELESS_ABSTRACT_METHOD)

この抽象メソッドは,この抽象クラスによって実装されるインタフェースで既に定義されています。 このメソッドは,付加価値が与えられないので除去できます。

CI: final なクラスが protected フィールドを宣言している (CI_CONFUSED_INHERITANCE)

このクラスは, final と宣言されていますが,フィールドは protected と宣言されています。 クラスは fainal なので派生できません。protected の使用は紛らわしいです。 フィールドのためのアクセス修飾子は,フィールドの真の用途を表すため, privatepublic に変更すべきです。

TQ: 値は型修飾子を必要としないが,不明としてマークされている (TQ_EXPLICIT_UNKNOWN_SOURCE_VALUE_REACHES_NEVER_SINK)

値は,型修飾子によって示された値ではないことを必要とする方法で使われています。 しかし,値はどこでその型修飾子がいるのか禁止されていのるかわからないと述べている明示的なアノテーションがあります。 使い方かアノテーションのどちらかが間違っています。

TQ: 値は型修飾子を必要としているが,不明としてマークされている (TQ_EXPLICIT_UNKNOWN_SOURCE_VALUE_REACHES_ALWAYS_SINK)

値は,常に型修飾子によって示された値であることを必要とする方法で使われています。 しかし,値はどこでその型修飾子が必要なのかわからないと述べている明示的なアノテーションがあります。 使い方かアノテーションのどちらかが間違っています。

NP: メソッドは戻り値の nullness アノテーションを緩和している (NP_METHOD_RETURN_RELAXING_ANNOTATION)

メソッドは,オーバーライドするメソッドの契約を常に実装すべきです。 したがって,メソッドが @Nonnull 値を返すようにアノテーションが付けられているならば,サブクラスでメソッドが @Nullable または @CheckForNull 値を返すようにアノテーションが付けられたメソッドをオーバーライドすべきでありません。 そうすると,メソッドが null を返すべできではないという契約に違反します。

NP: メソッドはパラメータに nullness アノテーションを強化している (NP_METHOD_PARAMETER_TIGHTENS_ANNOTATION)

メソッドは,オーバーライドするメソッドの契約を常に実装すべきです。 したがって,メソッドが @Nullable としてマークされるパラメーターを取るならば,サブクラスでパラメーターを @Nonnull にしてメソッドをオーバーライドすべきでありません。 そうすると,メソッドが null パラメータを処理する必要があるという契約に違反します。