for・拡張forの全体像

拡張forは配列やIterableの要素を順に取り出す書き方です。添字を自分で増やす基本forと比較し、値のコピーと参照先の変更を区別します。例はJava 17のmain内です。

この単元で学ぶこと

  • 拡張forで配列を走査する
  • ループ変数への代入と配列要素の更新を区別する
  • 添字が必要な処理で基本forを選ぶ

本文解説

要素を一つずつ受け取る int[] a={2,4,6}; int s=0; for(int x:a){s+=x;}ではxに2、4、6が順に代入され、sは12になります。コロンの左が各回の変数、右が走査対象です。xは添字0、1、2ではありません。

基本forと対応させる この配列の集計はfor(int i=0;i<a.length;i++){s+=a[i];}でも書けます。基本forは初期化→条件→本体→更新を実行し、拡張forは要素の取得を任せます。逆順、二つおき、隣接要素の比較、要素の位置を表示するなら添字を制御する基本forが適します。

プリミティブ値のコピー for(int x:a){x=0;}を実行してもaは{2,4,6}のままです。各要素のint値をxへコピーしており、xへの代入はa[i]への代入ではありません。配列をすべて0にするならfor(int i=0;i<a.length;i++){a[i]=0;}のように要素そのものへ代入します。

参照のコピー StringBuilder[] a={new StringBuilder("A")}; for(StringBuilder x:a){x.append("B");}ではa[0]もABになります。xとa[0]が同じオブジェクトを参照しているためです。一方x=new StringBuilder("Z")はxの参照だけを置き換え、a[0]の参照は変えません。参照のコピーとオブジェクトの複製は別です。

変更不能なString String[] a={"a","b"}; for(String x:a){x=x.toUpperCase();}では配列は小文字のままです。toUpperCaseは新しい文字列などの参照を返し、代入先はxです。StringBuilderのappendのような対象自体の変更とは動作が違います。

空とnullの違い 空配列なら要素がないので本体を0回実行して正常に終了します。参照そのものがnullの配列を拡張forに渡すと、配列を走査できずNullPointerExceptionになります。配列の要素がnullの場合は別で、ループには入り、そこでnullに対しメソッドを呼ぶと例外になります。

型と変数の範囲 int[]をfor(long x:a)で走査する拡大変換は可能ですが、for(byte x:a)のような暗黙の縮小変換はできません。xのスコープは拡張for本体で、ループの後では使えません。Iterableも走査できますが、本教材の順番や出力の保証は明示した配列を対象とします。

実行して区別する 空配列、一要素、複数要素で回数と合計を確認します。xへの代入後には配列をもう一度表示し、参照型ではappendと参照再代入を別々に試します。コンパイル不可の型とスコープの例は別ファイルにし、実行時例外と混同しません。

図解

要素を受け取った後の代入先
要素のコピーは、参照先オブジェクトのコピーを意味しない。

重要ポイント

  • 拡張forの変数は要素であり添字ではない。
  • 変数への代入だけでは元の配列要素を置き換えない。
  • 参照先の可変オブジェクトは変更できる。
  • 空配列とnull配列を区別する。

間違えやすい点

  • x++でint配列を更新したつもりにならない。
  • Stringへの再代入とStringBuilderの変更を混同しない。
  • 位置・逆順が必要な処理を拡張forだけで無理に書かない。

用語解説

拡張for
配列やIterableから要素を順次受け取る繰返し。
ループ変数
各回の要素を受け取る本体内の変数。
参照
オブジェクトを指し示す値。
可変オブジェクト
生成後に内部状態を変更できるオブジェクト。

参考資料

教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。

確認問題の出題・採点や学習履歴の保存にはログインが必要です。