九九の段を作る
このレッスンで分かること
- ループ変数
iを計算式に組み込めば、九九・累積和・配列演算などが書けます- 区切り文字を末尾に残さないコツは
if (i > 1) result += " ";で先頭以外に空白を入れる- 最小例は
for (int i = 1; i <= 9; i++) { if (i > 1) sb.append(" "); sb.append(n * i); }
九九の段を作る とは
forループの応用として、引数nの段の九九を空白区切りの文字列で組み立てる方法を学びます。
ループ変数を計算に使う
前のレッスンで for 文の基本形を学びました。for (int i = 1; i <= 9; i++) { ... } のように、カウンタ変数 i を 1 から 9 まで動かすあのお馴染みの形です。今回はその一歩先、ループ変数 i を計算に使う というテーマに踏み込みます。
これまで i は「何回ループしたか」を数えるだけの存在でした。でも Java でも他の多くの言語でも、i は普通の int 変数なので、ループの中で n * i のように掛け算したり、配列のインデックス arr[i] として使ったり、自由に計算に組み込めます。この発想ができるようになると、ループで書ける処理の幅が一気に広がります。
「ループ変数はただのカウンタ」と思っていると、
for文の本当の威力を引き出せません。iを計算式の一部として捉えなおすと、九九、累積和、フィボナッチ、配列処理、ありとあらゆる場面でforが武器になります。
このレッスンの題材は、誰もが小学生のときに暗記した 九九 です。「3 の段」「7 の段」のように、引数 n で指定された段の答えを n * 1, n * 2, ..., n * 9 の順で並べた文字列を返すメソッドを書きます。
インデックスと計算結果の違い
まずは課題の構造を分解しましょう。multTable(3) を呼ぶと "3 6 9 12 15 18 21 24 27" を返してほしいわけですが、この出力を for でどう作るか考えます。
iは インデックス (何番目か、1〜9 の数え上げ)n * iは 計算結果 (実際に文字列に並ぶ値)
この 2 つを混同しないことがポイントです。i 自体を出力するのではなく、i をかけ算の右辺として使い、その結果 n * i を文字列にしていきます。
Java
for (int i = 1; i <= 9; i++) {
int value = n * i; // インデックス i を使って実際の値を計算
// value を文字列に追加する
}int value = n * i; の行が今回の核です。i がループのたびに 1, 2, 3, ..., 9 と変化するので、value は n * 1, n * 2, n * 3, ... と次々に変わっていきます。
iをそのままインデックスとして使うか、n * iのように計算して別の値を作るか。この使い分けがforループ上達の第一歩です。慣れてくるとiをarr[i]の添字として使ったり、i % 2で偶奇を判定したり、iを縦横に展開して二重ループにしたり、応用の幅がぐっと広がります。
動きを追ってみる
multTable(3) を呼んだとき、ループの中で何が起きているかを 1 ステップずつ見てみましょう。
n = 3 のときに i、value、result がどう変わるかを表にすると、次のとおりです。
i | n * i | 直前の result | 追加処理 | 直後の result |
|---|---|---|---|---|
| 1 | 3 | "" | result += "3" | "3" |
| 2 | 6 | "3" | result += " 6" | "3 6" |
| 3 | 9 | "3 6" | result += " 9" | "3 6 9" |
| ... | ... | ... | ... | ... |
| 9 | 27 | "3 6 9 ... 24" | result += " 27" | "3 6 9 ... 27" |
この対応関係で意識してほしいのは「i は 1 から 9 まで、value は n * i の結果」という対応関係です。出力に並ぶのは value のほうであって、i そのものではありません。
文字列連結の素直な書き方
ここまでの考え方をそのままコードにすると、次のような形になります。
Java
public class Solution {
public static String multTable(int n) {
String result = "";
for (int i = 1; i <= 9; i++) {
int value = n * i;
if (i == 1) {
result = result + value;
} else {
result = result + " " + value;
}
}
return result;
}
}if (i == 1) の分岐は、末尾の空白を出さない ための工夫です。素直に result = result + value + " "; と書くと、"3 6 9 12 15 18 21 24 27 " のように最後に余計な空白が 1 つ残ってしまいます。今回のテストは末尾の空白に厳しいので、最初の 1 つは空白なしで、2 つ目以降は前に空白を付ける、という形で組み立てるのが王道です。
「空白を区切り文字として、最初だけ特別扱い」というパターンは、
forで文字列を組み立てるときの定番テクニックです。CSV、JSON 配列、SQL のIN句など、似た構造が至るところで顔を出します。一度覚えるとずっと使えます。
文字列連結が遅い問題と StringBuilder
上のコードは動きはしますが、Java 経験者が見るとちょっと顔をしかめます。理由は String の連結は遅い から、です。
Java の String はイミュータブル (一度作ったら変更できない) という性質があります。result = result + " " + value; と書くと、Java は内部で「新しい String オブジェクトを作って、中身を全部コピーして、古い result を捨てる」という処理をします。ループのたびにこれを繰り返すので、ループ回数が増えるほど効率が悪くなります。
今回のように 9 回だけなら全く問題ありませんが、これが 10000 回、100000 回となると話は別です。そこで Java には専用の道具 StringBuilder が用意されています。
Java
public class Solution {
public static String multTable(int n) {
StringBuilder sb = new StringBuilder();
for (int i = 1; i <= 9; i++) {
if (i > 1) {
sb.append(" ");
}
sb.append(n * i);
}
return sb.toString();
}
}StringBuilder は中身を書き換えられるバッファです。append で末尾に追加していき、最後に toString() で String に変換します。コピーが発生しないので、長いループでも快適に動きます。
入門のうちは
Stringの+連結で書いて構いません。九九の 9 回程度なら、最近のJVMはコンパイラ最適化で内部的にStringBuilderに置き換えてくれます。ただし「長いループで文字列を作るときはStringBuilderを使う」というキーワードは覚えておきましょう。コードレビューで指摘される定番の話題です。
よくある間違い
九九を for で書くとき、初心者がよくハマるポイントは大きく分けて 3 つあります。
- 0 から始める / 1 から始めるの混同 — 九九は
n * 1からn * 9までです。for (int i = 0; i < 9; i++)と書くとiは 0〜8 になり、n * 0 = 0が先頭に入ってしまいます。今回はi = 1; i <= 9; i++が正解です - 末尾の余計な空白 —
result = result + value + " ";のように書くと、最後の値の後ろにも空白が残ります。テストは"3 6 9 12 15 18 21 24 27"のように末尾に空白なしを期待しているので、if (i == 1)で分岐するか、if (i > 1)で先に空白を入れるパターンを使いましょう iとnの取り違え — 文字列に並べるのはn * iの結果であって、iそのものではありません。うっかりresult = result + i;と書くと"1 2 3 4 5 6 7 8 9"がいつも返ってきてしまい、n = 3でもn = 7でも同じ出力になります
もうひとつ、配列を使い慣れている人は int[] arr = new int[9]; のように配列に値を詰めてから String.join(" ", ...) でつなぎたくなりますが、入門段階では素直に for で文字列を組み立てるほうが、ループ変数の使い方が身につきます。
「動けば OK」ではなく「期待される文字列とぴったり一致するか」を意識してください。
" "(半角スペース 1 つ) と" "(半角スペース 2 つ) は別物として扱われ、テストは fail します。出力フォーマットの厳密さは、API レスポンスや CSV 生成の現場でもよく問われるテーマです。
ここまでの要点
ループ変数 i を n * i のように計算に使う発想を持つ。区切り文字は「先頭以外に前置」で末尾の余計な空白を防ぐ。長いループの文字列組み立ては StringBuilder で高速化。
やってみよう
それでは課題に挑戦してみましょう。手順は次のとおりです。
- 結果を貯める変数を用意する (
String result = "";またはStringBuilder sb = new StringBuilder();) for (int i = 1; i <= 9; i++)でiを 1 から 9 まで動かす- ループの中で
n * iを計算し、空白区切りで結果に追加する - 末尾に余計な空白が残らないように
ifで先頭だけ特別扱いする (または先に空白を入れる方式にする) - ループを抜けたら結果の文字列を
returnする
まずは String の + 連結で素直に書いて、テストが pass することを確認してみてください。pass したら、余裕があれば StringBuilder 版に書き換えて、同じテストが通るか試してみましょう。同じ仕様を 2 通りの書き方で実装すると、それぞれの強みと弱みが体で理解できます。
慣れてきたら、引数を int n, int max の 2 つに増やして「n の段を max までかける」ように改造したり、二重ループで 1 の段 から 9 の段 までを全部出力する全段表を作ったり、自由に発展させてみてください。
よくある質問
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 標準を固めるのが効率的です。
次のレッスン
次は while 文 で、for ループの応用として、引数 n の段の九九を空白区切りの文字列で組み立てる方法を学びます を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- 九九 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. 九九 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン
要件
- クラス名は
Solution、メソッド名はmultTable、引数はint n1 つ、戻り値の型はString forループを使い、iを 1 から 9 まで動かしながらn * iを組み立てること- 値同士の区切りは半角スペース 1 つ。末尾には余計な空白を残さないこと (
"3 6 9 12 15 18 21 24 27"の形式)
入出力例
test-cases.txt
multTable(3) → "3 6 9 12 15 18 21 24 27"
multTable(7) → "7 14 21 28 35 42 49 56 63"
multTable(1) → "1 2 3 4 5 6 7 8 9"
multTable(0) → "0 0 0 0 0 0 0 0 0"