while 文

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

while 文 とは

while 文の構文と使いどころを学びながら、整数の桁数を数えるアルゴリズムを実装してみよう。本レッスンでは、while 文 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

条件で繰り返す while

プログラムの世界では「同じ処理を何度も繰り返す」場面が本当によく出てきます。配列の中身をひとつずつ調べる、ユーザーが正しい値を入れるまで聞き直す、ファイルの末尾までデータを読む、ゲームの 1 フレームごとに描画を更新する。こうした「繰り返し」を表現する道具が Java には大きく 2 種類あります。これまでに見てきた for 文と、このレッスンで学ぶ while 文です。

for 文は「決まった回数だけ繰り返す」処理を簡潔に書くのが得意です。一方の while 文は「ある条件を満たしている間ずっと繰り返す」処理を素直に書けます。回数より「いつ抜けるか」が主役の処理では、while のほうが読みやすいコードになります。

たとえば「1 から 10 まで足す」のような決まった回数の処理は for (int i = 1; i <= 10; i++) がぴったりです。逆に「ユーザーが q を入力するまで質問を続ける」「割り算の余りが 0 になるまでループする」「整数を 10 で割り続けて桁を数える」のような、終わる条件が値の状態で決まる処理は while のほうが自然に書けます。

while 文の基本構文

まずは構文を見てみましょう。while のうしろにカッコで条件を書き、その中身を { ... } で囲むのが基本の形です。

Java

while (条件) { // 条件が true のあいだ繰り返す処理 }

動きをひと言でまとめると、こうなります。while( ) の中の条件式を評価し、true なら本体を実行する、もう一度先頭に戻って条件を評価する、false になったらブロックを抜ける、という流れです。

簡単な例を見てみましょう。次のコードは 0 から始めた i5 未満のあいだだけ 1 ずつ増やしています。

Java

public class Counter { public static int countUp() { int i = 0; while (i < 5) { i = i + 1; } return i; } }

このメソッドの中で起きていることを順番に追ってみます。最初に i = 0 を用意し、while (i < 5) をチェックします。0 < 5true なので、本体の i = i + 1 が走って i1 になります。もう一度 while の条件に戻り、1 < 5true、ともう一度 i2 になります。これを繰り返して、i5 になった瞬間に 5 < 5false になるので、ループを抜けて return i;5 が返ります。

while 文の最大のポイントは、ループの中で 必ず条件に関係する値を更新する ことです。値を更新し忘れると、true のまま二度と抜けない「無限ループ」に陥ります。while を書くときは「いつ条件が false になるのか」を声に出して確認するくらい慎重に組み立てましょう。

forwhile の使い分け

forwhile はどちらも同じことを表現できますが、「読んでぱっと意図が伝わる」かどうかは選び方で変わります。次の表で雰囲気を比べてみてください。

  • 回数が決まっている処理 — for (int i = 0; i < n; i++) を使うと、n 回繰り返すことが一目でわかる
  • 終わる条件が値の状態で決まる処理 — while (n > 0) のように書けると、何を待っているかが素直に読める
  • ファイルや入力ストリームを末尾まで読む — while (scanner.hasNextLine()) のように while が自然
  • リトライ処理 — while (!success && retry < 3) のような書き方は while のほうがすっきり

両者は機械的にはまったく等価で、for で書いたものを while で書き直すこともできます。それでも、読み手の頭の中に最初に浮かぶイメージが違うので、適切なほうを選ぶとコードはぐっと読みやすくなります。

このレッスンで作るもの

今回作るのは Solution.digitCount(int n) というメソッドです。正の整数 n を受け取って、n が何桁なのかを返します。たとえば digitCount(123)3digitCount(9)1digitCount(10000)5 です。さらに今回は 01 桁として扱う仕様です。

桁数を求めるアルゴリズムには、定番のテクニックがあります。「整数を 10 で割り続けて、0 になるまでの回数を数える」というものです。たとえば 123 に対しては、こんな順番で値が変わっていきます。

  • 開始時 — n = 123count = 0
  • 1 回目 — count = 1n = 123 / 10 = 12
  • 2 回目 — count = 2n = 12 / 10 = 1
  • 3 回目 — count = 3n = 1 / 10 = 0
  • n == 0 になったのでループ終了、count = 3 を返す

Java の整数 (int) どうしの割り算は 小数を切り捨て ます。123 / 1012.3 ではなく 12 になるのはそのためです。この性質のおかげで、10 で割り続けるという素朴な式だけで桁数を数えられます。

diagram (will load when visible)

図のとおり、n == 0 だけは特別扱いで 1 を返します。あとは n > 0 のあいだだけ count+1 して n10 で割る、というシンプルな繰り返しです。

ループ変数ではなく「状態」を更新する

for 文では i++ のような ループ専用の変数 を進めるのが普通でした。while 文ではもっと自由で、「ループが続くかどうかを決める状態そのもの」を更新するのが基本です。今回のように n 自体を 10 で割り続けるのが典型例です。

Java

while (n > 0) { count = count + 1; n = n / 10; }

この形は最初は少し違和感があるかもしれません。「引数の n を上書きしていいのか」と心配になる人もいます。Java ではメソッド内のローカル変数は呼び出し元には影響しないので、n を中で書き換えても安全です。

ループの中で状態を更新するときは、「いまの状態」と「次の状態」をいったり来たりするイメージを持つと整理しやすいです。n = 123n = 12n = 1n = 0 と、n 自身が階段を降りていくと考えてみてください。

もし元の n の値も後で使いたい場合は、別の変数にコピーしておけば安心です。たとえば int temp = n; と書いてから while (temp > 0) でループを回せば、n はそのままで temp だけが変化します。

0 というエッジケース

仕様で「01 桁とする」と決まっているのが今回の地味な落とし穴です。素直に while (n > 0) だけで書くと、n = 0 のときはループが一度も実行されず、count = 0 のまま返ってしまいます。01 桁なので、これでは仕様違反です。

対処方法はいくつかありますが、いちばんシンプルなのは「最初に n == 0 を特別扱いする」ことです。

Java

public class Solution { public static int digitCount(int n) { if (n == 0) { return 1; } int count = 0; while (n > 0) { count = count + 1; n = n / 10; } return count; } }

もうひとつの書き方として、do-while を使う方法もあります。do { ... } while (条件) は本体を 必ず 1 回は実行してから 条件を判定するので、n = 0 のときも count = 1 になってから抜けてくれます。少し進んだ書き方なので、まずは if で特別扱いする方法に慣れておきましょう。

仕様を読むときは「境界の値」「特殊な値」を必ず探す癖をつけてください。今回なら 0 がそれにあたります。実務でも、空配列、null、最大値、最小値、マイナス、こうした「ちょっと変わった入力」はバグの温床です。コードを書く前にテストケースを書き出すと、こうしたエッジケースを忘れにくくなります。

よくある間違い

初めて while 文を書くとき、ほぼ全員が一度はハマるパターンが 3 つあります。先回りで紹介しておきます。

  • 条件を更新し忘れて無限ループwhile (n > 0) { count = count + 1; } のように n を更新する行を書き忘れると、n は永遠に正のままで、count だけが増え続けます。Java の executor では 5 秒で強制終了されますが、本物のアプリでは画面が固まって最悪のユーザー体験になります。ループの中で「条件に関係する変数を必ず変える」のは絶対のルールです
  • 初期値を境界の外に置いてしまうint count = 1; のように count を最初から 1 にしてしまうと、すべての結果が +1 ずれます。「ループに入る前に何回実行したことになっているか」をいつも意識して、初期値を決めましょう
  • エッジケース (0 や負の数) を考えていない — 今回は 01 桁として扱う仕様でしたが、これに気づかず while (n > 0) だけで提出すると、digitCount(0)0 を返してテスト失敗です。仕様の境界値は必ずテストケースに混ぜて、コードを書く前に紙に書き出すクセをつけましょう

どれもベテランでも油断するとやってしまうミスです。書き終えたら必ず「n = 0 のとき」「n = 1 のとき」「n = 9 のとき」のように、頭の中で 1 ステップずつ値を追って動きを確認してみてください。

やってみよう

右側のエディタを開いて、Solution.digitCount(int n) を完成させましょう。手順は次のとおりです。

  1. n == 0 のときに 1 を返す if 文を最初に書く
  2. int count = 0;count を用意する
  3. while (n > 0) のループを書き、中で count = count + 1;n = n / 10; を実行する
  4. ループを抜けたら return count;
  5. 「実行」ボタンを押して、すべてのテストが緑になることを確認する

動いたら自分でいろいろな値を入れて遊んでみてください。digitCount(1) digitCount(99) digitCount(1000000) digitCount(0) digitCount(123456789) などを試して、桁数が正しく返ることを確認しましょう。int の最大値である 214748364710 桁としてちゃんと数えてくれるはずです。

さらに余裕があれば、for 文だけで同じ処理を書き直してみるのもおすすめです。for (int count = 0; n > 0; n = n / 10) { count = count + 1; } のように、for の 3 つの式に押し込むこともできます。ただし、ループ変数の代わりに n 自身を進める発想は while のほうが圧倒的に素直で読みやすいはずです。両方書いてみると、「どんなときに while が嬉しいのか」が実感できると思います。

while 文は、これからプログラムを書いていく上で何百回、何千回と登場する基本道具です。条件を更新し忘れない、初期値を間違えない、エッジケースを忘れない。この 3 つを意識すれば、もう怖いことはありません。次のレッスンでは、while の親戚である do-while 文や、break continue を使ったループ制御に進んでいきます。

よくある質問

Q. while で無限ループを止めるには?

A. ループ内で必ずカウンタを更新するか、break で抜ける条件を書きます。たとえば i = 0; while i < 10: i += 1 のように i += 1 を忘れると永久に止まりません。Ctrl+C で強制終了できますが、デバッグ時はループの 1 周目で print(i) を入れて挙動を確認すると原因が見えます。

Q. while と for はどう違いますか?

A. 繰り返し回数が決まっていれば for、終了条件が動的なら while が向いています。リスト走査や range は for で書く方が安全で、ユーザー入力が来るまで・センサー値が閾値を超えるまで、のようなケースは while True + break が定石です。

Q. do-while のように最低 1 回は実行したい場合は?

A. Python には do-while がないため、while True: ... if cond: break のパターンで再現します。JavaScript なら do { ... } while (cond) と書けます。「最初の 1 回は条件を見ずに走らせる」処理(入力受付など)で有効です。

次のレッスン

次は カウントダウン で、while 文の構文と使いどころを学びながら、整数の桁数を数えるアルゴリズムを実装してみよう を学びます。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. while の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. while とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

要件

  1. クラス名は Solution、メソッド名は digitCount、引数は int n 1 つにすること
  2. 戻り値の型は int で、n の桁数を返すこと
  3. ループには 必ず while 文を使う こと (for 文は使わない)
  4. n == 0 のときは 1 を返すこと (01 桁として扱う仕様)

入出力例

test-cases.txt

digitCount(123)3 digitCount(9)1 digitCount(10000)5 digitCount(0)1 digitCount(99)2 digitCount(1)1 digitCount(10)2 digitCount(100)3

ヒント

main.java
main.java
学習モード

メモ

while 文

⌘S で保存