コードに落とす練習の全体像
「例題をコードに落とす」とは、文章で書かれた問題を、入力・出力・処理手順・境界条件に分解して、テスト可能な小さな関数やプログラムに組み立てることです。重要なのは「考える順序」を固定すること。問題を読む→入力と出力を決める→制約と境界を洗い出す→手順(擬似コード)を書く→まず動く最小を作る→テスト→リファクタのサイクルで、正確さと読みやすさを両立させます。
問題分解の型(重要ポイントの深掘り)
入力・出力を先に固定する
コードは「関数(入力→出力)」の形で考えると壊れにくくなります。入出力が明確だと、テストが容易になり、内部実装の自由度が上がります。
// 例:文字列を受けて、単語数を返す
static int countWords(String text) { /* 実装 */ }
Java制約と境界条件を列挙する
「空文字」「null」「重複」「大文字小文字」「極端なサイズ」「外部仕様(文字コード・ロケール)」などを先取りし、仕様を言語化します。これがバグ予防線になります。
// 仕様例:空白は複数でも区切り、空文字は0、nullはIllegalArgumentException
Java擬似コードで「順序」を決める
いきなりコードにしない。箇条書きの手順(擬似コード)を作ると、実装に迷いがなくなります。
1. nullチェック
2. 先頭末尾の空白を削る
3. 連続空白を1つに正規化
4. 空なら0、そうでなければ分割して長さ
練習 1: FizzBuzz(仕様をコードへ)
仕様と分解
1から100までの整数を順に出力。3の倍数なら「Fizz」、5の倍数なら「Buzz」、両方なら「FizzBuzz」、それ以外は数値。
実装
public class FizzBuzz {
public static void main(String[] args) {
for (int i = 1; i <= 100; i++) {
System.out.println(label(i));
}
}
static String label(int n) {
boolean fizz = n % 3 == 0;
boolean buzz = n % 5 == 0;
if (fizz && buzz) return "FizzBuzz";
if (fizz) return "Fizz";
if (buzz) return "Buzz";
return Integer.toString(n);
}
}
Java重要ポイント
分岐の優先順位を「両方→片方→通常」に固定。判定を変数へ落とすと読みやすく、テストしやすくなります。
練習 2: 単語数カウント(入力正規化の設計)
仕様と分解
文字列中の単語数を数える。空白で分割。空文字は0。nullは例外。複数空白や改行は区切りとして扱う。
実装
public final class WordCounter {
public static int countWords(String text) {
if (text == null) throw new IllegalArgumentException("text must not be null");
String trimmed = text.trim();
if (trimmed.isEmpty()) return 0;
String normalized = trimmed.replaceAll("\\s+", " ");
return normalized.split(" ").length;
}
}
Java重要ポイント
前処理(trim、連続空白の正規化)で仕様を「単純な分割」に落とす。例外方針を明文化すると、呼び手の責務が明確になります。
練習 3: 配列の中央値(境界とアルゴリズム)
仕様と分解
整数配列の中央値を返す。要素数が奇数なら中央、偶数なら2つの平均(切り捨てでなく四捨五入)。空配列は例外。
実装
import java.util.Arrays;
public final class Median {
public static double median(int[] xs) {
if (xs == null || xs.length == 0) throw new IllegalArgumentException("empty");
int[] a = Arrays.copyOf(xs, xs.length);
Arrays.sort(a);
int n = a.length;
if (n % 2 == 1) return a[n / 2];
int left = a[n / 2 - 1], right = a[n / 2];
return (left + right) / 2.0; // 小数で返す(四捨五入不要)
}
}
Java重要ポイント
元配列を破壊しないためにコピーしてからソート。偶数ケースの平均は double で返すと誤差や丸めの曖昧さを避けられます。
練習 4: コマンドライン集計(入力検証と終了コード)
仕様と分解
引数で整数を受け取り合計を出力。不正入力があればエラーメッセージを出して失敗終了。引数なしはヘルプ。
実装
public class SumApp {
public static void main(String[] args) {
if (args.length == 0) {
System.err.println("usage: SumApp <ints...>");
System.exit(1);
}
try {
int sum = java.util.Arrays.stream(args).mapToInt(Integer::parseInt).sum();
System.out.println(sum);
System.exit(0);
} catch (NumberFormatException e) {
System.err.println("invalid number: " + e.getMessage());
System.exit(2);
}
}
}
Java重要ポイント
「成功=0、入力エラー=1〜2」など終了コードの契約を決める。標準出力と標準エラーを使い分けると、運用が明快になります。
練習 5: ファイルの行数カウント(リソースと例外)
仕様と分解
UTF-8 のテキストファイルの行数を出力。ファイルがない・読めない場合は理由を表示して失敗終了。
実装
import java.nio.file.*;
import java.nio.charset.StandardCharsets;
import java.io.*;
public class LineCount {
public static void main(String[] args) {
if (args.length < 1) {
System.err.println("usage: LineCount <path>");
System.exit(1);
}
var path = Path.of(args[0]);
try (var br = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
long count = 0;
while (br.readLine() != null) count++;
System.out.println(count);
System.exit(0);
} catch (IOException e) {
System.err.println("read error: " + e.getMessage());
System.exit(3);
}
}
}
Java重要ポイント
文字コードは必ず指定(UTF-8)。try-with-resources で確実にクローズ。例外をユーザー向けメッセージ+終了コードに変換します。
練習 6: 仕様から関数へ(メールバリデーションの最小版)
仕様と分解
メールアドレスの「最低限」チェック。空白なし、1つだけ @ を含む、@ の前後が空でない。細かい RFC 準拠は不要。
実装
public final class EmailValidator {
public static boolean isSimpleValid(String s) {
if (s == null) return false;
String x = s.trim();
if (x.isEmpty() || x.contains(" ")) return false;
int at = x.indexOf('@');
if (at <= 0 || at != x.lastIndexOf('@')) return false;
if (at == x.length() - 1) return false;
return true;
}
}
Java重要ポイント
「最低限の仕様」を明示して過剰な複雑性を避ける。要件が増えたら段階的に拡張し、テストを追加していきます。
小さく作って磨くサイクル
最小の正しさを先に
すべての境界を一気に詰めるより、「最小仕様を満たす」版を先に動かし、次に境界・性能を足していきます。早いフィードバックが最強の武器です。
テストを伴走させる
問題の例と境界に対応するテストを作り、毎回通ることを確認しながら拡張します。関数化した入出力はテストしやすく、失敗の位置特定も容易です。
static void test() {
assert WordCounter.countWords("a b c") == 3;
assert EmailValidator.isSimpleValid("a@b");
assert !EmailValidator.isSimpleValid(" @b");
}
Javaリファクタで読みやすさを上げる
重複・長すぎるメソッド・曖昧な命名を直し、例外方針やコメント(なぜ)を整えます。「最初に完璧」は不要、磨き続ける習慣が品質を作ります。
仕上げのアドバイス(重要部分のまとめ)
入出力を先に固定し、制約と境界を言語化、擬似コードで順序を決め、最小で動かしてからテストとリファクタを回す——この型を身体に入れると、どんな例題でも迷わずコードに落とせます。分岐は優先順位を明確に、前処理で仕様を単純化、外部I/Oは文字コード指定、失敗はメッセージ+終了コードに変換。小さな関数へ分割して、テスト可能な形で進めるのが最短です。
