拡張forを理解する
拡張forは配列やIterableの要素を順に取り出す書き方です。添字を自分で増やす基本forと比較し、値のコピーと参照先の変更を区別します。例はJava 11の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から要素を順次受け取る繰返し。
- ループ変数
- 各回の要素を受け取る本体内の変数。
- 参照
- オブジェクトを指し示す値。
- 可変オブジェクト
- 生成後に内部状態を変更できるオブジェクト。
関連教材
参考資料
教材データに登録された参考リンクです。リンク先の内容や更新日は提供元でご確認ください。
確認問題の出題・採点や学習履歴の保存にはログインが必要です。