1.従来の for ループ
従来の for ループは、Java で広く使用されている古典的なループ構造です。
従来の for ループの特徴は次のとおりです。
柔軟な制御: 従来の for ループでは、for (初期化式、終了条件、ステップ式) の形式の構文を使用します。ループのインデックスを手動で制御し、必要に応じてカスタム操作を実行できます。
インデックス アクセス: 従来の for ループは、インデックスを介してコレクションまたは配列内の要素にアクセスし、要素の値を直接読み取り、変更できます。
例えば:
import java.util.Arrays;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
for (int i = 0; i < numbers.size(); i++) {
System.out.println(numbers.get(i)); // 读取元素的属性值或执行操作是允许的
numbers.set(i, 10); // 直接修改元素的值是允许的
}
}
}
低レベルの操作: 強化された for ループと比較して、従来の for ループはより柔軟な低レベルの操作を提供しますが、より煩雑でもあります。
適用可能なオブジェクト: Iterable または Iterator インターフェイスを実装する任意のコレクション クラスに適用できます。
サンプルコード:
public class Demo {
public static void main(String[] args) {
int[] numbers = {1, 2, 3, 4, 5};
for (int i = 0; i < numbers.length; i++) {
System.out.println(numbers[i]);
}
}
}
従来の for ループのコード構造は次のとおりです。
for (ループ変数の最初の宣言; ループの判定条件; ループ変数の変更条件){
ループ本体
}
実行順序は、 ①ループ変数の初期宣言(ループ変数の宣言) ②ループの判定条件(ループを継続するかどうかの判定、ブール値) ③ループ本体(繰り返し実行したいコード部分) ) ④ ループ変数の変更条件(ループの終了に使用) ⑤ 手順 2 に戻り、ループから抜け出すかどうかを判断し、結果が true の場合は上記の処理を続行します。判定結果が偽の場合は、ループコード全体を抜けて後続のコードを実行します。
たとえば、テストではトラバーサルによる配列への代入が実装されており、その代入は 100、200、300、400、500 です。
import java.util.Arrays;
public class Demo {
public static void main(String[] args) {
int[] arr = new int[5];
int num = 100;
for (int i = 0; i < arr.length; i++) {
arr[i] = num;
num += 100;
}
System.out.println(Arrays.toString(arr));
}
}
コードの出力は次のようになります: [100, 200, 300, 400, 500]
明らかに、通常の for ループは添字インデックスを介して配列の内部に値を割り当てます。
2. forループの強化
拡張された for ループは foreach ループとも呼ばれ、ループ構文の簡略化されたバージョンです。これを使用して、Iterable インターフェイスを実装する配列またはコレクション クラスを反復処理できます。
拡張された for ループの特徴は次のとおりです。
簡潔な構文: 強化された for ループでは、for (要素型要素変数: コレクションまたは配列) の形式の構文が使用され、コードの読み書きが容易になります。
読み取り専用アクセス: 各反復で、拡張 for ループは現在の要素への読み取り専用アクセスを提供しますが、要素の値を直接変更することはできません。
例えば:
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Hello");
list.add("World");
System.out.println(list);
for (String s : list) {
s = "New Value"; // 尝试修改元素的值
}
System.out.println(list);
}
}
適用可能なオブジェクト: Iterable インターフェイスを実装する配列またはコレクション クラスに適用できます。
サンプルコード:
import java.util.Arrays;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List<String> list = Arrays.asList("Apple", "Banana", "Orange");
for (String fruit : list) {
System.out.println(fruit);
}
}
}
拡張された for ループのコード構造は次のとおりです。
for (配列要素を受け取る型変数名:array){
変数名は配列内の各データを表します
}
強化された機能は、配列内の各要素を走査し、前の変数名を使用してそれを受け取ることができます。型によって定義された変数は、各要素を分離するのではなく、配列内の各要素を受け取るためにのみ使用されるため、受信することに重点を置きます。
上にリストしたように、テストでは 2 つのトラバーサル メソッドを使用して、それぞれ配列に値を割り当てます。割り当てられる値は 100、200、300、400、500 です。
import java.util.Arrays;
public class Demo {
public static void main(String[] args) {
int[] arr = new int[5];
int num = 100;
for (int i : arr) {
i = num;
num += 100;
}
System.out.println(Arrays.toString(arr));
}
}
コード出力は次のようになります: [0, 0, 0, 0, 0]
つまり、拡張された for ループは値を配列にまったく渡しません。これは通常の for と拡張 for の違いでもあり、通常の for ループは配列に値を代入し、インデックスに従って動作できますが、foreach は走査して取得することしかできず、配列内のデータを変更することはできません。
さらに、: 先頭は受け取り側の配列要素の型です ここで強調したいのは、ここで定義されている型は受け取り側の配列要素の型であり、配列の型関係である必要はないということです。
for(long|float|double|.. i:arr){
i=num;
num+=100;
}
実際には、int 型配列 arr の要素を受け取ることができれば、型はそれほど厳密ではありません。もちろん、byte、short、char など、受信できない他の型ではエラーが報告されます。
3. forEachループ_
forEach は、Java 8 で導入されたメソッドで、コレクション内の要素を反復処理し、要素に対して何らかの操作を実行するために使用されます。コレクション内の各要素を操作する関数をパラメーターとして受け入れることができます。この関数は、Lambda 式または通常の関数インターフェイスにすることができます。
ラムダ式は、特定の操作を記述するための簡潔で機能的な方法として Java 8 で導入されました。ラムダ式は主に 1 つのメソッドのみでインターフェイスを作成するために使用され、このインターフェイスにはパラメーター リストと式またはブロック ステートメントを含めることができます。この式またはブロック ステートメントが Lambda 本体です。
ラムダ式 for ループの特徴は次のとおりです。
関数型スタイル: ループのラムダ式は関数型プログラミング スタイルを採用しており、ループ本体の動作はラムダ式で定義されるため、コードがより簡潔で読みやすくなります。
自動反復: 拡張された for ループと同様に、ラムダ式の for ループは、インデックス付けを手動で制御することなく、コレクションまたは配列内の要素を自動的に反復します。
例えば:
import java.util.Arrays;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
// 使用Java 8的forEach和Lambda表达式
list.forEach(fruit -> System.out.println(fruit));
}
}
4.効率の簡易比較
注: テストは、時間、マシン、実行順序の点で厳密ではない場合や、CPU 実行後の効率が低下する場合があります。これは参考値です。
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args) {
long[] numbers = {10000L, 100000L, 1000000L, 10000000L};
for (int j= 0; j < numbers.length; j++) {
long times = numbers[j];
System.out.println("操作次数:" + times);
List<String> list = new ArrayList<>();
List<String> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<String> list3 = new ArrayList<>();
for (int i = 0; i < times; i++) {
list.add(new String());
}
long startTime = System.currentTimeMillis();
//普通for
for (int i = 0; i < list.size(); i++) {
list1.add(list.get(i));
}
long endTime = System.currentTimeMillis();
System.out.println("普通for时间(毫秒):" + (endTime - startTime));
//增强for
long startTime1 = System.currentTimeMillis();
for (String s : list) {
list2.add(s);
}
long endTime1 = System.currentTimeMillis();
System.out.println("增强for时间(毫秒):" + (endTime1 - startTime1));
long startTime2 = System.currentTimeMillis();
//forEach
list.forEach(s -> list3.add(s));
long endTime2 = System.currentTimeMillis();
System.out.println("forEach时间(毫秒):" + (endTime2 - startTime2));
}
}
}
結果:
操作数: 10000
通常の時間 (ミリ秒): 1
時間の拡張 (ミリ秒): 1
forEach time (ミリ秒):59
操作数: 100000
通常の時間 (ミリ秒): 2
時間の拡張 (ミリ秒): 2
forEach time (ミリ秒): 3
操作数: 1000000
通常の時間 (ミリ秒): 37
時間の拡張 (ミリ秒): 10
forEach time (ミリ秒): 8
操作数: 10000000
通常の時間 (ミリ秒): 203
時間の拡張 (ミリ秒): 170
forEach time (ミリ秒):184
5.適用可能なシナリオの選択
適切なリサイクル方法の選択は、特定のニーズと運用によって異なります。推奨される使用シナリオをいくつか示します。
従来の for ループ: 手動でインデックスを制御したり、カスタム操作を実行したり、コレクションまたは配列要素の値を変更したりする必要があるシナリオに適しています。
強化された for ループ: コレクションまたは配列の要素を変更する必要のない単純な走査および読み取り専用操作に適しています。
ラムダ式 + forEach ループ: 関数型プログラミング スタイルに適しており、コードが簡素化され、インデックスを手動で制御する必要がなくなります。
特定のニーズに応じて、さまざまなループ方法を柔軟に選択して、コードの単純さ、読みやすさ、パフォーマンスのバランスを実現できます。