低速ディテクタです。
]]>this.getClass().getResource(...)
の使用を探します。
]]>
中速ディテクタです。
]]>java.net.URL
の equals と hashCode メソッドはドメイン名の解決をします。
その結果、これらの演算はかなり高くつきます。このディテクタは、メソッドが呼び出されるかもしれない場所を探します。
]]>
(x == 5 || x == 5)
のような繰り返される条件テストを含んでいるコードを探します。
]]>
equals
メソッドを定義しているクラスと互換性がないクラスのインスタンスをオペランドにしてチェックする equals
メソッドをチェックします。
]]>
Logger
を保持するのに弱参照が使われます。
]]>
このディテクタは、新しいディテクタをテストするためのフックです。通常このディテクタは何もしません。
]]>||
と &&
の代わりに |
と &
)。
]]>
中速ディテクタです。
]]>Comparator
を実装するクラスを書くためのイディオムの違反を探します。
]]>
substring(0)
) に渡されている間違った引数を探します。
]]>
finalize
メソッドの呼び出しと他のファイナライザ関連の問題を探します。
]]>
hashCode
メソッドと equals
メソッドの定義の問題を探します。
]]>
equals
メソッドをオーバーライドする equals
メソッドを探します。
]]>
notify
メソッドの呼び出を探します。
]]>
Thread.run()
の呼び出しを探します。
高速ディテクタです。
]]>wait
メソッドを探します。
]]>
wait
メソッドの呼び出しを探します。
低速ディテクタです。
]]>wait
メソッドの呼び出しを探します。
]]>
InputStream.read()
または InputStream.skip()
の呼び出しを探します。
]]>
wait
メソッドの呼び出しを探します。
]]>
低速ディテクタです。
]]>低速ディテクタです。
]]>低速ディテクタです。
]]>java.util.concurrent
) のロックを獲得したのにメソッドからのすべての経路で解除されないロックを探します。
中速ディテクタです。
補助クラスパスに java.util.concurrent パッケージ (またはパッケージ自体を解析している) が必要であることに注意してこのディテクタを使用してください
]]>java.lang.String
のような型のクラスの参照値を比較することは一般的に誤りです。
低速ディテクタです。
]]>
wait
メソッド、notify
メソッド、notifyAll
メソッドの呼び出しを探します。
中速ディテクタです。
このディテクタは、まだ開発中で、あまりに多くの誤検出が発生するので、無効にされています。
]]>低速ディテクタです。
]]>中速ディテクタです。
]]>中速ディテクタです。
]]>toArray(T[] a)
メソッドに長さが0の配列を渡してコレクションを配列に変換するコードを探します。
]]>
Adapter
クラスを拡張して、間違ったシグネチャで Listener
メソッドをオーバーライドするコードを探します。
]]>
ResultSet
の getXXX または setXXX メソッドの呼び出しを探します。
ResultSet
の列インデックス番号は1で始まるので、これは常に間違いです。
]]>
init
メソッドの前まで初期化されないので、これらのメソッドはコンストラクタで失敗します。
]]>
Thread.interrupted()
の呼び出しを探します。
Thread.currentThread().interrupted()
から呼び出されるなら、役に立たない行為なので Thread.interrupted()
を使用します。
しかしながら、interrupted
メソッドは常にカレントスレッドで呼び出されるので、任意のスレッドオブジェクトで呼び出すのはほぼ間違いなく誤りです。
]]>
execute
メソッドの呼び出しを探すためにデータフロー解析を使います。
]]>
中速ディテクタです。
]]>keySet
イテレータから取り出されたキーを使用して Map
エントリの値にアクセスするコードを探します。
]]>
高速ディテクタです。
]]>低速ディテクタです。
]]>java.lang.Math
の static メソッドを呼び出すコードを探します。
その代わりに定数を使用する方がより高速で、ときにはより正確です。
]]>
wait
メソッド、notify
メソッド、notifyAll
メソッドを使用する public クラスを探します。
これは public クラスの同期化実装を暴露することになります。public クラスの利用者は、利用者のクラスで public クラスのインスタンスを同期化オブジェクトとして使うかもしれません。
これはベース実装に大惨事をもたらします。
]]>
ObjectOutput
の writeObject
メソッドに渡される非 Serializable オブジェクトを探します。
]]>
Thread.sleep()
の呼び出しを探します。
低速ディテクタです。
]]>おそらく、新しいパラダイムにクラスのすべてを完全に変更することではなく、クラスの使用中の変化が原因となりました。
]]>低速ディテクタです。
]]>低速ディテクタです。
]]>低速ディテクタです。
]]>高速ディテクタです。
]]>有効にしないでください。
]]>java.lang.Object
を受け取る総称型コレクションメソッドへの呼び出しの引数を見ます。
無関係なクラス型による引数は決してコレクションの中に格納されることはありません。
たとえば、foo
が List<String>
で、bar
が StringBuffer
なら foo.contains(bar)
の呼び出しは常に false を返すことになります。
高速ディテクタです。
]]>Calendar
は、マルチスレッドでの使用は本質的に安全ではないので、このディテクタは、java.util.Calendar
や java.text.DateFormat
(サブクラスも) の static フィールドについて警告します。
]]>
デフォルトでは有効にされません。
]]>ConcurrentMap
の putIfAbsent
メソッドの結果が無視されるなら、2番目の引数として渡された値が再利用されていないことをチェックします。
]]>
new BigDecimal(0.1)
と書くと、0.1と正確に等しい BigDecimal (スケールが1でスケールなしの値が1) が作成されると思うかもしれませんが、
実際には0.1000000000000000055511151231257827021181583404541015625と等しくなります。
おそらく BigDecimal.valueOf(double d)
メソッドの使用が望ましいです。BigDecimal(たとえば、BigDecimal.valueOf(0.1)
は0.1を与えます) を作成するためには double の文字列表現を使用します。
ScheduledThreadPoolExecutor
は決して何も実行しません。
最大プールサイズへの変更は無視されます。ScheduledThreadPoolExecutor
は ThreadPoolExecutor
から継承されますが継承されたチューニングメソッドの一部は有用ではありません。
特に、corePoolSize スレッドとアンバウンド形式のキューを使用する固定サイズプールとして動作するので、maximumPoolSize の調整は有用な効果がありません。UnsupportedOperationException
をスローします。
]]>
FindBugs は、HRS の最も露骨で自明なケースだけを探します。 FindBugs が何かを派遣したならほぼ間違いなく FindBugs が報告しないより多くの脆弱性があるでしょう。 HRS を心配するなら、商用の静的解析ツールかペネトレーションテストツールの使用を真剣に検討するべきです。
]]>FindBugs は、HRS の最も露骨で自明なケースだけを探します。 FindBugs が何かを見つけたならほぼ間違いなく FindBugs が報告しないより多くの脆弱性があるでしょう。 HRS を心配するなら、商用の静的解析ツールかペネトレーションテストツールの使用を真剣に検討するべきです。
]]>FindBugs は、相対パストラバーサルの最も露骨で自明なケースだけを探します。 FindBugs が何かを見つけたならほぼ間違いなく FindBugs が報告しないより多くの脆弱性があるでしょう。 相対パストラバーサルを心配するなら、商用の静的解析ツールかペネトレーションテストツールの使用を真剣に検討するべきです。
]]>FindBugs は、相対パストラバーサルの最も露骨で自明なケースだけを探します。 FindBugs が何かを見つけたならほぼ間違いなく FindBugs が報告しないより多くの脆弱性があるでしょう。 相対パストラバーサルを心配するなら、商用の静的解析ツールかペネトレーションテストツールの使用を真剣に検討するべきです。
]]>FindBugs は、XSS の最も露骨で自明なケースだけを探します。 FindBugs が何かを見つけたならほぼ間違いなく FindBugs が報告しないより多くの脆弱性があるでしょう。 XSS を心配するなら、商用の静的解析ツールかペネトレーションテストツールの使用を真剣に検討するべきです。
]]>HttpServletResponse.sendError
を使用して HTTP パラメータを直接書き込んでいます。
信頼できない入力を返すことは反射型 XSS(クロスサイトスクリプティング) 脆弱性を可能にします。FindBugs は、XSS の最も露骨で自明なケースだけを探します。 FindBugs が何かを見つけたならほぼ間違いなく FindBugs が報告しないより多くの脆弱性があるでしょう。 XSS を心配するなら、商用の静的解析ツールかペネトレーションテストツールの使用を真剣に検討するべきです。
]]>FindBugs は、XSS の最も露骨で自明なケースだけを探します。 FindBugs が何かを見つけたならほぼ間違いなく FindBugs が報告しないより多くの脆弱性があるでしょう。 XSS に関して心配しているなら商用の静的解析ツールかペネトレーションテストツールの使用を真剣に検討するべきです。
]]>show
メソッド、setVisible
メソッド、pack
メソッドは、フレームのための関連したピアを作成します。
ピアの作成で、システムはイベントディスパッチスレッドを作成します。
これが問題になることがあります。なぜなら pack
メソッドと validate
メソッドがまだ処理中でもイベントディスパッチスレッドがリスナに通知できるからです。
この状況は、2つのスレッドが Swing コンポーネントにアクセスする可能性があり、デッドロックや、その他のスレッドに関する問題になる可能性がある重大な欠陥です。
pack
メソッドの呼び出しはコンポーネントを実体化させます。実体化しているときに、イベントディスパッチスレッドがリスナへの通知を開始する可能性があります。
]]>
StackOverflowException
をスローします。
]]>
this.getClass().getResource(...)
の呼び出しは予想外の結果をもたらす可能性があります。
]]>
x == 0 || x == 0
)。
多分、2つめの条件テストは何か他のことを意図しています (たとえば、x == 0 || y == 0
)。
]]>
putNextEntry
メソッドを呼び出して、closeEntry
メソッドをすぐにを呼び出しています。
これは空の ZIP ファイルエントリになります。
エントリデータは putNextEntry
メソッドと closeEntry
メソッドの呼び出しの間で ZIP ファイルに書き込むべきです。
]]>
putNextEntry
メソッドを呼び出して、 closeEntry
メソッドをすぐに呼び出しています。
これは空の JAR ファイルエントリになります。
エントリデータは putNextEntry
メソッドと closeEntry
メソッドの呼び出しの間で JAR ファイルに書き込むべきです。
]]>
IllegalMonitorStateException
は、一般的に設計上の欠陥 (ロックを保持していないオブジェクトで wait
メソッドまたは notify
メソッドを呼び出す) の場合にだけスローされます。
]]>
16777216.0f + 1.0f = 16777216.0f
。
その代わりに double の使用を検討してください。
]]>
Number[] arr = new Integer[10]; arr[0] = 1.0;
作成した配列の型またはフィールド型を変更することを検討してください。
]]>Number[] arr = new Integer[10]; arr[0] = 1.0;
作成した配列の型またはローカル変数型を変更することを検討してください。
]]>作成した配列の型またはメソッドの戻り型を変更することを検討してください。
]]>Cloneable
を実装していますが、clone
メソッドを定義していないか使用していません。
]]>
Cloneable
を実装していないのに clone
メソッドを定義しています。
これが OK (たとえば、サブクラスのクローンの実装を自分自身で制御したい場合です) という状況もありますが意図したことなのか確認してください。
]]>
super.clone()
を呼び出さない clone
メソッドを定義しています。
クラス A がサブクラス B によって拡張され、サブクラス B が super.clone()
を呼び出すなら、クラス B の clone
メソッドは、型 A のオブジェクトを返す可能性が高いです。
これは clone
のための汎用規約に違反します。
すべての clone
メソッドが super.clone()
を呼び出すなら Object.clone()
が呼び出されることが保証され、常に正しい型のオブジェクトが返されます。
Map
か Set
を使用しています。
URL の equals
と hashCode
は、ドメイン名の解決を行うので、ひどい性能になります。java.net.URI
を使用することを検討してください。
]]>
equals
メソッドと hashCode
メソッドは、ドメイン名の解決を行うので、ひどい性能になる可能性があります。java.net.URI
を使用することを検討してください。
]]>
@Retention(RetentionPolicy.RUNTIME)
でアノテートされなければ、リフレクション (たとえば、isAnnotationPresent(...)
メソッド) を使用して観測することができません。
]]>
System.exit(...)
を呼び出すことは、Java 仮想マシン全体をシャットダウンさせてしまいます。
それが適切な場合にだけ使用するべきです。
System.exit(...)
の呼び出しは、他のコードによる呼び出しを困難か不可能にします。
その代わりに RuntimeException をスローすることを検討してください。
]]>
System.runFinalizersOnExit
と Runtime.runFinalizersOnExit
を呼び出さないでください。
Java ライブラリで最も危険なメソッドの1つです。 -- Joshua Bloch
]]>
new String(String)
コンストラクタの使用はメモリを浪費します。
そのようにして構築されたオブジェクトと パラメータとして渡された String
は機能的に区別がつかないからです。
引数の String
をそのまま使用してください。
]]>
java.lang.String()
オブジェクトを作成するとメモリを浪費します。
そのようにして作成されたオブジェクトと空の文字列定数 ""
は機能的に区別がつかないからです。
Javaは、同一の文字列定数が同じ String
オブジェクトによって表されることを保証します。
したがって、直接空の文字列定数を使用するべきです。
]]>
String.toString()
を呼び出すのは冗長です。String
を使用してください。
]]>
過去に、close
メソッドや finalize
メソッドでガベージコレクタを明示的に呼び出していた状況は、巨大なパフォーマンスブラックホールの原因となりました。
ガベージコレクションは高くつきます。何百、何千ものガベージコレクションを強制する状況は、システムの停滞をもたらすでしょう。
java.lang.Boolean
の新しいインスタンスを作成するとメモリを浪費します。
Boolean
オブジェクトは不変で、2つの有用な値 (Boolean.TRUE
と Boolean.FALSE
) があります。
その代わりに Boolean.valueOf
メソッド (または J2SE 5.0 のオートボクシング) を使用して Boolean
オブジェクトを作成してください。
]]>
new Integer(int)
の使用は、常に新しいブジェクトになることが保証されています。
これに対して、Integer.valueOf(int)
は、コンパイラ、クラスライブラリ、Java 仮想マシンで値がキャッシュされます。
キャッシュに格納された値を使用することはインスタンスの作成を回避し、コードはより高速になります。
-128から127までの値は対応するキャッシュされたインスタンスを持つことが保証されています。
そして、valueOf
メソッドの使用は、コンストラクタを使用するより約3.5倍高速です。
定数範囲外の値は、両方のスタイルの性能は同じです。
クラスが J2SE 5.0より前の Java 仮想マシンとの互換性が不要なら、Long
、Integer
、Short
、Character
、Byte
のインスタンスを作成するときは、オートボクシングか valueOf
メソッドを使用してください。
new Double(double)
の使用は、常に新しいブジェクトになることが保証されています。
これに対して、Double.valueOf(double)
は、コンパイラ、クラスライブラリ、Java 仮想マシンで値がキャッシュされます。
キャッシュに格納された値を使用することはインスタンス生成を回避し、コードはより高速になります。
クラスが J2SE 5.0より前の Java 仮想マシンとの互換性が不要なら、オートボクシングか Double
、Float
の valueOf
メソッドを使用してください。
b ? e1 : e2
) の評価の一部として、別のプリミティブ型にアンボクシングされて変換されます。
Java 言語仕様では、e1
と e2
がラップされた数値なら値はアンボクシングされ、共通の型へと変換/型変換されます
(たとえば、e1
が Integer
で、e2
が Float
なら e1
はアンボクシング (int
に変換) され、float
に変換され、ボクシング (Float
に変換) されます)。
JLS セクション15.25を参照してください。
]]>
new Double(d).intValue()
)。
直接プリミティブ型の型変換を実行してください (たとえば (int) d
)。
]]>
toString
メソッドを呼び出すためにプリミティブ型のラッパクラスのインスタンスを作成しています。
それよりもプリミティブ値を引数にとる static な toString
メソッドを使用したほうが効率的です。
置換前 | 置換後 |
---|---|
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) |
getClass
メソッドを呼び出しています。
クラスリテラル (Foo.class
) を使うほうが簡単です。
]]>
java.util.concurrent.locks.Condition
オブジェクトで wait
メソッドを呼び出しています。
Condition
オブジェクトを待機させるためには Condition
インタフェースで定義された await
メソッドを使用するべきです。
]]>
Random.nextInt(n)
メソッドを使いたかったのでしょう。
]]>
Math.min(0, Math.max(100, value))
のような構文を使用して境界値を制限しようとしています。
しかしながら、定数の順序が間違っています。 Math.min(100, Math.max(0, value))
とすべきです。
結果としてこのコードは常に同じ結果 (もし値が NaN なら NaN) を作り出します。
]]>
java.util.Random
のインスタンス r
で、0
から n-1
の乱数を生成したいのであれば、(int)(r.nextDouble() * n)
ではなく r.nextInt(n)
を使用します。
nextInt
メソッドへの引数は整数でなければなりません。
たとえば、-99から0までの乱数を生成したいなら、-r.nextInt(100)
を使用してください。
execute
または addBatch
メソッドを呼び出しています。
その代わりに PreparedStatement
を使用することを検討してください。
効率的で、SQL インジェクション攻撃に強いです。
]]>
PreparedStatement
を作成しています。
ユーザからのチェックされていない汚染されたデータがこの文字列を作る際に使われるなら、PreparedStatement
で予想外で望ましくない何かをするために SQL インジェクションが使われる可能性があります。
]]>
Thread
クラスから派生した run
メソッドを指定していないか、Runnable
オブジェクトを渡すことなく、スレッドを作成しています。
このスレッドは、時間の無駄です。
]]>
この問題を直すために、最初にローカル変数をオブジェクトに格納して、完全に構築した後で volatile フィールドを保存することを考えてください。
]]>finalize
メソッドを除去するべきです。
]]>
finalize
メソッドは public ではなく、protected にすべきです。
]]>
finalize
メソッドは役に立たないので削除するべきです。
]]>
finalize
メソッドは、明示的にスーパークラスによって定義されたどんなファイナライザの効果も無効にします。
スーパークラスのために定義されたどんなファイナライザアクションも実行されません。
これが意図したことではない場合、メソッドを削除してください。
]]>
finalize
メソッドは、スーパークラスの finalize
メソッドを呼び出しているだけです。
冗長なので削除してください。
]]>
finalize
メソッドは、スーパークラスの finalize
メソッドを呼び出していません。
したがって、スーパークラスのために定義されたどんなファイナライザアクションも実行されません。
super.finalize()
の呼び出しを追加してください。
]]>
finalize
メソッドの呼び出しがあります。
ファイナライザは Java 仮想マシンによって1度だけ実行されることになっているので、これは間違った考えです。
参照によってつながった複数のオブジェクトがファイナライズ可能になると、Java 仮想マシンはすべてのオブジェクトの finalize
メソッドを呼び出します。
おそらく異なるスレッドで同時にです。
したがって、クラス X の finalize
メソッドの中から X によって参照されているオブジェクトの finalize
メソッドを呼び出すのは、とりわけ間違った考えです。
なぜなら、オブジェクトが既に別のスレッドによってファイナライズされているかもしれないからです。
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
メソッドを実現するのはとても難しいので、バッドプラクティスと見なされています。
プロパティがなければまったく予想していない振る舞いが起こりえます。
equals
メソッドを定義することは、ひどいバッドプラクティスです。
2つの異なる列挙値が equals
メソッドでは「等価ではない」と判定され、共変な equals
メソッドでは「等価」と判定されるからです。
共変な equals
メソッドを定義しないでください。
]]>
equals
メソッドを定義していますが、 equals(Object)
メソッドは java.lang.Object
クラスから継承しています。
クラスは、boolean equals(Object)
メソッドを定義するべきです。
]]>
equals
メソッドを定義していますが、java.lang.Object
クラスの equals(Object)
メソッドをオーバーライドしていません。
クラスは、boolean equals(Object)
メソッドを定義するべきです。
]]>
equals
メソッドを定義していますが、java.lang.Object
クラスの equals(Object)
メソッドをオーバーライドしていません。
その代わりに、スーパークラスから equals(Object)
メソッドを継承して、boolean equals(Object)
メソッドを定義するべきです。
]]>
equals
メソッドを定義しているクラスを拡張してフィールドを追加していますが、equals
メソッドを定義していません。
したがって、このクラスのインスタンスの等価性は、サブクラスと追加されたフィールドの同一性を無視します。
これが意図したことで、しかも、equals
メソッドをオーバーライドする必要がないことを確実にしてください。
たとえ equals
メソッドをオーバーライドする必要がないとしても、サブクラスのための equals
メソッドが super.equals(o)
を呼び出して結果を返すという事実を実証するためにいずれにしろ、equals
メソッドをオーバーライドすることを検討してください。
]]>
equals
メソッドを定義しています。
java.lang.Object
の equals
メソッドを正しくオーバーライドするためには equals
メソッドのパラメータの型は、java.lang.Object
でなければなりません。
]]>
equals
メソッドをオーバーライドする equals
メソッドを定義しています。
両方の equals
メソッドは、2つのオブジェクトが等しいかどうかの判定で、instanceof
を使用しています。
equals
メソッドは対称的 (a.equals(b) == b.equals(a)
) であることが重要なのでこれは危険を伴っています。
B が A のサブタイプなら A の equals
メソッドは引数が instanceof A
なのかチェックします。
そして、B の equals
メソッドは引数が instanceof B
なのかチェックします。
これらのメソッドによって定義された同値関係が対称的でないということです。
]]>
equlas
メソッドがあります。
equals
メソッドは、クラスリテラルを引数のクラスと比較しています (たとえば、Foo
クラスで Foo.class == o.getClass()
のような判定を行っています)。
this.getClass() == o.getClass()
の方がより良いです。
]]>
equals
メソッドは、引数の型が this
オブジェクトの型と互換性があるこをチェックするために我々が認識しているパターンで何もしていません。
このコードは何も間違っていないかもしれませんが、レビューする価値があります。
]]>
equals
メソッドを定義しています。
これは想像力に富むが、あまり良い方法とはいえません。さらに、equals
メソッドが対称的ではないことを意味します。
]]>
equlas
メソッドを定義しています。
これはオブジェクトがそれ自身と等価ではないことを意味していて、このクラスの有用な Map や Set を作成できません。
より根本的に、equals
メソッドの要件の一つである反射性を満たしていないことになります。
おそらく意図されたことは、オブジェクトはそれ自身と等価であるというオブジェクト同一性です。
これは Object
クラスから継承される振る舞いです。
異なるスーパークラスから継承される equals
メソッドをオーバーライドする必要があるなら以下のようなコードが使えます。
]]>public boolean equals(Object o) { return this == o; }
JDK はこのバグを解決してサイズを1MB減らすことができました。
詳細は、JDK bug 6447475 を参照してください。
equals(Object)
メソッドの実装は引数として渡されている null をチェックしていないので、java.lang.Object.equals()
で定義された規約に違反しています。
すべての equals
メソッドは引数に null が渡されたなら false を返すべきです。
]]>
compareTo
または compare
メソッドの戻り値を無効にしています。
これは疑わしいかバッドプログラミングプラクティスです。戻り値が Integer.MIN_VALUE なので、戻り値を無効にすることは結果の符号を無効にしません。
結果を無効にするのではなくオペランドの順序を逆にすることによって、同じ意図した結果を得ることができます。
]]>
compareTo
または compare
メソッドは Integer.MIN_VALUE を返します。ひどいバッドプラクティスです。
compareTo
メソッドの戻り値で重要なことは結果の符号だけです。
しかし、結果の符号を無効にすることを期待して、compareTo
メソッドの戻り値を無効にすることがあります。
返された値が Integer.MIN_VALUE の場合を除いてです。 Integer.MIN_VALUE よりも-1を返してください。
]]>
compareTo
メソッドを定義しています。
Comparable
インタフェースの compareTo
メソッドを正しく実装するためには compareTo
メソッドのパラメータの型は、java.lang.Object
でなければなりません。
]]>
equals
メソッドを宣言していますが、hashCode
メソッドは java.lang.Object
から継承しています。
これは「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode
メソッドの汎用規約に従っていないのでハッシュ化できません。
]]>
equals(Object)
メソッドを定義していますが、hashCode
メソッドを定義していません。
これは「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode
メソッドの汎用規約に従っていません。
このクラスのインスタンスはハッシュデータ構造で使われています。最重要問題を修正する必要があります。
]]>
hashCode
メソッドを定義していますが、 equals
メソッドは java.lang.Object
から継承しています (オブジェクトの参照比較で等価性を判定します)。
これは「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode
メソッドの汎用規約に従っているかもしれませんが、
おそらく、hashCode
メソッドをオーバーライドすることによって意図されたことではありません。
(hashCode
メソッドをオーバーライドすることは、オブジェクトの同一性が単純な参照等価性よりも複雑な規約に基づくことを意味します)。
このクラスのインスタンスが HashMap/HashTable に決して代入されるだろうと思わないなら推奨される hashCode
メソッドの実装は以下のようになります。
]]>public int hashCode() { assert false : "hashCodeが呼び出されることは想定されていません。"; return 42; // 適当な値 }
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
と一貫性のない自然順序付けを持ちます」などと明示することをお勧めします。
hashCode
メソッドを定義していますが、equals
メソッドは定義していません。
これは「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode
メソッドの汎用規約に違反するかもしれません。
]]>
equals(Object)
をオーバーライドしていますが、hashCode
メソッドは java.lang.Object
から継承しています (同一性ハッシュコード (Java 仮想マシンによってオブジェクトに代入された任意の値) を返します)。
したがって、「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode
メソッドの汎用規約に違反するかもしれません。
このクラスのインスタンスが HashMap/HashTable に決して代入されるだろうと思わないなら推奨される hashCode
メソッドの実装は以下のようになります。
]]>public int hashCode() { assert false : "hashCodeが呼び出されることは想定されていません。"; return 42; // 適当な値 }
equals(Object)
メソッドを継承して、java.lang.Object
から hashCode
メソッドを継承しています (同一性ハッシュコード (Java 仮想マシンによってオブジェクトに代入された任意の値) を返します)。
したがって、「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode
メソッドの汎用規約に違反するかもしれません。
hashCode
メソッドを定義したくないまたはオブジェクトが HashMap/Hashtable に決して格納されないだろうと思っているなら UnsupportedOperationException
をスローする hashCode()
メソッドを定義してください。
equals(Object)
メソッドをオーバーライドしていますが、hashCode
メソッドはオーバーライドしていません。
したがって、「等価なオブジェクトは等価なハッシュコードを保持する必要がある」という hashCode
メソッドの汎用規約に違反するかもしれません。
]]>
equals
メソッドを定義しています。
java.lang.Object
の equals
メソッドを正しくオーバーライドするためには equals
メソッドのパラメータの型は、java.lang.Object
でなければなりません。
]]>
java.lang.String
オブジェクトを比較しています。
両方の文字列がソースファイルの定数か、String.intern()
を使用して正準化されていないかぎり、同じ文字列は2つの異なる String オブジェクトによって表されるかもしれません。
その代わりに equals(Object)
メソッドを使用することを検討してください。
]]>
java.lang.String
パラメータを比較しています。
文字列定数または正準化された文字列だけをメソッドに渡すことを呼び出し元に要求することは必要以上に脆弱で測定可能な性能の向上をもたらしません。
その代わりに equals(Object)
メソッドを使用することを検討してください。
]]>
compareTo
メソッドを定義しています。
Comparable
インタフェースの compareTo
メソッドを正しく実装するためには compareTo
メソッドのパラメータの型は、java.lang.Object
でなければなりません。
]]>
このバグパターンに合致する典型的なバグは、スレッドセーフを意図したクラスでメソッドを同期化させることを忘れていることです。
ディテクタがどこでフィールドが同期化なしでアクセスされると信じていたかを示すコードの場所に「非同期アクセス」というラベルがついているノードを選択できます。
不正確ないろいろな原因がこのディテクタにあることに注意してください。 たとえば、ディテクタはロックを保持されるすべての状況を静的に検出できるわけではありません。 また、ディテクタがロックされたアクセスとアンロックされたアクセスの区別が正確なときでも、問題のコードは依然として正しいかもしれません。
]]>notify
メソッドまたは notifyAll
メソッドへの呼び出しは可変オブジェクト状態にどんな (明らかな) 付随的な変更ももたらされませんでした。
一般的に別のスレッドが期待しているいくつかの条件が真になったので、モニタで notify
メソッドが呼び出されます。
しかしながら、意味がある条件のために両方のスレッドに見えるヒープオブジェクトを含まなければなりません。
可変オブジェクトの状態変更が通知があるメソッドを呼び出したメソッドで起こったかもしれないので、このバグが必ずしもエラーを示すというわけではありません。
]]>run
メソッドを呼び出しています。
一般的にクラスは新しいスレッドで自己の run
メソッドを呼び出してもらうために Runnable
インタフェースを実装します。
その場合は、Thread.start()
を呼び出すのが正しいです。
]]>
詳細については、the Java Language Specification を参照してください。
]]>詳細については、the Java Language Specification を参照してください。
]]>wait
メソッドを呼び出すと、待機しているオブジェクトのロックを解除するだけで、その他のロックは解除しません。
これは必ずしもバグではありませんが厳密に調べる価値があります。
]]>
java.lang.Object.wait()
の呼び出しがあります。
このコードは wait
メソッドを呼び出す前に待機するつもりだった条件が既に満たされていないことを確かめるべきです。
どんな前の通知も無視されます。
]]>
これはたくさんの具象クラスを作るためです。以下のクラスを検討してください。
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
の初期化されていない値が読み出されます。
foo
は null です。
]]>public class CircularClassInitialization { static class InnerClassSingleton extends CircularClassInitialization { static InnerClassSingleton singleton = new InnerClassSingleton(); } static CircularClassInitialization foo = InnerClassSingleton.singleton; }
java.util.Iterator
を実装しています。
しかしながら、next
メソッドは java.util.NoSuchElementException
をスローできません。
next
メソッドは、それ以上要素を返すことができないときは NoSuchElementException
をスローするように変更するべきです。
]]>
private static String LOCK = "LOCK"; synchronized(LOCK) { ... }
文字列定数は正準化され、Java 仮想マシンによってロードされたすべてのクラス全体で共有されます。
したがって、これは他のコードがロックしているかもしれない何かをロックしている可能性があります。
これはブロッキングとデッドロックの振る舞いの診断を難しくして、とても奇妙な結果になる可能性があります。
詳細は、http://www.javalobby.org/java/forums/t96352.html と http://jira.codehaus.org/browse/JETTY-352 を参照してください。
Boolean
のようなボクシングされたプリミティブ型の定数で同期化しています。
private static Boolean inited = Boolean.FALSE; synchronized(inited) { if (!inited) { init(); inited = Boolean.TRUE; } }
一般には2つの Boolean
オブジェクトだけが存在しています。
このコードは他の無関係なコードと同じオブジェクトで同期化している可能性があるので、無応答やデッドロックの原因になります。
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
オブジェクトを使用するように置き換えてしまい、非常に紛らわしい振る舞いと潜在的デッドロックの原因になります。
private static Integer count = 0; synchronized(count) { count++; }
Integer
オブジェクトはキャッシュして共有できます。
他の無関係なコードと同じオブジェクトで同期化している可能性があるので、無応答やデッドロックの原因になります。
CERT の CON08-J. Do not synchronize on objects that may be reused を参照してください。
]]>synchronized() { }
空の synchronized ブロックは巧妙で正しく使用するのは困難です。 空の synchronized ブロックはわざとらしくて決して良い解決策ではありません。
]]>このバグパターンに合致する典型的なバグは、スレッドセーフを意図したクラスでメソッドを同期化するのを忘れていることです。
不正確のいろいろなソースがこのディテクタにあることに注意してください。 たとえば、ディテクタはロックを保持されるすべての状況を静的に検出できるわけではありません。 また、ディテクタがロックされたアクセスとアンロックされたアクセスの区別が正確なときでも、問題のコードはまだ正しいかもしれません。
]]>]]>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; }
foo(17)
を呼び出します。それはスーパークラスと外部のメソッドの両方で定義されています。
Java のセマンティックスでは、継承したメソッドを呼び出しますが、これはあなたが意図したことではないかもしれません。
本当に継承されたメソッドを呼び出すつもりなら super を付けて (例:super.foo(17)) 呼び出してください。 そうすれば、外部クラスのメソッドではなく継承されたメソッドを呼び出したいことがこのコードを読む人と FindBugs に明確になります。
this.foo(17)
を呼び出す場合は、継承されたメソッドが呼び出されます。
しかしながら、FindBugs はクラスファイルを見るだけなので、this.foo(17)
と foo(17)
の呼び出しの違いを見分けることができません。
潜在的なあいまいな呼び出しについて文句を言うでしょう。
alpha.Foo
が beta.Foo
を拡張します)。
これは非常に紛らわしく、参照関係を解決するために import 文を見なければならなかったり、スーパークラスのメソッドをオーバーライドしないで誤ってメソッドを定義する状況を作り出します。
]]>
alpha.Foo
が beta.Foo
を継承しているような状況です)。
これは非常に紛らわしく、参照関係を解決するために import 文を見なければならなかったり、スーパークラスのメソッドをオーバーライドしないで誤ってメソッドを定義する状況を作り出します。
]]>
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)
メソッドは、クラス A
の f(Foo)
メソッドをオーバーライドしていません。
これは引数の型 Foo
が違うパッケージだからです。
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)
メソッドは、クラス A
の f(Foo)
メソッドをオーバーライドしません。
これは引数の型 Foo
が違うパッケージだからです。
この場合、サブクラスがスーパークラスのメソッドと同一のシグネチャでメソッドを定義しているので、おそらく理解できます。 しかしながら、そのようなメソッドは非常に紛らわしいです。 類似しているが同一ではないシグネチャのメソッドを除去するか、非推奨にすることを強く検討するべきです。
]]>hashcode()
という名前のメソッドを定義しています。
このメソッドは、java.lang.Object
の hashCode
メソッドを (おそらく意図的に) オーバーライドしていません。
]]>
tostring()
という名前のメソッドを定義しています。
このメソッドは、java.lang.Object
の toString
メソッドを (おそらく意図的に) オーバーライドしていません。
]]>
equal(Object)
という名前のメソッドを定義しています。
このメソッドは、java.lang.Object
の equals(Object)
を (おそらく意図的に) オーバーライドしていません。
]]>
java.io.InputStream.read()
(またはそのバリエーション) の戻り値を無視しています。
戻り値がチェックされないと呼び出し元は要求したバイト数よりも少ないバイト数を読み出した場合、正しく処理できません。
これは潜在的なバグで、多くのプログラムでは、入力ストリームからの読み出しは、通常要求した完全なデータ量を読み出しますが、散発的に失敗することがあります。
]]>
java.io.InputStream.skip()
の戻り値を無視しています。
戻り値がチェックされないと呼び出し元は要求したバイト数よりも少ないバイト数しかスキップしなかった場合、正しく処理できません。
これは潜在的なバグで、多くのプログラムでは、入力ストリームからのスキップは、通常要求した完全なデータ量をスキップをしますが、散発的に失敗することがあります。
しかしながら、バッファードストリーム での skip
メソッドはバッファのデータをスキップするので要求されたバイト数のスキップは常に失敗します。
]]>
readResolve
メソッドが直列化機構で認識されるためには static メソッドとして宣言してはいけません。
]]>
readResolve
メソッドを定義しています。
そのため、このメソッドはサブクラスで継承できません。
これが意図したことなら間違っていないかもしれませんが確認するためにレビューするべきです。
]]>
readResolve
メソッドが直列化機構で認識されるためには戻り値の型が Object
で宣言されなければなりません。
]]>
Serializable
インタフェースを実装して、カスタム直列化/直列化復元のためのメソッドを定義しています。
しかし、そのメソッドが private として宣言されていないので、直列化/直列化復元 API によって無視されます。
]]>
Externalizable
インタフェースを実装していますが、引数なしコンストラクタを定義していません。
Externalizable
オブジェクトが直列化復元されるときは、最初に引数なしコンストラクタを呼び出すことによって構築される必要があります。
このクラスには引数なしコンストラクタがないので、直列化と直列化復元は実行時に失敗します。
]]>
Serializable
インタフェースを実装していますが、そのスーパークラスは実装していません。
そのようなオブジェクトが直列化復元されるとき、スーパークラスのフィールドはスーパークラスの引数なしコンストラクタを呼び出すことによって初期化される必要があります。
スーパークラスには引数なしコンストラクタがないので、直列化と直列化復元は実行時に失敗します。
]]>
Serializable
インタフェースを実装していますが、serialVersionUID
フィールドを定義していません。
.class オブジェクトへの参照を追加するのと同じくらい簡単な変更でクラスに合成フィールドを追加します。
それは、残念ながら暗黙の serialVersionUID
を変えます (たとえば、String.class
への参照を追加すると、class$java$lang$String
という static フィールドを生成します)。
また、バイトコードコンパイラへの異なるソースコードは、クラスオブジェクトまたは内部クラスを参照するために生成される合成変数のために異なる命名規則を使用するかもしれません。
バージョンを横断する Serializable の相互運用性を保証するために明示的に serialVersionUID を追加することを検討してください。
]]>
Comparator
インタフェースを実装しています。
Serializable
インタフェースも実装するべきかどうか検討するべきです。
コンパレータが TreeMap
のような順序付きコレクションを構築するために使われるなら、コンパレータが直列化可能な場合だけ、TreeMap
は直列化可能です。
大部分のコンパレータがほとんど状態を持たないとしても直列化可能にすることは簡単で良い防衛的なプログラミングです。
]]>
解析は生成されたバイトコードを見るだけなので、default が switch 文の終わりにあって、他のケースに break 文が含まれていないなら誤検出のトリガーとなります。
]]>writeObject
メソッドがあります。
しかしながら、クラスのその他のメソッドは同期化していません。
]]>
readObject
メソッド を定義していますが、
直列化復元によって作成されるオブジェクトは1つのスレッドによってだけ到達可能です。
したがって、readObject
メソッドは同期化する必要がありません。
readObject
メソッドそのものが別のスレッドに見えるようになるオブジェクトの原因になっているなら非常に疑わしいコーディングスタイルの例です。
]]>
serialVersionUID
フィールドを定義しています。
直列化を目的としてバージョン UID を指定することを意図しているならフィールドは static とすべきです。
]]>
serialVersionUID
フィールドを定義しています。
直列化を目的としてバージョン UID を指定することを意図しているならフィールドは final とすべきです。
]]>
serialVersionUID
フィールドを定義しています。
直列化を目的としてバージョン UID を指定することを意図しているならフィールドは long とすべきです。
]]>
java.lang.Object
でもない非プリミティブ型のインスタンスフィールドを定義して、
Externalizable
インタフェースまたは readObject
メソッドと writeObject
メソッドを実装するように見えません。
また、Externalizable
インタフェースも実装していなくて、readObject
メソッドも writeObject
メソッドも定義していません。
非直列化可能オブジェクトがこのフィールドに格納されるならクラスのオブジェクトは正しく直列化復元されません。
]]>
できれば、内部クラスを static にして問題を解決するべきです。 外部クラスを直列化可能にすることで動作するかもしれないが、内部クラスのインスタンスを直列化することは外部クラスも常に直列化することを意味します。 本当に望むことですか。
]]>readLine
メソッドの結果が null なのか確かめないで値を利用しています。
readLine
メソッドは、それ以上読み出すテキスト行がなければ null を返すので、NullPointerException が発生します。
]]>
readLine
メソッドの結果をすぐに利用しています。
readLine
メソッドは、それ以上読み出すテキスト行がなければ null を返すので、NullPointerException が発生します。
]]>
java.lang.Object.wait()
を呼び出しています。
モニタが複数の条件のために使われるなら、呼び出し元が待機するつもりだった条件は実際には発生しないかもしれません。
]]>
java.util.concurrent.await()
(またはそのバリエーション) を呼び出しています。
オブジェクトが複数の条件のために使われるなら、呼び出し元が待機するつもりだった条件は実際には発生しないかもしれません。
]]>
notifyAll
メソッドではなく notify
メソッドを呼び出しています。
モニタが複数の条件のために多くの場合使われます。
notify
メソッドの呼び出しは1つのスレッドを起こすだけで起こされたスレッドは呼び出し元が満たした待機条件の1つではないかもしれないことを意味しています。
]]>
我々はできる限り誤検出を減らそうと努力しているが、いくつかのケースでは警告は間違っているかもしれません。 よくある誤検出例です。
- メソッドは、副作用を持つかもしれないクラスのロードをトリガすることを意図している
- メソッドは、暗黙のわかりにくい例外をスローするように意図されている
]]>この解析はめったに誤検出することはありません。よくある誤検出のケースです。
- 暗黙のうちに曖昧な例外をスローした
- コードを一般化してスタブとして使用された
- 弱/ソフト参照オブジェクトへの強い参照を持っていた
]]>String.indexOf
を呼び出して結果が正かどうか確かめています。
結果が負かどうか確かめるほうがずっと典型的です。チェックされる部分文字列が先頭以外の場所で出現するときだけ正になります。
]]>
readLine
メソッドの戻り値を null でないのか確かめた後で捨てています。
ほとんどすべての状況で、結果が null でないなら戻り値を使用したいでしょう。
再び readLine
メソッドを呼び出すと異なる行が得られます。
]]>
我々は、できる限り誤検出を減らそうとしていますが、いくつかのケースではこの警告が間違っているかもしれません。 よくある誤検出です。
- メソッドは、オーバライドされ解析対象外の他のプロジェクトで副作用がもたらされるように設計されている
- メソッドは、副作用をもたらすかもしれないクラスローダをトリガーするように呼び出されている
- メソッドは、例外を取得するために呼び出されている
我々の仮定が正しくないと感じるなら、FindBugs にこのメソッドの戻り値が無視されることを許容するように指示する @CheckReturnValue アノテーションを使用することができます。
]]>String.toLowerCase()
の戻り値を無視するような)。
我々は、戻り値を無視することがメソッド本体の単純な解析から悪い考えかもしれないと推測しています。 このメソッドの戻り値を無視することが重要であるか許容できるかどうかに関して、FindBugs に指示する @CheckReturnValue アノテーションが使えます。
戻り値を無視することが間違いではないか決めるために厳密に調査してください。
]]>String dateString = getHeaderField(name); dateString.trim();
プログラマは、trim
メソッドが dateString
によって参照される String オブジェクトが更新されると思っています。
しかし、String オブジェクトは不変で、trim
メソッドが新しい String オブジェクトを返すのに無視しています。
このコードは以下のように修正するべきです。
]]>String dateString = getHeaderField(name); dateString = dateString.trim();
File.delete()
はファイルをうまく削除できなかったなら、例外をスローするのではなく false を返します。
結果をチェックしないなら例外的戻り値を返すメソッドの呼び出しで予想外の振る舞いの合図に気づきません。
]]>
if (x < 0) { new IllegalArgumentException("x must be nonnegative"); }
おそらくプログラマの意図は、作成した例外をスローすることでした。
]]>if (x < 0) { throw new IllegalArgumentException("x must be nonnegative"); }
close
メソッドは、常に null 値のオブジェクトで呼び出されています。
この文が実行されるなら NullPointerException が発生します。
ここでクローズするべき何かを決してクローズしないという大きな危険性があります。
]]>
switch 文の default が多くの場合実行不可能なので FindBugs が例外経路である default を検討することに注意して下さい。
]]>switch 文の default が多くの場合実行不可能なので FindBugs が例外経路である default を検討することに注意して下さい。
]]>clone
メソッドは、いくつかの条件で null を返すと思われます。
しかし、clone
メソッドは決して null を返すのは許されません。
この経路が到達できないことを確信しているなら、代わりに AssertionError
をスローしてください。
]]>
toString
メソッドは、いくつかの条件で null を返すと思われます。
仕様を寛大に読むとこれが許されると解釈できるかもしれませんが、それはおそらく間違った考えで、他のコードが壊れる原因になる可能性があります。
null ではなく空の文字列または、いくつかの他の適切な文字列を返してください。
]]>
なお、if (x == null) throw new NullPointerException();
は x
の参照解除として扱われることに注意して下さい。
finally
ブロックを使用することは一般的に良い考えです。
]]>
finally
ブロックを使用することは一般的に良い考えです。
]]>
他方では、「この質問に対する答えがない」ことを示すために null を使用することはおそらく適切です。
たとえば、File.listFiles()
は、ファイルがないディレクトリを与えられた場合は空のリストを返し、ファイルがディレクトリでないなら null を返します。
if
文が原因になります。
]]>if (argv.length == 0) { // TODO: handle this case }
if
文の本体を空文を使用したことが原因になります。
]]>if (argv.length == 1); System.out.println("Hello, " + argv[0]);
This particular warning generally indicates that a value known not to be null was checked against null. While the check is not necessary, it may simply be a case of defensive programming.
]]>java.util.concurrent
) のロックを獲得していますが、メソッドからのすべての経路で解除していません。
一般的に JSR-166のロックを使用するための正しいイディオムは以下のようになります。
]]>Lock l = ...; l.lock(); try { // do something } finally { l.unlock(); }
java.util.concurrent
) のロックを獲得していますが、メソッドからのすべての例外経路で解除していません。
一般的に JSR-166のロックを使用するための正しいイディオムは以下のようになります。
]]>Lock l = ...; l.lock(); try { // do something } finally { l.unlock(); }
equals
メソッドです。
等価で識別可能なインスタンスを作成する可能性がありますが異なるオブジェクトなので == で比較しないでください。
参照によって一般に比較されるべきでないクラスの例は、java.lang.Integer
、java.lang.Float
などです。
]]>
equals
メソッドです。
等価で識別可能なインスタンスを作成する可能性がありますが異なるオブジェクトなので == で比較しないでください。
一般的に参照によって比較されるべきではないクラスの例は、java.lang.Integer
、java.lang.Float
などです。
]]>
Boolean.TRUE
と Boolean.FALSE
) だけですが、
new Boolean(b)
コンストラクタを使用して他の Boolean オブジェクトを作成する可能性があります。
そのようなオブジェクトを回避することは最高です。
しかし、それらが存在するなら、Boolean オブジェクトの等価性をチェックするために .equals(...)
ではなく == または != を使用しているなら異なる結果をもたらします。
]]>
equals(Object)
メソッドを呼び出していて、解析が実行時に異なるクラスのオブジェクトになることを示唆しています。
さらに、呼び出されるであろう equals メソッドの検査では、この呼び出しは常に false を返すか、
あるいは equals メソッドが対称 (Object クラスの equals のための契約に必要な性質) ではないことのどちらかを示唆しています。
]]>
equals(Object)
メソッドを呼び出しています。
そして、両方のインタフェースを実装する既知の非抽象クラスがありません。
したがって比較されている2つのオブジェクトは実行時に同じクラスのメンバである可能性が低いです (いくつかのアプリケーションクラスが解析できなかったか、動的クラスローディングが実行時に起こることができた場合を除く)。
equals
メソッドの規約によると、異なるクラスのオブジェクトは常に等しくないとして比較するべきです。
したがって、java.lang.Object.equals(Object)
によって定義される規約によれば、この比較の結果は実行時に常に false になります。
]]>
equals(Object)
メソッドを呼び出しています。
クラスは、そのクラスの非抽象サブクラスも含めてインタフェースを実装していません。
したがって比較されている2つのオブジェクトは実行時に同じクラスのメンバである可能性が低いです (いくつかのアプリケーションクラスが解析できなかったか、動的クラスローディングが実行時に起こることができた場合を除く)。
equals
メソッドの規約によると、異なるクラスのオブジェクトは常に等しくないとして比較するべきです。
したがって、java.lang.Object.equals(Object)
によって定義される規約によれば、この比較の結果は実行時に常に false になります。
]]>
equals(Object)
を呼び出しています。
equals
メソッドの規約によると、この呼び出しは常に false を返すはずです。
]]>
Object.wait()
を呼び出しています。
保持されるロックがない状態で、wait
メソッドを呼び出すことは、IllegalMonitorStateException
をスローすることになります。
]]>
Object.notify()
や Object.notifyAll()
を呼び出しています。
保持されるロックがない状態で、notify
メソッドや notifyAll
メソッドを呼び出すことは、IllegalMonitorStateException
をスローすることになります。
]]>
int foo; public void setFoo(int foo) { foo = foo; }
そのような代入は役に立ちません。そうではなく、フィールドに代入するつもりでしたか?
]]>public void foo() { int x = 3; x = x; }
そのような代入は役に立たないので、論理エラーかタイプミスかもしれません。
]]>int x; public void foo() { x = x; }
そのような代入は役に立たないので、論理エラーかタイプミスかもしれません。
]]>int x,y; public void foo() { x = x = 17; }
フィールドに2回代入することは役に立たないので、論理エラーかタイプミスかもしれません。
]]>public void foo() { int x,y; x = x = 17; }
変数に同じ値を2回代入することは役に立たないので、論理エラーかタイプミスかもしれません。
]]>Double.longBitsToDouble()
の呼び出しで、32ビット int 値が引数として渡されています。
これはほぼ間違いなく意図したことではありませんし意図した結果を与えることはほとんどありません。
]]>
Preconditions.checkNotNull("message", message)
は、引数を予約しました。チェックされる値は第一引数です。
]]>
java.util.Random
オブジェクトを作成して1つの乱数を生成するために使用して捨てています。
これはあまり良くない品質の乱数を作り出し、効率が悪いです。
できれば、Random
オブジェクトを1つだけ作成して保存されるようにコードを書き直してください。
そして、毎回新しい乱数は既存の Random
オブジェクトを呼び出して取得することが必要です。
生成された乱数が推測可能でないことが重要なら、乱数ごとに新しい Random
オブジェクトを作成してはいけません (値はあまりに簡単に推測可能です)。
その代わりに java.security.SecureRandom
の使用を強く検討するべきです (そして必要とされる乱数ごとに新しい SecureRandom
のオブジェクトを作成することを回避します)。
Integer.MIN_VALUE
なら結果は同様に負です (Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE
なので)。
(同じ問題は long 値でも同様に起きます)。
]]>
Integer.MIN_VALUE
なら結果は同様に負です (Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE
なので)。
文字列の2^32個に1個は Integer.MIN_VALUE
のハッシュコードを持っていて、「polygenelubricants」、「GydZG_」、「DESIGNING WORKHOUSES」が該当します。
Random.nextInt(int)
の使用を強く検討してください。
]]>
計算結果が負ではないことを確認したいなら、コードを変更する必要があるかもしれません。
除数が2の累乗であることがわかっているなら、代わりにビット演算を使用できます (すなわち、x.hashCode()%n
の代わりに x.hashCode()&(n-1)
を使用してください)。
これはおそらく、剰余を計算するより高速です。
除数が2の累乗であるということをわかっていないなら、剰余演算の結果の絶対値を取得してください (すなわち Math.abs(x.hashCode()%n)
)。
b
を範囲が0~255の符号なしバイトに変換するには 0xff & b
を使用してください。
]]>
v & 0xffffffff
)。
]]>
x <= Integer.MAX_VALUE
)。
]]>
(exp % 1)
も常に0を返すことが保証されています。
そうではなく、(exp & 1)
または (exp & 2)
を意味していましたか?
]]>
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)); }
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));
((event.detail & SWT.SELECTED) > 0)
のような式で比較しています。
ビット演算をより大きい演算子で比較することは、予想外の結果 (もちろん、SWT.SELECTED の値による) の原因になる可能性があります。
SWT.SELECTED が負数であるなら、これはバグの候補です。
SWT.SELECTED が負ではないとしても、'> 0' の代わりに '!= 0' を使用することが良いプラクティスであると思われます。
]]>
((val & CONSTANT) > 0)
のようなビット演算式で比較しています。
ビット演算をより大きい演算子で比較することは、予想外の結果の原因になる可能性があります。比較は期待したようになりません。
'> 0' の代わりに '!= 0' を使用することが良いプラクティスです。
]]>
(e & 0)
形式の式を0と比較しています。それは、常に等価であることを比較します。論理エラーかタイプミスかもしれません。
]]>
(e | C)
形式の式を D と比較しています。
定数 C と D の特定の値のために常に等しくないことを比較します。論理エラーかタイプミスかもしれません。
典型的に、このバグは、ビットセットで帰属関係のテストを実行したいコードで発生します。 しかし、ビット論理積演算子 ("&") の代わりにビット論理和演算子 ("|") を使用しています。
こうしたバグは (e & (A | B)) == C
が意図されている間に ((e & A) | B) == C
のように解析される (e & A | B) == C
のような式で現れるかもしれません。
たとえメソッドが複数のスレッドによって決して呼び出されないと確信していても、 それは、フィールドに設定している値が完全にデータを読み込まれるか初期化されるまで、 static フィールドを設定しないほうが良いかもしれません。
]]>java.util.concurrent.locks.Lock
を実装したオブジェクトで同期化しています。
そのようなオブジェクトは synchronized (...)
構文よりも acquire()
/release()
を使用してロックとロックの解除をします。
]]>
await()
メソッド、signal
メソッド、signalAll
メソッドを提供するオブジェクト
(たとえば、util.concurrent の Condition オブジェクト) で、wait
メソッド、notify
メソッド、notifyAll
メソッドを呼び出しています。
これはおそらくあなたが望むことではありません。たとえそれを望むとしても、他の開発者が非常に紛らわしいことを理解して、設計を変更することを検討するべきです。
]]>
synchronized
の使用とは違う互換性のないそれら自身の並行制御メカニズムを持っています。
たとえば、AtomicBoolean
で同期しても、他のスレッドが AtomicBoolean
を変更するのを防ぎません。
そのようなコードは正しいかもしれないが、将来コードを維持しなければならない人々を混乱させるかもしれないので慎重にレビューし文書化するべきです、
]]>String
を構築していると思われます。
各々の繰り返しにおいて、String
は StringBuffer
/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();
Connection.prepareStatement
に不変の引数を渡して呼び出しています。
PreparedStatement
を複数回実行する必要があるなら、それぞれのループの繰り返しで再生成する理由がありません。
ループの外に呼び出しを移動します。
]]>
NodeList.getLength()
を呼び出し、NodeList
は、getElementsByTagName
の呼び出しによって作られます。
NodeList
は長さを格納しませんが、毎回とても最適ではない方法で計算されます。
ループの前に変数に長さを格納することを検討してください。
]]>
Pattern.compile
に不変の定数を渡して呼び出しています。
Pattern
を複数回使用する必要があるなら、それぞれのループの繰り返しでコンパイルする理由がありません。
ループの外に呼び出しを移動するか static final フィールドにします。
]]>
Pattern.compile
を使用して正規表現をプリコンパイルするのが最適でしょう。
]]>
myString.indexOf(".")
の代わりに myString.indexOf('.')
を呼び出します。
]]>
myString.lastIndexOf(".")
の代わりに myString.lastIndexOf('.')
を呼び出します。
]]>
myCollection.toArray(new Foo[myCollection.size()])
を使用するほうがより効率的です。
渡される配列がコレクションの要素のすべてを格納できるくらいの大きさなら、データが読み込まれて、そのまま返されます。
これは結果として返す2番目の配列 (リフレクションによって) を作成する必要を回避します。
]]>
run
メソッドで JUnit アサーションが実行されています。失敗した JUnit アサーションは例外をスローします。
したがって、この例外がテストメソッドを実行したスレッド以外のスレッドで発生するなら、例外はスレッドを終了させますが、テストの失敗になりません。
]]>
setUp
メソッドを実装しています。
setUp
メソッドは、super.setUp()
を呼び出すべきなのにそうしていません。
]]>
tearDown
メソッドを実装しています。
tearDown
メソッドは、super.tearDown()
を呼び出すべきなのにそうしていません。
]]>
suite
メソッドを実装しています。
suite
メソッドは static として宣言するべきなのにそうしていません。
]]>
suite
メソッドを実装しています。
しかしながら、suite
メソッドは、
public static junit.framework.Test suite()
か
public static junit.framework.TestSuite suite()
のどちらかを宣言する必要があります。
]]>ResultSet
の getXXX、updateXXX メソッドを呼び出しています。
ResultSet
のインデックスは1から開始するので、これは常に間違いです。
]]>
PreparedStatement
の setXXX メソッドを呼び出しています。
インデックスは1から開始するので、これは常に間違いです。
]]>
init
メソッドが呼び出されるまで AppletStub は初期化されないので、これらのメソッドは正しく機能しません。
]]>
.equals(Object o)
を呼び出しています。
比較されているものが違う型なら等しくないことであることが保証されているので、比較はほぼ間違いなく誤りです。
たとえそれらが両方とも配列だったとしても、配列の equals
メソッドは2つの配列が同じオブジェクトだと決定するだけです。
配列のコンテンツを比較するためには java.util.Arrays.equals(Object[], Object[])
を使用してください。
]]>
.equals(Object o)
を呼び出しています。
配列は、Object
の equals
メソッドをオーバーライドしないので、配列で equals
メソッドを呼び出すことはアドレスを比較することと同じです。
配列のコンテンツを比較するためには java.util.Arrays.equals(Object[], Object[])
を使用してください。
配列のアドレスを比較するために明示的に ==
を使用して参照等価性をチェックすることは、それほど紛らわしくないでしょう。
]]>
.equals(Object o)
を呼び出しています (たとえば、String[]
と StringBuffer[]
、String[]
と int[]
) 。
それらは、決して等価ではありません。
さらに、equals(...)
が配列を比較するのに使用されるとき、それらが同じ配列であるかどうか確かめるだけで、配列のコンテンツは無視します。
]]>
interrupted
メソッドを呼び出すために Thread.currentThread()
を呼び出しています。
interrupted
メソッドは static メソッドなので、Thread.interrupted()
を使用するほうが単純明解です。
]]>
Thread.interrupted()
を呼び出しています。
interrupted
メソッドは static なので、作成者が意図したこととは異なるオブジェクトで呼び出されます。
]]>
Sun の javac コンパイラが final なローカル変数のためにしばしば無効な格納を生成することに注意してください。 FindBugs は、バイトコードベースのツールなので誤検出をなくす簡単な方法がありません。
]]>return x++;
のような return 文があります。
接頭辞インクリメント/デクリメントは 式の値に影響を与えないので、インクリメント/デクリメントは効果がありません。
この文が正しいのか確かめてください。
]]>
Foo.class
への参照は Foo
のためのスタティックイニシャライザが既に実行されていないなら実行することを強制します。
J2SE 5.0 ではそうしません。
より多くの詳細と例と J2SE 5.0 のクラスの強制的な初期化の方法の提案は Sun の article on Java SE compatibility を参照してください。
]]>Map.get(key)
ルックアップを回避するのでより効率的です。
]]>
try { ... } catch (Exception e) { something }
を使用することが共通のバグパターンです。
しかし、この構文は誤って実行時例外も同様にキャッチするので、潜在的なバグを隠します。
より良いアプローチは、明示的にキャッチするよりもスローされる特定の例外をスローします。 あるいは、以下に示すように明示的に RuntimeException をキャッチ、再スローして、非実行時例外をキャッチします。
]]>try { ... } catch (RuntimeException e) { throw e; } catch (Exception e) { ... deal with all non-runtime exceptions ... }
if (x == Double.NaN)
)。
しかしながら、NaN
の特別な意味のため、値は NaN
と等価ではありません。
したがって、x == Double.NaN
は常に false と評価します。
x
という値が特別な非数値であるかどうか確かめるためには Double.isNaN(x)
を使用します (または x
が浮動小数点精度であるなら Float.isNaN(x)
)。
]]>
BigDecimal
のような固定精度型を使用することを検討してください。
正確である必要がない値のためにいくつかの範囲の中で等価性のために比較することを検討してください。
たとえば、if (Math.abs(x - y) < .0000001)
。java.lang.Math
の static メソッドを呼び出しています。
このメソッドの結果は静的に判定でき、より高速で、ときには定数を使用するほうがより正確です。メソッド | パラメータ |
---|---|
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 |
wait
メソッド、notify
メソッド、notifyAll
メソッド とともに同期化しています。
このクラスを使用するクライアントクラスは、同期化のためのオブジェクトとしてこのクラスのインスタンスをさらに使用するかもしれません。
2つのクラスが同期化のために同じオブジェクトを使用するので、マルチスレッドの正確性は疑わしいです。
同期化するべきでもないし、公開参照でセマフォメソッドも呼び出すべきではありません。
同期化の制御には内部の公開されないメンバ変数を使用することを検討してください。
]]>
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; }
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); }
Math.round()
に渡して引数に最も近い int/long を返します。
整数を float に変換すると小数部がない数値が得られるので、この演算は常にノーオペレーションになります。
Math.round()
に渡される値を生成した演算が浮動小数点演算を使用して実行することを意図した可能性が高いです。
]]>
Math.ceil()
に渡しています。
整数を double に変換すると小数部がない数値が得られるので、この演算は常にノーオペレーションになります。
Math.ceil()
に渡される値を生成した演算が倍精度浮動小数点演算を使用して実行することを意図した可能性が高いです。
]]>
]]>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;
ObjectOutput.writeObject
に非直列化可能オブジェクトを渡していると思われます。
このオブジェクトが本当に非直列化可能なら、エラーを招きます。
]]>
formatter.format("%<s %s", "a", "b")
が実行されると MissingFormatArgumentException をスローします。
]]>
String.format("%d", "1")
は、文字列 "1" が書式指示子 "%d" と互換性がないので例外を生成します。
]]>
Arrays.asList(...)
を使用して配列をラップすることを検討してください。
]]>
System.out.println("%d\n", "hello");
の %d 書式指示子は数値の引数を必要としますが数値ではなく文字列が渡されています。
この文が実行されると実行時例外が発生します。
]]>
equals(Object o)
メソッドは、o
の型についてどんな仮定もするべきではありません。
o
が this
と同じ型でないなら単に false を返すべきです。
]]>
List
、Set
、Map
)。
オブジェクトがキャストする型であるということが保証されていることを確認してください。
必要とするコレクションの反復処理ができるなら Set または List にキャストする必要はありません。
]]>
Object[]
より特定の型のコレクションで toArray
メソッドを呼び出す結果をキャストしています。
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 []
を返します。
FindBugs はそのようなケースを検出して抑止しようとしますが、見落としているかもしれません。
s.replaceAll(".", "/")
は、すべての文字が '/' 文字に置換された String を返すs.split(".")
は、常に長さが0の String 配列を返す"ab|cd".replaceAll("|", "/")
は、"/a/b/|/c/d/"
を返す"ab|cd".split("|")
は、6個の要素がある配列を返す: [, a, b, |, c, d]
File.separator
を使用しています。
これは File.separator
がバックスラッシュである Windows プラットホームでは失敗します。
バックスラッシュは正規表現ではエスケープ文字として解釈されます。
その他の選択肢としては、File.separator
の代わりに File.separatorChar=='\\' ? "\\\\" : File.separator
を使用できます。
]]>
i++
) を実行してすぐに上書きしています。
たとえば、i = i++
は元の値をインクリメントした値で上書きします。
]]>
hashCode
メソッドを呼び出しています。
配列で hashCode
メソッドを呼び出すことは、System.identityHashCode と同じ値を返すので、コンテンツと配列の長さを無視します。
配列 a
のコンテンツによるハッシュコードを必要とするなら、java.util.Arrays.hashCode(a)
を使用してください。
]]>
toString
メソッドを呼び出しています。「[C@16f0472」のようなかなり役に立たない結果を生成します。
配列のコンテンツを与え、読める文字列に変換するために Arrays.toString()
を使用することを検討してください。toString
メソッドを呼び出しています。「[C@16f0472」のようなかなり役に立たない結果を生成します。
配列のコンテンツを与え、読める文字列に変換するために Arrays.toString()
を使用することを検討してください。(low+high)/2
ではなく (low+high) >>> 1
を使用してください。
このバグは、二分探索とマージソートの多くの以前の実装で存在します。 Martin Buchholz が JDK ライブラリのバグを発見して修正しています。 Joshua Bloch が バグパターンとして公表しました。
]]>x % 2 == 1
を使用して値が負数なのか確かめていますが、負数 (たとえば、(-5) % 2 == -1
) なので機能しません。
奇数チェックを意図しているなら、x & 1 == 1
または x % 2 != 0
を使用することを検討してください。
]]>
new File("/home/dannyc/workspace/j2ee/src/share/com/sun/enterprise/deployment");
)。
]]>
substring(0)
を呼び出していますが、元の値を返します。
]]>
hasNext
メソッドは、next
メソッドを呼び出しています。
hasNext
メソッドは、イテレータの状態を変更することになっていないので、ほぼ確実に間違っています。
next
メソッドがイテレータの状態を変更することになっています。
]]>
Thread.sleep()
を呼び出しています。
他のスレッドがロックを獲得するために待機しているかもしれないので、ひどい性能とスケーラビリティ、またはデッドロックの原因になるかもしれません。
ロックで wait
メソッドを呼び出すことはかなり良い考えで、ロックを解除して他のスレッドが実行するのを許可します。
]]>
Foo
と Bar
クラスがサブタイプによって関係がないなら、Foo
のインスタンスは Bar
のインスタンスと等価のはずがありません。
その他の問題で対称的ではない equals
メソッドになる可能性が高いです。
たとえば、Foo
が String
と等価であるように Foo
クラスを定義するなら、String
は String
だけと等価であるので、equals
メソッドは対称的ではありません。
まれに、非対称 equals
メソッドを定義して、まだ、何とかそれらのコードを機能させています。
APIのどれも文書化していないか、保証もしていないが、Collection<String>
に Foo
があるかどうか調べたいなら、
引数の equals
メソッド (たとえば、Foo
クラスの equals
メソッド) を使用して等価性をチェックします。
s.contains(s)
が true) にだけ意味があります。
これが本当だとは思えないし、もし本当なら問題の原因になります (たとえば、無限再帰になっているハッシュコードの計算)。
間違ったパラメータが渡されている可能性が高いです。
]]>
c
も c.containsAll(c)
を呼び出すことは常に true であるべきです。
そして、c.retainAll(c)
は効果があるはずがありません。
]]>
m
が entrySet のためのそのような反復子を返すならば、c.addAll(m.entrySet())
はひどく間違っているでしょう。
OpenJDK 1.7 の すべての Map 実装はこれを回避するために書き直されました。
]]>
c
からすべての要素を除去したいなら、c.removeAll(c)
ではなく c.clear
を使用してください。
コレクションを消去するために c.removeAll(c)
を呼び出すことは、それほど明確ではなく、タイプミスからの誤りに影響されやすく、効率的ではなく、いくつかのコレクションでは、ConcurrentModificationException
をスローするかもしれません。
]]>
より正確に、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); }
より正確に、when=ALWAYS を指定した型修飾子でアノテートされた値が到達することが保証されているか同じ型修飾子で when=NEVER を指定する場所で使用しています。
たとえば、@NonNegative は型修飾子アノテーション @Negative(when=When.NEVER) の略称とします。 以下のコードは、return 文が @NonNegative 値を要求するが @Negative としてマークされている値を受け取るのでこの警告を生成します。
]]>public @NonNegative Integer example(@Negative Integer value) { return value; }
厳密なアノテーションを指定しているので値を型変換します。戻り値が厳密なアノテーションでアノテートされる同一性機能を定義してください。 これは厳密な型修飾子アノテーションで非アノテート値を値に変える唯一の方法です。
]]>より正確に、when=NEVER を指定した型修飾子でアノテートされた値が同じ型修飾子で when=ALWAYS を指定する場所で使用しています。
]]>追加モードでファイルを開き、オブジェクト出力ストリームで書き込むことができる唯一の状況は、 ファイルを読み出すときにランダムアクセスモードで開き、追加を開始するところまでバイトオフセットをシークすると計画した場合です。
]]>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 によって寄贈されたバグパターン
]]>一般的にメソッドがストリープや他のリソースを開いたなら、メソッドはストリームやリソースがメソッドが戻る前にクリーンアップされることを確認するために try/finally ブロックを使用するべきです。
このバグパターンは、OS_OPEN_STREAM と ODR_OPEN_DATABASE_RESOURCE と基本的に同じですが異なる (そして、うまくいけばより良い) 静的解析技術に基づいています。 私たちは、このバグパターンの有効性についてのフィードバックを得ることに関心があります。 どちらかの方法でフィードバックを送ってください。
特に、このバグパターンの誤検出抑制探索法は詳細にわたって調整されていないので、誤検出についてのレポートは我々の助けになります。
解析技術の説明は、Weimer と Necula による Finding and Preventing Run-Time Error Handling Mistakes を参照してください。
]]>一般的にメソッドがストリープや他のリソースを開いたなら、メソッドはストリームやリソースがメソッドが戻る前にクリーンアップされることを確認するために try/finally ブロックを使用するべきです。
このバグパターンは、OS_OPEN_STREAM と ODR_OPEN_DATABASE_RESOURCE と基本的に同じですが異なる (そして、うまくいけばより良い) 静的解析技術に基づいています。 私たちは、このバグパターンの有効性についてのフィードバックを得ることに関心があります。 どちらかの方法でフィードバックを送ってください。
特に、このバグパターンの誤検出抑制探索法は詳細にわたって調整されていないので、誤検出についてのレポートは我々の助けになります。
解析技術の説明は、Weimer と Necula による Finding and Preventing Run-Time Error Handling Mistakes を参照してください。
]]>putIfAbsent
メソッドは、1つの値が与えられたキー (非存在が成功するかどうかの第一の値) と関連することを確認するために使われます。
戻り値を無視して中で渡される値への参照を保持するなら、マップのキーと関連する1つではない値を保持する危険性を冒します。
どれを使用するかが重要であり、マップに格納できないものを使うとプログラムは誤った振る舞いをします。
]]>
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
]]>