while文
while
文はプログラミングにおいて基本的なループ構造の1つです。これを効果的に使うためのポイントは以下の通りです。
- 条件の理解:
while
文は、条件が真(true)である限りブロック内のコードを繰り返し実行します。この条件が偽(false)になった時点でループは終了します。条件を適切に設定することが重要です。 - ループ変数の更新: 通常、ループの条件には変数が関与します。この変数(ループ変数とも呼ばれる)は、ループ内で更新される必要があります。そうしないと、無限ループになる可能性があります。
- 無限ループを避ける: 上記に関連して、無意識に無限ループを作成しないように注意が必要です。ループが意図しないほど長く続く場合、プログラムは応答しなくなるかもしれません。
- ループ内の効率: ループ内のコードは何度も実行されるため、できる限り効率的である必要があります。ループ内での重い処理や不必要な計算は避け、必要な処理だけを行うようにしましょう。
- breakとcontinue:
break
文を使用してループを途中で終了させることができます。これは特定の条件下でループを抜け出す場合に便利です。また、continue
文を使用して、ループの残りの部分をスキップし、次のイテレーションに直接移行することもできます。 - ループのネスト:
while
文を他のループ(for
、do-while
)内にネストさせることができますが、深くネストするとコードの可読性が低下するため注意が必要です。 - 変数のスコープ: ループ内で宣言された変数は、ループのブロック内でのみアクセス可能です。ループ外からアクセスする必要がある変数は、ループの外で宣言する必要があります。
- 適切なループの選択: ときには
while
ループではなく、for
ループやdo-while
ループの方が適している場合もあります。ループの種類によっては、コードが読みやすくなることもあります。
num = 10; while(num++ <= 10) { num++; } System.out.println(num);//13
例題
次のコードの実行結果を予測してください。なお、解答は実際にコードを作成して確認してください。
public class MysteriousWhileLoop { public static void main(String[] args) { int a = 10; int b = 0; int c = 3; while (b < 6) { if (c < a) { System.out.print(a + " "); } else { System.out.print(b + " "); } a -= 2; b++; c++; } } }
while文で{}を省略したときのポイント
while
文で中括弧{}
を省略すると、while
文によって制御されるのは直後の1つの文だけとなります。この方式は、ループ内で実行する処理が1つだけの場合によく用いられますが、注意点もあります。
- コードの明確さ: 中括弧を省略すると、コードが簡潔になる反面、可読性が低下する可能性があります。明確で簡潔な場合にのみ、この方式を採用することをお勧めします。
- インデントの重要性: 中括弧を省略した場合、適切なインデントが非常に重要になります。インデントを正しく行うことで、どの文が
while
文によって制御されているのかをはっきりさせることができます。 - 追加の文の注意: ループ内で追加の文を書く必要が出てきた場合、それが
while
文の制御下に入るつもりであっても、中括弧がないと制御されません。これを防ぐために、新しい文を追加するときは中括弧を使うように変更するか、非常に慎重に行ってください。 - メンテナンス: プログラムのメンテナンスの際に他の開発者がコードを理解しやすいように、中括弧の省略は慎重に行ってください。しばしば、中括弧を省略することで生じる利点は、将来的な混乱やバグのリスクに見合わないことがあります。
- 一貫性: コードベース全体で一貫性を保つことが重要です。もしプロジェクトやチームで特定のスタイル(中括弧の使用または省略)が採用されている場合、それに従ってください。
中括弧を省略する例:
int i = 0;
while (i < 5)
System.out.println(i++);
中括弧を使用する同じ例:
int i = 0;
while (i < 5) {
System.out.println(i++);
}
中括弧を省略する場合には、上記の点に注意しながら慎重に進めることが重要です。けれども試験問題には出しやすいです。どこからどこまでがブロック部分か書き出してみて確認するようにしましょう。Silver対策
do while
do{} while();
のwhileの条件式の後にはセミコロンが必要。条件にマッチするしないにかかわらず処理が1回は実行されます。
public class Loop1a {
public static void main(String[] args) {
int a = 0;
while (a < 5) {
do {
a++;
System.out.println(a);
} while (true);
}
}
}
while文だけではなく、do while文も中括弧を省略できます。while文、do while文で中括弧を省略した場合は、1つの文しか書けません。
while文で複数の文を書いた場合、最初の文のみループとして取り扱われます。それ以外はループを抜けた文になります。
また、do while文の場合は{}を省略して複数の文を書くとコンパイルエラーになります。
public class Loop1a {
public static void main(String[] args) {
int a = 0;
while(a < 5)
System.out.println(a++);
System.out.println("A");
}
}
結果
0 1 2 3 4 A
以下はコンパイルエラーになります。
public class Loop1b {
public static void main(String[] args) {
int a = 0;
while (a < 5)
do
a++;
System.out.println(a);
while (true);
}
}
while文で条件判定をふくめてインクリメントが出たならその時点で1プラスされることに注意。条件がマッチしてもしなくても1プラスされます。また、後置き++の場合は条件判定時点ではプラスされてないので要注意しましょう。while文とインクリメントを併せた問題は出やすいのでしっかり練習しておきましょう。Silver対策
for文
for文の実行タイミングは次のようになります。
- 初期化文
- 条件文
- 繰り返し処理する内容
- 更新文
{}でブロックを作るループ文では、ブロック内で宣言した変数はブロック内しか使えません。条件式で宣言した変数を不用意に使用しないこと。
for文の条件式と更新式は省略できます。条件式を省略したらtrueと同等無限ループになります。また、更新式を省略したら初期値が続くことになるのでこれも無限ループになります。
for文の無限ループ
- 条件式をtrueにする
- 条件式を省略する
- 更新式を省略する
Silver対策
- for文の初期化文と更新文は複数作ることができます
- 条件文は複数指定できません。コンパイルエラーになります
- 更新文にメソッドを使用することができます
- 2次元のfor文が出た時は表を作成する練習をしておく。
- 2次元ループの回数 = 外側ループ回数 * 内側ループ回数
- for文は複数の変数をカンマで区切って書く事ができるが、複数の変数を宣言する場合は同じ型である必要がある。
num = 10;
while(num++ <= 10) {
num++;
}
System.out.println(num);//13
拡張for文
拡張for文を使うと配列の要素を簡単に取り出せます。
for(型 変数名: 集合){
//繰り返し処理
}
拡張for文はこのページ後半でコレクションの取り扱いとともに更に詳しく説明します。
ラベル
ラベルを使うことで、breakやcontinueの時に制御を移す箇所を自由に指定できます。例えば2重ループの内側でbreakした場合は、元々の動作で内側のループだけ抜けます。それが、ラベルを使えば外側のループも一度に抜けることが可能です。
ラベルをつけることが可能な箇所
- コードブロック
- ループ文
- 分岐(if, switch)
- 式
- 代入
- return文
- tryブロック
- throw文
break, continueのラベル
breakはループを中断するのに使われます。ただし、2重ループの場合は、直近のループだけです。
public static void main(String[] args) {
// TODO 自動生成されたメソッド・スタブ
String[] array = {"A", "B"};
for (String a : array) {
for (String b : array) {
if("B".equals(b))
break;
System.out.println(b);
}
}
} // AAと表示
Javaのbreak
文とcontinue
文は、通常、ループの中で使用されます。しかし、複数のネストされたループを持つ場合、どのループから脱出するか、またはどのループをスキップするかを指定するために、ラベルが必要になることがあります。以下に、ラベルを使用したbreak
文とcontinue
文の例を示します。
public class LabelExample {
public static void main(String[] args) {
// ラベルを使用したbreak文の例
outerloop:
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
System.out.println(i + " " + j);
if (i == 2 && j == 2) {
break outerloop;
}
}
}
System.out.println();
// ラベルを使用したcontinue文の例
outerloop:
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if (i == 2 && j == 2) {
continue outerloop;
}
System.out.println(i + " " + j);
}
}
}
}
この例では、outerloop
という名前のラベルを使用して、break
文とcontinue
文を指定しています。break outerloop
は、外側のループから脱出するために使用され、continue outerloop
は、外側のループをスキップして次の反復を開始するために使用されます。
for文のポイントと応用
Javaにおけるfor文の基本的な構文は次の通りです。
for (initialization; termination; increment) {
// body of loop
}
initialization
: ここで変数が初期化されます。一度だけ実行されます。termination
: この式がfalseと評価されると、ループが終了します。increment
: ループの終わりに毎回実行されます。
無限ループを作成するfor文は次のように書きます。
for (;;) {
// body of loop
}
このfor文は、終了条件が指定されていないために無限ループとなります。
for文で複数の変数の指定
Javaのfor文では、カンマを用いて複数の変数を定義することが可能です。ただし、これらの変数はすべて同じ型でなければなりません。以下に例を示します:
for (int i = 0, j = 0; i < 5; i++, j++) {
System.out.println("i = " + i + ", j = " + j);
}
このコードは、iとjという2つのint型の変数を同時に初期化しています。また、それぞれの変数はループの各イテレーションでインクリメントされています。
しかし、異なるデータ型の変数を初期化したい場合には、for文の外で変数を定義する必要があります。例を以下に示します。
int i;
double d;
for (i = 0, d = 0.0; i < 5; i++, d += 0.1) { // エラー
System.out.println("i = " + i + ", d = " + d);
}
このコードはコンパイルエラーとなります。なぜなら、forループの初期化フェーズでは、異なる型の変数をカンマで区切って初期化することはできないからです。そのため、以下のように書き換える必要があります。
int i = 0;
double d = 0.0;
for (; i < 5; i++, d += 0.1) {
System.out.println("i = " + i + ", d = " + d);
}
このように書き換えると、iとdという異なる型の2つの変数を同時に扱うことができます。
複数の条件式を使いたい
Javaのforループの条件部分では、カンマを使用して複数の条件を区切ることはできません。カンマを使用した複数の条件は、セミコロンで区切られたforループの3つの部分(初期化、条件、増分)のうち、初期化部分と増分部分でのみ使用できます。
しかし、条件部分に複数の条件を指定したい場合は、論理演算子(&&、||)を使用することで実現できます。以下に例を示します:
for (int i = 0, j = 0; i < 5 && j < 5; i++, j++) {
System.out.println("i = " + i + ", j = " + j);
}
このコードでは、iとjの両方が5未満の場合にのみループが続行されます。もしiかjのどちらか一方が5に達した場合、ループは終了します。
論理演算子を用いることで、複数の条件を指定し、それら全てまたは一部が満たされた場合にループを続ける、といった柔軟なループの制御が可能になります。
for文の括弧内で省略できるもの
Javaのforループの構文は以下の通りです。
for (initialization; termination; increment) {
// body of loop
}
このうち、initialization
、termination
、**increment
**の各部分は、それぞれ省略可能です。
initialization
は省略すると、ループ内での変数の初期化が行われません。変数の初期化はforループの前に行うことも可能です。termination
を省略すると、無限ループが生成されます。そのため、ループを終了させる条件はループ内部の何らかの形(break文など)で提供する必要があります。increment
を省略すると、ループの各イテレーションの終了時に特定の操作(例えば、変数の増分)が行われません。これもループ内部で行うことが可能です。
以下に、各部分を省略した例を示します。
initializationを省略:
int i = 0;
for (; i < 5; i++) {
System.out.println(i);
}
terminationを省略 (無限ループの生成):
for (int i = 0;; i++) {
System.out.println(i);
if (i == 4) {
break;
}
}
incrementを省略:
for (int i = 0; i < 5;) {
System.out.println(i);
i++;
}
なお、全て省略した場合は以下のようになります(無限ループ):
for (;;) {
// body of loop
}
for-each文(拡張for文)とforEach()メソッド
for-eachループ (Enhanced for loop): Java 5から導入されたfor-eachループは、配列やコレクションの各要素に対して処理を行う場合に便利です。
int[] array = {1, 2, 3, 4, 5};
for (int element : array) {
System.out.println(element);
}
上記のコードは、arrayの各要素を取り出し、その値を出力します。
Java 8からは、Collection Framework(ListやSetなど)の各要素に対して操作を行うために、forEach
メソッドが追加されました。
基本的な使い方は以下の通りです。
List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
list.forEach(element -> System.out.println(element));
上記のコードでは、list
内の各要素に対してSystem.out.println(element)
を実行しています。このとき、element -> System.out.println(element)
部分がラムダ式(無名関数)と呼ばれる部分で、element
が各要素を一時的に保持する変数、System.out.println(element)
がその要素に対して実行される処理です。
メソッド参照を使用すると、上記のコードはさらに簡潔に書くことができます。
List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
list.forEach(System.out::println);
この場合、System.out::println
はメソッド参照と呼ばれ、特定のメソッドをラムダ式の代わりに使用することができます。
なお、forEach
メソッドはストリームAPIとも連携して使うことが可能で、例えばフィルタリングやマッピングなどの中間操作と組み合わせることで、より複雑な処理を行うことができます。
List<String> list = Arrays.asList("Apple", "Banana", "Cherry", "Dragonfruit", "Elderberry");
list.stream() // ストリームの生成
.filter(s -> s.length() > 5) // 長さが5より大きい要素だけを取り出す
.forEach(System.out::println); // 残った要素を出力
以上がforEach
メソッドの基本的な使い方となります。ただし、forEach
メソッドは要素の順序に依存しない操作を行うときに適しており、順序に依存する操作を行う場合や、ループ内で例外をスローする場合、または複数のループ変数を管理する必要がある場合は、従来のforループや、インデックス付きのforループ(for-iループ)を使用した方が良い場合があります。
固定サイズのリスト
Arrays.asList()
メソッドで作成されたリストは固定サイズであり、そのサイズを変更することはできません。このメソッドは、指定された配列に基づく固定サイズのリストを返します。このリストは変更可能(つまり、要素自体は変更可能)ですが、サイズを変更する操作(つまり、要素の追加や削除)はサポートされていません。以下に例を示します:
List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
// 以下の行はエラーを引き起こします。
list.add("Orange"); // UnsupportedOperationException
list.remove(1); // UnsupportedOperationException
add
メソッドやremove
メソッドを使って要素を追加または削除しようとすると、UnsupportedOperationException
がスローされます。
要素の追加や削除が可能なリストを作成するには、新たなArrayList
(または他のList
実装)のインスタンスを明示的に作成します:
List<String> list = new ArrayList<>(Arrays.asList("Apple", "Banana", "Cherry"));
// 以下の行は問題なく実行されます。
list.add("Orange");
list.remove(1);
このようにすることで、Arrays.asList()
で生成したリストを元に新たなArrayList
を作成し、そのサイズを自由に変更できるようになります。
拡張for文
Javaの拡張for文(またはfor-each文)は、配列やコレクションの要素を順番に処理するための構文です。以下に基本的な形式を示します。
for (Type variableName : arrayOrCollection) {
// body of loop
}
ここで、変数variableName
の型Type
は、配列やコレクションの要素の型と一致する必要があります。これが最も重要な点です。つまり、整数のリストをループする場合、変数の型はint
かInteger
であるべきです。同様に、文字列のリストをループする場合、変数の型はString
であるべきです。
もし、適切な型を使用しないと、コンパイルエラーが発生します。例えば以下のようなコードはコンパイルエラーになります:
List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
// 以下の行はコンパイルエラーを引き起こします。
for (int s : list) { // s should be of type String, not int
System.out.println(s);
}
このコードは、String
のリストをループするための変数s
の型をint
としているため、エラーになります。
その他の点として、配列やコレクションにnullが含まれている場合、nullを扱うための適切なチェックが必要であるという点も考慮する必要があります。
また、拡張for文内での要素の削除や追加はできません。これを行いたい場合は、イテレータを使用するか、標準のfor文を使用する必要があります。
以上が、拡張for文において注意すべき点です。
2重ループの解き方
Java Silverなどのテスト対策では、2次元配列と2重ループのコードを見て、素早く確実に答えを導き出す必要があります。
2次元配列はエクセルのような表を作成していることをまずは認識しておきましょう。その2次元配列の値を一つずつ取得するには2重のfor文を作成します。
- 外側のfor文は行を作成したり、行の値を取得する
- 内側のfor文は行の中のセルを作成したり、その値を取得する
これらの動きを次の例題のコードで試して実際にマトリックスを書いて練習しましょう。この例題ではすでにある配列の展開ではなく、for文が持つ初期値 i や j を活用しています。
パッとコードを見ただけで表にできるようになるまで練習しておくと2重ループの苦手意識がかなり軽減されると思います。
例1
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(i + "" + j + " ");
}
System.out.println();
}
以上の表がすぐに書けるようになったら次の例題を試してください。
練習問題
- 次のコードの出力結果は何ですか?
for (int i = 0; i < 3; i++) { for (int j = 3; j > 0; j--) { if (i == j) { break; } System.out.print(i + "" + j + " "); } System.out.println(); }
- 次のコードの出力結果は何ですか?
for (int i = 1; i <= 3; i++) { for (int j = 1; j <= 3; j++) { if (i * j > 2) { break; } System.out.print(i * j + " "); } System.out.println(); }
- 次のコードの出力結果は何ですか?
int sum = 0; for (int i = 1; i <= 3; i++) { for (int j = 1; j <= i; j++) { sum = sum + j; } } System.out.println(sum);
- 次のコードの出力結果は何ですか?
for (int i = 0; i < 2; i++) { for (int j = 0; j < 2; j++) { if (i == j) { continue; } System.out.print(i + "" + j + " "); } System.out.println(); }
- 次のコードの出力結果は何ですか?
for (int i = 5; i > 0; i--) { for (int j = i; j > 0; j--) { System.out.print(j + " "); } System.out.println(); }
- 次のコードの出力結果は何ですか?
for (int i = 1; i <= 3; i++) { for (int j = 3; j >= i; j--) { System.out.print(j + " "); } System.out.println(); }
- 次のコードの出力結果は何ですか?
int counter = 0; for (int i = 0; i < 3; i++) { for (int j = i; j < 3; j++) { counter++; } } System.out.println(counter);
- 次のコードの出力結果は何ですか?
for (int i = 1; i <= 3; i++) { for (int j = 1; j <= 3; j++) { if (i % j == 0) { System.out.print(j + " "); } } System.out.println(); }
- 次のコードの出力結果は何ですか?
for (int i = 0; i < 3; i++) { for (int j = 0; j <= i; j++) { System.out.print((i + 1) * (j + 1) + " "); } System.out.println(); }
- 次のコードの出力結果は何ですか?
int sum = 0; for (int i = 0; i < 3; i++) { for (int j = 0; j <= i; j++) { sum += (i + 1) * (j + 1); } } System.out.println(sum);
コメントを投稿するにはログインしてください。