JPCERT コーディネーションセンター

DCL02-J. 拡張 for 文ではコレクションの要素を変更しない

DCL02-J. 拡張 for 文ではコレクションの要素を変更しない

拡張for文は、コレクション配列に対する繰り返し処理のために設計されている。

『Java言語仕様』§14.14.2「拡張for文」[JLS 2014] では、以下の例が示されている。

拡張for文は、以下に示す通常のfor文と等価である。

for (I #i = Expression.iterator(); #i.hasNext(); ) {
    {VariableModifier} TargetType Identifier =
        (TargetType) #i.next();
    Statement
}

#iは、拡張for文により自動で生成される識別子で、スコープ内にある他の識別子(自動で生成されたものもそうでないものも)とは区別される。

通常のfor文とは異なり、ループ変数への代入は、元のコレクションと配列や繰り返しの順序に影響を与えない。つまり、ループ変数への代入と、ループ本体をスコープとしループのイテレータが参照するオブジェクトを初期値とする変数を変更することは、等価である。このようにループ変数に変更を加えることは、必ずしも間違いであるとは言えないが、ループの動作が分かりづらくなるだろうし、そもそもプログラマが拡張for文の動作を誤解していることを意味するかもしれない。

拡張for文のループ変数は必ずfinal宣言すること。final宣言することで、コンパイラはループ変数への代入を検出し、変数への代入を拒む。

違反コード

以下の違反コード例では、拡張for文を用いて整数のコレクションに対する処理を行っている。同時に、後の処理のためコレクションの最初の要素を変更することを意図している。

List<Integer> list = Arrays.asList(new Integer[] {13, 14, 15});
boolean first = true;

System.out.println("Processing list...");
for (Integer i: list) {
  if (first) {
    first = false;
    i = new Integer(99);
  }
  System.out.println(" New item: " + i);
  // iを処理する
}

System.out.println("Modified list?");
for (Integer i: list) {
  System.out.println("List item: " + i);
}

しかし、このコードは実際にはリストを変更せず、プログラムの出力は以下のようになる。

Processing list...
New item: 99
New item: 14
New item: 15
Modified list?
List item: 13
List item: 14
List item: 15

適合コード

ifinalで宣言すると、iに新しい値を代入することをコンパイラが許可しないため、この問題への対策になる。

// ...
for (final Integer i: list) {
  if (first) {
    first = false;
    i = new Integer(99); // コンパイルエラー:変数 'i' はすでに代入されている可能性があります
  }
// ...
適合コード

以下の適合コードは、実際のリストはそのままに、「変更された」リストを処理する。

// ...

for (final Integer i: list) {
  Integer item = i;
  if (first) {
    first = false;
    item = new Integer(99);
  }
  System.out.println(" New item: " + item);
  // 要素を処理する
}

// ...
リスク評価

拡張for文(for-each文)のループ変数への代入は、元のコレクションと配列や繰り返し処理の順序に影響を与えない。これは、プログラマを混乱させたり、データを壊れやすく不整合な状態に置きかねない。

ルール

深刻度

可能性

自動検出

自動修正

優先度

レベル

DCL02-J

不可

P2

L3

自動検出
ツール バージョン チェッカー 説明
Klocwork

2025.2

JD.UNMOD
Parasoft Jtest 2024.2 CERT.DCL02.ITMOD Do not modify collection while iterating over it
参考文献

[JLS 2014]

§14.14.2, "The Enhanced for Statement"

翻訳元

これは以下のページを翻訳したものです。

DCL02-J. Do not modify the collection's elements during an enhanced for statement (revision 116)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter