while 文
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 から始めた i を 5 未満のあいだだけ 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 < 5 は true なので、本体の i = i + 1 が走って i は 1 になります。もう一度 while の条件に戻り、1 < 5 も true、ともう一度 i は 2 になります。これを繰り返して、i が 5 になった瞬間に 5 < 5 が false になるので、ループを抜けて return i; で 5 が返ります。
while文の最大のポイントは、ループの中で 必ず条件に関係する値を更新する ことです。値を更新し忘れると、trueのまま二度と抜けない「無限ループ」に陥ります。whileを書くときは「いつ条件がfalseになるのか」を声に出して確認するくらい慎重に組み立てましょう。
for と while の使い分け
for と while はどちらも同じことを表現できますが、「読んでぱっと意図が伝わる」かどうかは選び方で変わります。次の表で雰囲気を比べてみてください。
- 回数が決まっている処理 —
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) は 3、digitCount(9) は 1、digitCount(10000) は 5 です。さらに今回は 0 も 1 桁として扱う仕様です。
桁数を求めるアルゴリズムには、定番のテクニックがあります。「整数を 10 で割り続けて、0 になるまでの回数を数える」というものです。たとえば 123 に対しては、こんな順番で値が変わっていきます。
- 開始時 —
n = 123、count = 0 - 1 回目 —
count = 1、n = 123 / 10 = 12 - 2 回目 —
count = 2、n = 12 / 10 = 1 - 3 回目 —
count = 3、n = 1 / 10 = 0 n == 0になったのでループ終了、count = 3を返す
Java の整数 (int) どうしの割り算は 小数を切り捨て ます。123 / 10 が 12.3 ではなく 12 になるのはそのためです。この性質のおかげで、10 で割り続けるという素朴な式だけで桁数を数えられます。
図のとおり、n == 0 だけは特別扱いで 1 を返します。あとは n > 0 のあいだだけ count を +1 して n を 10 で割る、というシンプルな繰り返しです。
ループ変数ではなく「状態」を更新する
for 文では i++ のような ループ専用の変数 を進めるのが普通でした。while 文ではもっと自由で、「ループが続くかどうかを決める状態そのもの」を更新するのが基本です。今回のように n 自体を 10 で割り続けるのが典型例です。
Java
while (n > 0) {
count = count + 1;
n = n / 10;
}この形は最初は少し違和感があるかもしれません。「引数の n を上書きしていいのか」と心配になる人もいます。Java ではメソッド内のローカル変数は呼び出し元には影響しないので、n を中で書き換えても安全です。
ループの中で状態を更新するときは、「いまの状態」と「次の状態」をいったり来たりするイメージを持つと整理しやすいです。
n = 123→n = 12→n = 1→n = 0と、n自身が階段を降りていくと考えてみてください。
もし元の n の値も後で使いたい場合は、別の変数にコピーしておけば安心です。たとえば int temp = n; と書いてから while (temp > 0) でループを回せば、n はそのままで temp だけが変化します。
0 というエッジケース
仕様で「0 は 1 桁とする」と決まっているのが今回の地味な落とし穴です。素直に while (n > 0) だけで書くと、n = 0 のときはループが一度も実行されず、count = 0 のまま返ってしまいます。0 は 1 桁なので、これでは仕様違反です。
対処方法はいくつかありますが、いちばんシンプルなのは「最初に 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や負の数) を考えていない — 今回は0を1桁として扱う仕様でしたが、これに気づかずwhile (n > 0)だけで提出すると、digitCount(0)が0を返してテスト失敗です。仕様の境界値は必ずテストケースに混ぜて、コードを書く前に紙に書き出すクセをつけましょう
どれもベテランでも油断するとやってしまうミスです。書き終えたら必ず「n = 0 のとき」「n = 1 のとき」「n = 9 のとき」のように、頭の中で 1 ステップずつ値を追って動きを確認してみてください。
やってみよう
右側のエディタを開いて、Solution.digitCount(int n) を完成させましょう。手順は次のとおりです。
n == 0のときに1を返すif文を最初に書くint count = 0;でcountを用意するwhile (n > 0)のループを書き、中でcount = count + 1;とn = n / 10;を実行する- ループを抜けたら
return count; - 「実行」ボタンを押して、すべてのテストが緑になることを確認する
動いたら自分でいろいろな値を入れて遊んでみてください。digitCount(1) digitCount(99) digitCount(1000000) digitCount(0) digitCount(123456789) などを試して、桁数が正しく返ることを確認しましょう。int の最大値である 2147483647 も 10 桁としてちゃんと数えてくれるはずです。
さらに余裕があれば、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 つができることを確認しましょう。
- while の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. while とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- クラス名は
Solution、メソッド名はdigitCount、引数はint n1 つにすること - 戻り値の型は
intで、nの桁数を返すこと - ループには 必ず
while文を使う こと (for文は使わない) n == 0のときは1を返すこと (0は1桁として扱う仕様)
入出力例
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