Java | 1 日 90 分 × 7 日アプリ学習 初級編:ミニToDoアプリ(CUI)

Web APP Java
スポンサーリンク

1日目のゴール

1日目のテーマは
「ミニToDoアプリを“ちゃんとクラス設計して、List で管理し、入力で動かす”感覚をつかむこと」 です。

いきなり完璧なアプリを作るのではなく、

クラスをどう分けるか
タスクを List でどう持つか
コンソールからの入力をどう扱うか

この3つを、シンプルな ToDo アプリを通して体に入れていきます。

機能は最小限です。

タスクを追加する
タスクを一覧表示する
タスクを削除する

今日は「CUI(コンソール)」版でやります。


全体設計を先に“言葉”で決める

どんなクラスが必要かを考える

いきなりコードに行かず、まずは言葉で設計します。

タスク1件分を表すクラス(Task)
タスクの一覧を管理するクラス(TaskManager)
アプリ全体の流れを持つクラス(Main)

この3つに分けると、きれいに整理できます。

Task は「1件分のデータ」
TaskManager は「Task の List を管理する役」
Main は「ユーザーとのやりとり(入力・メニュー)」

という役割分担です。


タスク1件分を表す Task クラス

Task クラスの基本形

まずは「タスク1件」をクラスにします。

public class Task {
    String title;

    Task(String title) {
        if (title == null || title.isEmpty()) {
            throw new IllegalArgumentException("タイトルは必須です。");
        }
        this.title = title;
    }

    void show(int index) {
        System.out.println(index + ": " + title);
    }
}
Java

ここでやっていることを整理します。

タイトルだけを持つシンプルなタスク
コンストラクタで「空文字や null を防ぐ」
show で「自分を表示する」

1日目なので、状態は「タイトルだけ」に絞っています。
あとで「完了フラグ」などを足す余地を残しておくイメージです。


タスク一覧を管理する TaskManager クラス

ArrayList でタスクを持つ

タスクは「何件になるか分からない」ので、
ArrayList<Task> で持つのが自然です。

import java.util.ArrayList;

public class TaskManager {
    ArrayList<Task> tasks;

    TaskManager() {
        tasks = new ArrayList<>();
    }
}
Java

ここでのポイントは、

TaskManager が「タスクの List を抱える役」
Main からは、なるべく tasks を直接触らない

という設計にすることです。


タスクを追加するメソッド

void addTask(String title) {
    try {
        Task task = new Task(title);
        tasks.add(task);
        System.out.println("タスクを追加しました: " + title);
    } catch (IllegalArgumentException e) {
        System.out.println("タスクの追加に失敗しました: " + e.getMessage());
    }
}
Java

ここで大事なのは、

Task の生成(バリデーション付き)
List への追加
メッセージ表示

を TaskManager の中に閉じ込めていることです。

Main 側は「タイトルを渡すだけ」で済みます。


タスク一覧を表示するメソッド

void showAll() {
    System.out.println("=== タスク一覧 ===");
    if (tasks.isEmpty()) {
        System.out.println("タスクはありません。");
        return;
    }
    for (int i = 0; i < tasks.size(); i++) {
        Task t = tasks.get(i);
        t.show(i);
    }
}
Java

ここでのポイントは、

インデックス(0,1,2…)を一緒に表示している
このインデックスを「削除するときの番号」として使う

という設計です。

「番号で指定して削除する」ために、
一覧表示のときに番号を見せています。


タスクを削除するメソッド

void removeTask(int index) {
    if (index < 0 || index >= tasks.size()) {
        System.out.println("その番号のタスクは存在しません。");
        return;
    }
    Task removed = tasks.remove(index);
    System.out.println("タスクを削除しました: " + removed.title);
}
Java

ここで重要なのは、

インデックスの範囲チェックを必ずする
remove(index) で、その位置のタスクを削除できる
削除された Task を戻り値として受け取れるので、メッセージに使える

という点です。


入力処理の基本:Scanner とメニュー

Scanner でコンソール入力を受け取る

Java で CUI の入力を扱うときの定番が Scanner です。

import java.util.Scanner;
Java

Main でこう使います。

Scanner scanner = new Scanner(System.in);
Java

これで、キーボードからの入力を読み取れるようになります。


メニューを表示して、ユーザーに選んでもらう

1日目のメニューはシンプルにします。

1: 追加
2: 一覧
3: 削除
0: 終了

これをコードにすると、こうなります。

public class Main {
    public static void main(String[] args) {
        TaskManager manager = new TaskManager();
        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.println();
            System.out.println("=== ミニToDoアプリ ===");
            System.out.println("1: タスク追加");
            System.out.println("2: タスク一覧");
            System.out.println("3: タスク削除");
            System.out.println("0: 終了");
            System.out.print("番号を選んでください: ");

            String line = scanner.nextLine();

            if (line.equals("0")) {
                System.out.println("終了します。");
                break;
            } else if (line.equals("1")) {
                System.out.print("タスクのタイトルを入力してください: ");
                String title = scanner.nextLine();
                manager.addTask(title);
            } else if (line.equals("2")) {
                manager.showAll();
            } else if (line.equals("3")) {
                manager.showAll();
                System.out.print("削除したいタスクの番号を入力してください: ");
                String indexStr = scanner.nextLine();
                try {
                    int index = Integer.parseInt(indexStr);
                    manager.removeTask(index);
                } catch (NumberFormatException e) {
                    System.out.println("番号は整数で入力してください。");
                }
            } else {
                System.out.println("不正な入力です。もう一度選んでください。");
            }
        }

        scanner.close();
    }
}
Java

入力処理で特に大事なポイント

文字列として受け取ってから解釈する

scanner.nextLine() は「1行まるごと文字列」で受け取ります。

メニュー番号
削除したいタスクの番号

どちらも、まずは String として受け取り、
必要に応じて Integer.parseInt で数値に変換しています。

ここで大事なのは、

入力は「必ず文字列として入ってくる」
「どう解釈するか」は自分で決める

という感覚です。


例外をキャッチしてアプリを落とさない

削除番号のところで、こう書きました。

try {
    int index = Integer.parseInt(indexStr);
    manager.removeTask(index);
} catch (NumberFormatException e) {
    System.out.println("番号は整数で入力してください。");
}
Java

ユーザーが「abc」などの変な文字を入れても、
アプリが落ちずにメッセージを出して続行できます。

「入力は信用しない」
「変な入力が来ても落ちないようにする」

これは、アプリを書くときの大事な姿勢です。


1日目のミニToDoアプリ全体像

TaskManager 全体

import java.util.ArrayList;

public class TaskManager {
    ArrayList<Task> tasks;

    TaskManager() {
        tasks = new ArrayList<>();
    }

    void addTask(String title) {
        try {
            Task task = new Task(title);
            tasks.add(task);
            System.out.println("タスクを追加しました: " + title);
        } catch (IllegalArgumentException e) {
            System.out.println("タスクの追加に失敗しました: " + e.getMessage());
        }
    }

    void showAll() {
        System.out.println("=== タスク一覧 ===");
        if (tasks.isEmpty()) {
            System.out.println("タスクはありません。");
            return;
        }
        for (int i = 0; i < tasks.size(); i++) {
            Task t = tasks.get(i);
            t.show(i);
        }
    }

    void removeTask(int index) {
        if (index < 0 || index >= tasks.size()) {
            System.out.println("その番号のタスクは存在しません。");
            return;
        }
        Task removed = tasks.remove(index);
        System.out.println("タスクを削除しました: " + removed.title);
    }
}
Java

Main 全体(再掲)

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        TaskManager manager = new TaskManager();
        Scanner scanner = new Scanner(System.in);

        while (true) {
            System.out.println();
            System.out.println("=== ミニToDoアプリ ===");
            System.out.println("1: タスク追加");
            System.out.println("2: タスク一覧");
            System.out.println("3: タスク削除");
            System.out.println("0: 終了");
            System.out.print("番号を選んでください: ");

            String line = scanner.nextLine();

            if (line.equals("0")) {
                System.out.println("終了します。");
                break;
            } else if (line.equals("1")) {
                System.out.print("タスクのタイトルを入力してください: ");
                String title = scanner.nextLine();
                manager.addTask(title);
            } else if (line.equals("2")) {
                manager.showAll();
            } else if (line.equals("3")) {
                manager.showAll();
                System.out.print("削除したいタスクの番号を入力してください: ");
                String indexStr = scanner.nextLine();
                try {
                    int index = Integer.parseInt(indexStr);
                    manager.removeTask(index);
                } catch (NumberFormatException e) {
                    System.out.println("番号は整数で入力してください。");
                }
            } else {
                System.out.println("不正な入力です。もう一度選んでください。");
            }
        }

        scanner.close();
    }
}
Java

1日目で絶対に押さえてほしい本質

今日いちばん大事なのは、
「クラス設計・List 管理・入力処理が、“1つのアプリ”の中でちゃんとつながった感覚」 を持てたかどうかです。

Task は「1件分のデータ」
TaskManager は「Task の List を管理する役」
Main は「ユーザーとの会話(入力・メニュー)」

そして、

タスクは ArrayList<Task> で可変長に持つ
一覧表示ではインデックスも一緒に見せる
削除はインデックス指定で行う
入力は文字列で受け取り、自分で解釈する

ここまでが自然に説明できれば、
2日目以降に「完了フラグ」「保存」「優先度」などを足していくときも、
迷わず設計を広げていけます。

もし余裕があれば、
メニューに「何もせず Enter だけ押したらどうなるか」など、
わざと変な入力をして、アプリの振る舞いを観察してみてください。
そこから「次にどんなガードを書きたいか」が見えてきます。

タイトルとURLをコピーしました