Java/基礎/反復処理

反復 (Iteration) は、同じ処理を繰り返し実行することで、コードの簡潔さと再利用性を向上させるためによく使用されます。Javaには、様々な方法で反復処理を行うことができます。たとえば、for文、while文、do-while文、拡張for文、Iterator、forEachメソッドなどがあります。
このチュートリアルでは、これらの反復処理方法を解説し、それぞれの使用方法や適切な場面について説明します。また、配列やコレクションに対する反復処理、ループ制御についても解説します。
反復処理は、プログラミングにおいて非常に重要な概念であり、プログラムの処理効率や保守性を向上させるためにも、しっかりと理解しておく必要があります。本チュートリアルを通じて、反復処理について深く理解し、効果的に使用するための知識を身につけましょう。
次のサンプルは、一応Hello worldの日本語版です。 Hello world同様、実用的な意味はありませんが、反復処理の例となっています。
上の例はfor文と呼ばれる構文を使った例です(4行目にキーワード「for」があることに注意してください)。 コンパイルして実行してみましょう。
このプログラムはwhile文を使って次のように書くこともできます。
さらにdo-while文を使って次のような書き方もできます。
またさらに、CharSequence#codePoints()でコードポイントのStreamを取得し、これのforEachメソッドで繰返しを行う次のような書き方も可能です。 これが最もシンプルな書き方です。
各構文の詳細を説明する前に、共通する要素について説明します。
反復には、必ず反復条件を伴います。反復は、反復条件が満たされている間だけ続けられ、条件が満たされなくなると終了する。
反復条件は、比較演算子を使って表現されることがあります。 比較演算子は不等号などの数学記号に似ています。
==演算子は、プリミティブ型の値またはオブジェクトの参照を比較するために使用されます。!=演算子は、==演算子と同じように使用されますが、2つの値が等しくない場合にtrueを返します。
<、>、<=、>=演算子は、プリミティブ型の値の大小関係を比較するために使用されます。
instanceof演算子は、オブジェクトの型を調べるために使用されます。左辺が右辺のクラスのインスタンスである場合、trueを返します。
注意点としては、オブジェクトの比較に==演算子を使用すると、オブジェクトの参照を比較するため、同じ内容のオブジェクトでもfalseを返す場合があります。 オブジェクトの内容を比較する場合は、.equals()メソッドを使用する必要があります。
Javaのfor文は、反復処理を行うための制御構造の一つで、指定された回数または条件を満たすまで繰り返します。一般的に、以下の形式で使用されます。
for文の本体は、継続条件式がtrueを返す間、繰り返し実行されます。通常、変数の値を使って何らかの処理を行います。
以下は、1から10までの整数を出力する例です。
for文の学習と言えば、典型的な例が掛け算九九を表示するサンプルです。

Javaにおいて、拡張for文(またはfor-each文)は、配列やコレクションなどの要素を繰り返し処理するための簡潔な方法を提供します。 標準的なforループとは異なり、ループカウンタを使用する必要がなく、ループ対象のデータ型に応じてループ変数を明示的に宣言する必要がありません。
構文は以下のようになります。
以下に、配列やコレクションを用いた拡張for文の例を示します。
この例では、配列numsの要素を順に表示するためにint型のループ変数numを使用し、同様に、コレクションfruitsの要素を順に表示するためにString型のループ変数fruitを使用しています。 拡張for文を使用することで、コードがより簡潔で読みやすくなります。
Javaにおけるwhile文は、指定した条件式がtrueである間、反復処理を続ける制御構造です。構文は以下の通りです。
条件式がtrueである限り、中括弧内の文が繰り返し実行されます。条件式がfalseになった時点で、while文の実行は終了します。
例えば、1から10までの整数を出力するプログラムは以下のように書けます。
このプログラムでは、変数iを1で初期化し、iが10以下である限り、iを出力してiを1ずつ増やしています。
これをStreamを使用して書き換えることができます。
IntStream.rangeClosed(1, 10)は、1から10までの整数のストリームを生成します。そして、.forEach(System.out::println)で各要素を出力しています。
rangeClosed()メソッドは指定された範囲(この場合は1から10まで)の整数ストリームを生成します。このストリームを使用して各要素に対して操作を行うことができます。
Javaにおいて、whileループを使ってファイルを読み込む方法について説明します。
以下は、例としてファイルの中身を1行ずつ読み込み、コンソールに出力するプログラムです。
まず、BufferedReader クラスを使ってファイルを読み込むための準備をします。BufferedReader クラスは、テキストファイルを1行ずつ読み込むためのクラスで、FileReader クラスと組み合わせて使用します。
while ループ内では、BufferedReader オブジェクトの readLine() メソッドを使って、ファイルから1行ずつデータを読み込みます。読み込んだ行が null でない場合は、読み込んだ行をコンソールに出力します。
ファイルの読み込みが終了したら、ファイルを閉じるために close() メソッドを呼び出します。また、エラーが発生した場合は、例外処理を行います。
このように、while ループを使ってファイルを読み込むことができます。ただし、ファイルの読み込みには例外処理が必要であることに注意してください。
上記のサンプルでは、while文の反復条件が(line = in.readLine()) != nullと書かれています。 これは代入演算と比較演算を同時に行う書き方で、こうした類の処理によく使われるパターンですが、慣れない間は奇異に見えるかもしれません。
なぜこうした書き方が可能なのかというと、代入演算の式は、その式で代入結果の値を返すからです。 念のため、処理の流れを追ってみましょう。
まず括弧内の処理、つまりline = in.readLine()が実行されます。この式は、変数lineに代入された値を返します。要するに、全体でlineが返されると考えてよいでしょう。
続いて、比較演算が行われます。括弧内をlineに置き換えるとわかりよいでしょう。つまりline != nullという判定が行われることになります。lineがnullになった場合、行はそれ以上ないというサインなので、ループから抜ける必要があります。
上記のサンプルは、for文を使ってたとえば
と書くこともできます。 コードの効率性や可読性、保守性なども考慮して判断する必要があります。

さらに、ファイル読み込みのコードをStreamを使用して書き換えることができます。BufferedReaderからの行のストリームを取得し、それを使用して各行を処理する方法があります。
このコードでは、Files.lines(Paths.get("input.txt"))を使用して、ファイルを行のストリームとして読み込んでいます。そして、.forEach(System.out::println)を使って、各行をコンソールに出力しています。
Files.lines()はファイルを行のストリームとして読み込む便利な方法です。それを使用することで、BufferedReaderを明示的に使わずにファイルをストリームとして扱うことができます。
Javaのdo-while文は、while文と同じくループ処理を行うための構文の1つです。ただし、while文と異なり、do-while文はループの最初に1度だけブロック内の処理を実行し、その後に条件式を評価します。条件式がtrueの場合、再びブロック内の処理を実行します。条件式がfalseの場合、ループから抜けます。
do-while文の基本構文は以下のようになります。
例えば、1から10までの整数を順番に出力する場合は、次のようにdo-while文を使用することができます。
このコードでは、変数iを初期化してから、doブロック内でiを出力し、iを1増やしています。その後、while文でiが10以下である限り、doブロックを繰り返し実行します。結果として、1から10までの整数が順番に出力されます。
do-while文は、ループの最初に必ず1度だけブロック内の処理を実行する必要がある場合に使用することができます。また、条件式がfalseであっても、ブロック内の処理を最低1回実行することが保証されるため、while文と異なり、特定の処理を必ず実行する必要がある場合にも適しています。
JavaのIteratorは、コレクションオブジェクト内の要素を順番に取得するためのインターフェースです。Iteratorは、Javaのコレクションフレームワークの一部であり、java.utilパッケージに含まれています。
Iteratorを使用することで、配列やリストなどのコレクションオブジェクトの要素を順番に取得し、処理を行うことができます。Iteratorは、以下の3つのメソッドを持っています。
Iteratorの基本的な使い方は、以下のようになります。
ここで、collectionは要素を持つコレクションオブジェクトです。まず、iterator()メソッドを使用してイテレータを取得し、hasNext()メソッドで次の要素があるかどうかを確認します。次の要素がある場合、next()メソッドで次の要素を取得し、処理を行います。
また、Iteratorは、要素を削除するためのremove()メソッドを持っています。このメソッドを使用する場合は、必ずnext()メソッドで要素を取得した直後に呼び出す必要があります。例えば、次のように使用することができます。
Iteratorを使用することで、コレクションオブジェクトの要素を順番に取得し、必要な処理を行うことができます。ただし、Iteratorは単方向のイテレーションしかサポートしていないため、要素の逆順の処理が必要な場合は、リストイテレータを使用することが推奨されます。
JavaのforEachメソッドは、Java 8から導入された機能で、配列やコレクションの要素を繰り返し処理するためのメソッドです。forEachメソッドは、以下のように使用します。
ここで、arrayOrCollectionは、要素を持つ配列またはコレクションオブジェクトです。forEachメソッドは、要素ごとに指定された処理を行うためのラムダ式を引数として受け取ります。
ラムダ式は、->を用いて定義されます。上記の例では、elementという変数が要素を表し、{}内には要素に対する処理が記述されます。この場合、forEachメソッドは、配列またはコレクションの要素を繰り返し、各要素に対して指定された処理を行います。
forEachメソッドは、拡張for文に比べて、コードを簡潔に書くことができます。また、複数の要素に対して同じ処理を行う場合にも適しています。
forEachメソッドは、配列やコレクションの要素を順番に処理するため、要素の追加や削除などの操作を行う場合は、for文またはIteratorを使用する必要があります。また、forEachメソッドは、並列処理にも対応しており、parallelStreamメソッドと組み合わせて使用することで、複数のスレッドを使用した並列処理が可能です。
Javaのコレクションフレームワークを使用してリスト(List)、セット(Set)、およびマップ(Map)を作成し、それらの要素を表示する例
コードの概要:
各コレクション(リスト、セット、マップ)は、Java 9で導入された List.of()、Set.of()、Map.of() メソッドを使用して作成されています。これらのメソッドは、不変のコレクションを作成し、指定された要素で初期化する便利な方法を提供します。そして、forEach メソッドは、各要素に対して指定されたアクション(この場合は表示)を実行するために使用されています。
List.ofメソッドは、指定された要素から不変のリストを作成するために使用されます。つまり、この場合、"apple", "banana", "orange" の3つの要素を持つリストが作成されます。
そして、forEachメソッドは、リスト内の各要素に対して指定されたアクションを実行します。System.out::printlnは、メソッド参照を使っています。これはprintlnメソッドへの参照を表しています。
つまり、fruits.forEach(System.out::println);は、リストの各要素をSystem.out.printlnメソッドを使って出力するという意味です。
メソッドチェインは、Javaで複数のメソッド呼び出しを1つの文でつなげて書く方法です。これにより、コードがより簡潔で読みやすくなります。例を見てみましょう。
この例では、List.ofメソッドを使用してリストを作成し、それをストリームに変換しています。そして、メソッドチェインを使用していくつかの処理を行っています。
これにより、1つのストリーム処理内で複数の操作を行い、最終的な結果を得ることができます。メソッドチェインを使うと、コードがシンプルで、各ステップが連続しているため、処理の流れがより明確になります。

以下は、Javaで反復処理を行う際に使用する主要な文法とメソッドのチートシートです。