はじめに
Java基礎学習のアウトプットとして、
学生の追加・削除・更新・平均点計算を行うCLIアプリを実装しました。
シンプルなCRUD処理ですが、実装の中で以下の点につまずきました。
- Listは戻り値で返さないと更新されない?
- Streamのfilterは元のListを変更する?
- mapToIntの意味が分からない
- isBlankとisEmptyの違い
- booleanで処理結果を返す設計
この記事では、クラス構成 → ソースコード → 学びの振り返り の順で整理します。
アプリの仕様
コンソール上で以下の操作が可能です。
- 学生を追加
- 学生を削除
- 点数を更新
- 平均点を計算
- 全学生の情報を表示
- 終了
クラス構成
今回の構成は以下の通りです。
org.example
├── Main.java // 入力制御・画面表示
├── Student.java // 学生エンティティ
└── IndexStudent.java // 業務ロジック
役割を明確に分けることで、責務を整理しました。
| クラス | 役割 |
|---|---|
| Main | ユーザー入力と画面制御 |
| Student | データ保持 |
| IndexStudent | CRUD処理と計算ロジック |
Student.java(データクラス)
package org.example;
public class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}
ポイント
- フィールドは
private - getter / setterでアクセス
- シンプルなPOJO
IndexStudent.java(ロジッククラス)
package org.example;
import java.util.List;
public class IndexStudent {
public boolean addition(List<Student> list, String name, int score) {
if (!isValidName(name) && !isValidScore(score)) {
return false;
}
list.add(new Student(name, score));
return true;
}
public boolean delete(List<Student> list, String name) {
if (!isValidName(name)) {
return false;
}
list.removeIf(v -> v.getName().equals(name));
return true;
}
public boolean update(List<Student> list, String name, int score) {
if (!isValidName(name) && isValidScore(score)) {
return false;
}
for (Student student : list) {
if (student.getName().equals(name)) {
student.setScore(score);
return true;
}
}
return false;
}
public double average(List<Student> list) {
if (list == null || list.isEmpty()) {
return 0.0;
}
return list.stream()
.mapToInt(Student::getScore)
.average()
.orElse(0.0);
}
public void printAll(List<Student> list) {
if (list.isEmpty()) {
System.out.println("学生情報がありません。学生情報を入力してください。");
return;
}
System.out.println("学生一覧:");
for (Student student : list) {
System.out.println(student.getName() + ":" + student.getScore());
}
}
/* 入力チェック */
private boolean isValidName(String name) {
return name != null && !name.isBlank();
}
private boolean isValidScore(int score) {
return score >= 0 && score <= 100;
}
}
Main.java(入力制御)
package org.example;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
List<Student> studentList = new ArrayList<>();
IndexStudent indexStudent = new IndexStudent();
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("1. 学生を追加");
System.out.println("2. 学生を削除");
System.out.println("3. 点数を更新");
System.out.println("4. 平均点を計算");
System.out.println("5. 全学生の情報を表示");
System.out.println("6. 終了");
System.out.print("選択してください: ");
int number;
try {
number = scanner.nextInt();
} catch (Exception e) {
System.out.println("数字を入力してください。");
scanner.nextLine();
continue;
}
if (number == 1) {
System.out.print("学生の名前を入力してください: ");
String name = scanner.next();
System.out.print(name + "の点数を入力してください: ");
int score = scanner.nextInt();
if (!indexStudent.addition(studentList, name, score)) {
System.out.println("入力が不正です。");
}
} else if (number == 2) {
System.out.print("削除する学生の名前を入力してください: ");
String name = scanner.next();
if (!indexStudent.delete(studentList, name)) {
System.out.println("削除できませんでした。");
}
} else if (number == 3) {
System.out.print("更新する学生の名前を入力してください: ");
String name = scanner.next();
System.out.print(name + "の点数を入力してください: ");
int score = scanner.nextInt();
if (!indexStudent.update(studentList, name, score)) {
System.out.println("更新できませんでした。");
}
} else if (number == 4) {
System.out.println("平均点は: " + indexStudent.average(studentList));
} else if (number == 5) {
indexStudent.printAll(studentList);
} else if (number == 6) {
System.out.println("終了します。");
break;
} else {
System.out.println("1~6を選択してください。");
}
}
scanner.close();
}
}
実装で学んだこと
① Listは戻り値で返さなくても更新される
Listは参照型です。
list.add(student);
とすると、呼び出し元のListも変更されます。
そのため、戻り値でListを返す必要はありません。
② addの2つの書き方は同じ
Student s = new Student(name, score);
list.add(s);
と
list.add(new Student(name, score));
は本質的に同じです。
③ Streamのfilterは元のListを変更しない
list.stream().filter(...)
これは新しいStreamを作るだけで、
元のListは変更されません。
④ mapToIntの意味
.mapToInt(Student::getScore)
これは
- Student → int に変換
- 数値Streamにすることで average() を使用可能
という役割があります。
⑤ isBlankとisEmptyの違い
| メソッド | 意味 |
|---|---|
| isEmpty() | 長さが0 |
| isBlank() | 空白のみも空扱い |
入力チェックには isBlank() が適切です。
まとめ
今回の実装で得られた学び:
- 参照型の挙動
- Stream APIの基本
- mapToIntの意味
- 入力値バリデーション
- booleanで結果を返す設計
小さなCRUDアプリでも、Javaの基礎が多く詰まっています。
今後は、
- Optionalの理解を深める
- 重複チェック機能の追加
- 例外設計の改善
などに挑戦したいと思います。
以上、Java初心者が簡単な処理機能を実装してみた記録でした。