カウントダウン

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

カウントダウン とは

Java の while 文を使って、n から 1 までを空白区切りでつないだ文字列を作るカウントダウン処理を学びます。

while でカウントダウンする

プログラミングを書いていると「ある条件が true の間ずっと同じ処理を繰り返したい」という場面に山ほど出会います。3 秒のカウントダウン、ユーザーが quit と入力するまでの対話、ファイルの末尾まで 1 行ずつ読む処理、ゲームのフレームループ、どれも「ある条件が崩れるまで回し続ける」という形をしています。

こういう繰り返しを書くために、Java には大きく分けて forwhile の 2 種類のループ構文が用意されています。for は「回数が決まっているとき」に強く、while は「終わるタイミングが条件で決まるとき」に自然です。今回のカウントダウンのように「n から 1 までを降りていく」という処理は、どちらでも書けますが while のほうが意味がストレートに伝わります。

forwhile も最終的には「条件が true の間繰り返す」という同じ命令に翻訳されます。Java 仕様書のレベルでは、for (init; cond; update) { body }init; while (cond) { body; update; } と等価だと考えてかまいません。読み手にとって意味が伝わりやすいほうを選ぶのが基本です。

このレッスンでは、while 文の基本形をおさえつつ、n を 1 ずつ減らすデクリメント -- を組み合わせて、"3 2 1" のような空白区切りの文字列を組み立てる方法を学んでいきます。終了条件のちょっとした書き方の違いで結果が "3 2 1 0" になってしまったり、末尾に余分な空白が混ざってテストが fail したり、初学者がよくハマる落とし穴を一つずつ潰していきましょう。

while の基本文法

while 文の構文はとてもシンプルです。if 文とほとんど同じ見た目で、違うのは「条件が true の間、本体を 繰り返し 実行する」という点だけです。

Java

while (条件式) { // 条件が true の間、ここが繰り返し実行される }

動きは次のとおりです。

  • まず 条件式 を評価する
  • true なら { ... } の中身を 1 周ぶん実行する
  • 1 周終わったら、また 条件式 を評価する
  • これを 条件式false になるまで延々と繰り返す

if と違って while は「条件をもう一度評価しに戻ってくる」ループです。本体の中で条件に絡む変数を 必ず変化させる こと。さもないと無限ループに陥り、プログラムが止まらなくなります。Cmd + .Ctrl + C で強制終了する羽目になります。

たとえば 1 から 3 までを順に積み上げる単純なコードはこう書けます。

Java

public class Demo { public static int sumTo3() { int i = 1; int sum = 0; while (i <= 3) { sum = sum + i; i++; } return sum; } }

i1 2 3 と進む間ループが回り、i4 になった瞬間 i <= 3false になって抜けます。結果として sum1 + 2 + 3 = 6 になります。i++ を書き忘れると、i1 のまま永遠にループするので注意です。

for でも書けるが、while のほうが自然なケース

同じ繰り返しでも、for 文はよく「回数がはっきり決まっているループ」に使われます。たとえば「配列を最初から最後までなめる」「0 から 9 までやる」のような明確な回数があるケースは for が読みやすいです。

Java

for (int i = 0; i < 10; i++) { // 10 回まわる、回数がはっきりしている }

一方、今回のような「n から 1 まで降りる」「ユーザーが quit と打つまで繰り返す」「読み込んだ行が null になるまで」のように、終了条件が動的に決まる ケースでは while のほうが意味が素直に伝わります。書き手の意図が「回す回数」ではなく「終わる条件」にあるからです。

同じ処理を for でも while でも書ける、という場面はとても多いです。判断の目安は「コードを読む人に、回数を伝えたいか / 終わる条件を伝えたいか」で選ぶこと。while (n >= 1) は「n1 以上の間続ける」という意味がそのまま読めて、終了条件にフォーカスがあるので自然です。

デクリメント -- でカウンタを減らす

カウントダウンの主役は、変数を 1 ずつ減らすデクリメント演算子 -- です。1 増やすインクリメント ++ と兄弟の関係で、n = n - 1;n--; の 3 文字で書けるショートカットです。

  • n--;n を 1 減らす (n = n - 1; と同じ)
  • --n;n を 1 減らす (n = n - 1; と同じ)

単独の文として使うかぎり、前置 --n と後置 n-- はまったく同じ動きです。今回のカウントダウンでは、while の本体の最後で n--; と書いておけば「1 周ごとに n が 1 ずつ減って、いずれ 1 を下回って false になる」という流れになります。

カウントダウンのフロー図

while でカウントダウンを書くと、コードの流れはこんな形になります。n3 のときと 1 のときで、どこで false になって抜けるかを意識して読んでみてください。

diagram (will load when visible)

n = 3 で始めれば、C の分岐で 3 → 2 → 1 の 3 回 true を通り、n0 になった時点で false になって F に抜けます。n = 1 で始めれば 1 回だけ通って、n0 になって抜けます。図と頭の中の動きが一致しているか、ぜひ追いかけてみてください。

文字列の組み立て方

戻り値は "3 2 1" のような 空白区切り の文字列です。コードでは String result = result + n + " "; のように + で連結していく方法が一番素直です。ただしこの書き方だと末尾に空白が 1 つ余計につくので、最後に trim() で取り除くか、または if で先頭以外のときだけ空白を入れるなどの工夫が要ります。

今回の解答例では、StringBuilder を持ち出さず、シンプルな String 連結 + trim() で済ませます。短い文字列を組み立てるだけなら String の連結で十分速く、コードも読みやすいです。

Java

public class Solution { public static String countDown(int n) { String result = ""; while (n >= 1) { result = result + n + " "; n--; } return result.trim(); } }

result + n + " "+ は、左側が String なので右側の int n も自動的に文字列に変換されてつながります。JavaStringint の連結はこの仕組みのおかげで気軽に書けます。

result + n + " " のように + でつなぐと、ループ 1 周ごとに新しい String オブジェクトが内部で作られています。今回のような短いループでは何の問題もありませんが、何千回も回るループで巨大な文字列を組み立てる場合は StringBuilder を使うほうが効率的です。これは後の章で詳しく扱います。

よくある間違い

初学者が while でカウントダウンを書くと、ほぼ必ず一度は次のどれかにハマります。代表的なものを 3 つ紹介します。

  • 終了条件の > 0>= 1 の混同 — 整数の n であればどちらも結果は同じですが、n > 0 と書くつもりで n >= 0 と書いてしまうと、0 までカウントが進んで "3 2 1 0" のように余計な 0 が混ざります。>= 1> 0 のどちらかで意図を統一しましょう
  • n-- の位置を間違えて無限ループresult = result + n + " ";n-- を書いてしまうと、最初の値 n が結果に入らないまま 1 減って、想定とずれた文字列になります。さらに n-- 自体を書き忘れると n が永遠に減らず無限ループです
  • 末尾に余計な空白が残るresult + n + " " で連結すると、必ず最後にスペースが 1 つ余ります。"3 2 1 " のように末尾に空白が残った状態のままだと、テストの "3 2 1" と一致せず fail します。trim() で末尾の空白を必ず削ること

もうひとつ気をつけたいのが、n0 や負の数で呼ばれたケースです。while (n >= 1) という条件であれば、n = 0n = -5 ではループに 1 回も入らず、空文字 "" が返ります。今回のテストでは扱いませんが、現実のコードでは「ゼロや負の引数が来たときどうする?」を意識する習慣をつけておくと、後でバグになりにくいです。

ループの終了条件は「どの値で抜けるか」を一度声に出して確認してみてください。「n1 のときは入って、0 になったら抜ける」と読み上げられれば、>= 1> 0 の選択を迷うことはありません。

やってみよう

それでは課題に挑戦してみましょう。手順は次のとおりです。

  1. 空の結果用文字列を用意する (String result = "";)
  2. while (n >= 1) { ... } のループを書く
  3. ループの中で、result に現在の n と空白 " " を追加する
  4. ループの中で n--; を呼んで n を 1 ずつ減らす
  5. ループを抜けたら、result.trim() で末尾の空白を取り除いて return する

注意点としては、ループの中の n--;resultn を追加した後 に置くことです。先に n--; をしてしまうと、最初の値が結果に入らずに次の数字から始まってしまいます。

慣れてきたら、for 文で同じカウントダウンを書き直してみるのもおすすめです。for (int i = n; i >= 1; i--) { ... } という形になって、while 版との対応がよく見えてきます。同じ処理を別の構文で書き換えてみると、「終了条件で書きたい」「回数で書きたい」のどちらがしっくり来るかが体感できて、ループの理解がぐっと深まります。

よくある質問

Q. Java と他言語の文法はどう違いますか?

A. Java は静的型付けで、変数宣言時に型を明示します(int x = 0;)。中括弧でブロックを表し、文末にセミコロンが必要です。Python の動的型付けや JavaScript の柔軟さに慣れていると最初は窮屈ですが、コンパイル時にバグが発見できる安全性がメリットです。

Q. コードが動かないときに最初に見るべき場所は?

A. コンパイルエラーは行番号とエラー種別(cannot find symbol、incompatible types など)が表示されます。実行時例外はスタックトレースの最初の at ... が原因行です。IDE(IntelliJ / VS Code)の警告も丁寧に潰すと、半分のバグは未然に防げます。

Q. Java の習得後に学ぶべき技術は何ですか?

A. 基本構文を抑えたら java-intermediate(コレクション / ジェネリクス / Stream / 例外)に進み、Spring Boot や Web 開発に展開するのが王道です。クラウド時代は Kotlin / Scala への展開も視野に入りますが、まずは Java 標準を固めるのが効率的です。

次のレッスン

次は do-while 文 で、Java の while 文を使って、n から 1 までを空白区切りでつないだ文字列を作るカウントダウン処理を学びます を学びます。

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

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

理解度チェック (30 秒)

Q. カウントダウン とは何か、1 文で説明してください。

この章のポイント

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

関連レッスン

要件

  1. クラス名は Solution、メソッド名は countDown、引数は int n 1 つ、戻り値の型は String
  2. 繰り返し処理には必ず while 文を使うこと (for 文は使わない)
  3. 戻り値は n から 1 までを 半角スペース 1 つ区切り でつないだ文字列 (例: "3 2 1")。末尾に余計な空白を残さないこと

入出力例

test-cases.txt

countDown(3)"3 2 1" countDown(5)"5 4 3 2 1" countDown(1)"1" countDown(10)"10 9 8 7 6 5 4 3 2 1"

ヒント

main.java
main.java
学習モード

メモ

カウントダウン

⌘S で保存