Java | 1 日 90 分 × 7 日アプリ学習 初級編:List を使うアプリ

Web APP Java
スポンサーリンク

5日目のゴール

5日目のテーマは
「ArrayList の“順番”を意識して扱えるようになること」 です。

ここまでであなたは、

ArrayList は伸び縮みする箱
クラスのフィールドとして ArrayList を持てる
オブジェクト(Task など)のリストを作れる
探す・更新する・削除する、といった操作ができる

というところまで来ています。

5日目ではここから一歩進んで、

ArrayList の「順番」が意味を持つこと
並び替え(ソート)という考え方
“同じ中身を持つ別のリスト”を作るときの注意点

を、小さな「本の並び替えアプリ」を題材にして固めていきます。


今日の題材:本のリストを「並び替え」できるようにする

まずはシンプルな Book クラス

本を表すクラスを用意します。

public class Book {
    String title;
    int price;

    Book(String title, int price) {
        if (title == null || title.isEmpty()) {
            throw new IllegalArgumentException("タイトルは必須です。");
        }
        if (price < 0) {
            throw new IllegalArgumentException("価格は 0 以上で指定してください。");
        }
        this.title = title;
        this.price = price;
    }

    void show() {
        System.out.println("タイトル: " + title + " / 価格: " + price + "円");
    }
}
Java

ここでは「タイトル」と「価格」だけに絞っています。
1冊分の情報をまとめて持つ、というこれまでの流れの延長です。

本のリストを管理する BookList クラス

import java.util.ArrayList;

public class BookList {
    ArrayList<Book> books;

    BookList() {
        books = new ArrayList<>();
    }

    void add(Book book) {
        if (book == null) {
            System.out.println("null の本は追加できません。");
            return;
        }
        books.add(book);
    }

    void showAll() {
        System.out.println("=== 本一覧 ===");
        if (books.isEmpty()) {
            System.out.println("本はまだありません。");
            return;
        }
        for (int i = 0; i < books.size(); i++) {
            System.out.print((i + 1) + "冊目: ");
            books.get(i).show();
        }
    }
}
Java

ここまでは、これまでと同じ「可変長データをクラスの中に閉じ込める」パターンです。
ここから、この books の「順番」を意識して扱っていきます。


ArrayList の「順番」は意味を持つ

順番が変わると“見え方”が変わる

次のように本を追加してみます。

public class Main {
    public static void main(String[] args) {
        BookList list = new BookList();

        list.add(new Book("Java入門", 3000));
        list.add(new Book("アルゴリズム図鑑", 2500));
        list.add(new Book("オブジェクト指向設計", 4000));

        list.showAll();
    }
}
Java

このときの表示は、追加した順番になります。

1冊目: Java入門
2冊目: アルゴリズム図鑑
3冊目: オブジェクト指向設計

でも、現実のアプリでは、

価格の安い順に並べたい
タイトルの五十音順に並べたい

といった「並び替え」がしたくなります。

ここで初めて、
「ArrayList の順番を意図的に変える」
という操作が必要になります。


価格の昇順に並び替える(自前ソート)

まずは「一番安い本」を見つけるイメージ

いきなり全部を並び替えるのではなく、
まずは「一番安い本を見つける」ことから考えます。

Book findCheapest() {
    if (books.isEmpty()) {
        return null;
    }
    Book cheapest = books.get(0);
    for (int i = 1; i < books.size(); i++) {
        Book current = books.get(i);
        if (current.price < cheapest.price) {
            cheapest = current;
        }
    }
    return cheapest;
}
Java

ここでやっていることは、とてもシンプルです。

最初に「仮の最安」を 0 番目にしておく
1番目以降を順番に見ていき、もっと安い本があれば更新する
最後に「一番安かった本」を返す

これは「最小値を探す」という基本パターンです。
この考え方を、並び替えに発展させます。

選択ソートという考え方

「一番安い本を先頭に持ってくる」
「残りの中で一番安い本を2番目に持ってくる」
…というのを繰り返すと、
価格の昇順に並び替えられます。

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

void sortByPriceAsc() {
    for (int i = 0; i < books.size() - 1; i++) {
        int minIndex = i;
        for (int j = i + 1; j < books.size(); j++) {
            if (books.get(j).price < books.get(minIndex).price) {
                minIndex = j;
            }
        }
        if (minIndex != i) {
            Book tmp = books.get(i);
            books.set(i, books.get(minIndex));
            books.set(minIndex, tmp);
        }
    }
}
Java

少し長いので、流れを言葉で追ってみます。

外側の for(i)は「確定させる位置」を表す
i 番目に「その位置に来るべき最安の本」を置きたい
内側の for(j)は「i 以降の中で最安の本の位置」を探す
minIndex に「最安の本のインデックス」を覚えておく
見つかった最安の本と、i 番目の本を入れ替える

ここで新しく出てきた set も重要です。

books.set(i, books.get(minIndex));
Java

set(index, value) は、
「index 番目の要素を value に置き換える」メソッドです。

add は「間に割り込んで押し出す」
set は「その場所の中身だけを上書きする」

という違いがあります。


並び替え前後を Main から確認する

実行イメージをつかむ

BookListsortByPriceAsc を追加したとします。

public class Main {
    public static void main(String[] args) {
        BookList list = new BookList();

        list.add(new Book("Java入門", 3000));
        list.add(new Book("アルゴリズム図鑑", 2500));
        list.add(new Book("オブジェクト指向設計", 4000));

        System.out.println("=== 並び替え前 ===");
        list.showAll();

        list.sortByPriceAsc();

        System.out.println("=== 価格の安い順に並び替えた後 ===");
        list.showAll();
    }
}
Java

表示はこういうイメージになります。

並び替え前
1冊目: Java入門(3000)
2冊目: アルゴリズム図鑑(2500)
3冊目: オブジェクト指向設計(4000)

並び替え後
1冊目: アルゴリズム図鑑(2500)
2冊目: Java入門(3000)
3冊目: オブジェクト指向設計(4000)

ここで感じてほしいのは、

ArrayList の「中身の順番」を自分でコントロールできる
順番が変わると、アプリの“見え方”も変わる

ということです。


「別のリストにコピーする」ときの落とし穴

代入は“同じリストを指すだけ”

次のコードを見てください。

ArrayList<Book> a = new ArrayList<>();
a.add(new Book("Java入門", 3000));

ArrayList<Book> b = a;

b.add(new Book("アルゴリズム図鑑", 2500));

System.out.println(a.size());  // いくつ?
System.out.println(b.size());  // いくつ?
Java

直感的には「a と b は別物だから、サイズも違うはず」と思いがちですが、
実際にはどちらも 2 になります。

理由はシンプルで、

ArrayList<Book> b = a;
「a と同じリストを b という別名で呼んでいるだけ」
だからです。

a と b は「別の箱」ではなく、
同じ ArrayList オブジェクトを指す“2つの変数”になっています。

本当に“別のリスト”が欲しいとき

「a の中身をコピーして、b は b で自由に並び替えたい」
というときは、こう書きます。

ArrayList<Book> a = new ArrayList<>();
a.add(new Book("Java入門", 3000));
a.add(new Book("アルゴリズム図鑑", 2500));

ArrayList<Book> b = new ArrayList<>(a);
Java

new ArrayList<>(a) は、
「a と同じ要素を持つ新しい ArrayList」を作ります。

ここで大事なのは、

リストそのものは別物になる
でも、中に入っている Book オブジェクトは同じ参照

という点です。

つまり、

b 側で b.set(0, new Book(...)) のように「要素そのもの」を差し替える
→ a には影響しない

b 側で b.get(0).price = 1000; のように「Book の中身」を変える
→ a 側から見える Book も同じように変わる

という動きになります。

ここで感じてほしいのは、

ArrayList 自体と、その中に入っているオブジェクト
この2つを頭の中で分けて考える必要がある

ということです。


5日目のミニアプリ完成形

BookList に並び替えとコピーを追加した形

import java.util.ArrayList;

public class BookList {
    ArrayList<Book> books;

    BookList() {
        books = new ArrayList<>();
    }

    BookList(ArrayList<Book> source) {
        books = new ArrayList<>(source);
    }

    void add(Book book) {
        if (book == null) {
            System.out.println("null の本は追加できません。");
            return;
        }
        books.add(book);
    }

    void showAll() {
        System.out.println("=== 本一覧 ===");
        if (books.isEmpty()) {
            System.out.println("本はまだありません。");
            return;
        }
        for (int i = 0; i < books.size(); i++) {
            System.out.print((i + 1) + "冊目: ");
            books.get(i).show();
        }
    }

    void sortByPriceAsc() {
        for (int i = 0; i < books.size() - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < books.size(); j++) {
                if (books.get(j).price < books.get(minIndex).price) {
                    minIndex = j;
                }
            }
            if (minIndex != i) {
                Book tmp = books.get(i);
                books.set(i, books.get(minIndex));
                books.set(minIndex, tmp);
            }
        }
    }
}
Java

Main で「元の順番」と「並び替え後」を両方見る

public class Main {
    public static void main(String[] args) {
        BookList original = new BookList();
        original.add(new Book("Java入門", 3000));
        original.add(new Book("アルゴリズム図鑑", 2500));
        original.add(new Book("オブジェクト指向設計", 4000));

        System.out.println("=== 元の順番 ===");
        original.showAll();

        BookList sorted = new BookList(original.books);
        sorted.sortByPriceAsc();

        System.out.println("=== 価格の安い順(別リスト) ===");
        sorted.showAll();

        System.out.println("=== 元の順番は変わっていないか? ===");
        original.showAll();
    }
}
Java

ここで確認してほしいのは、

originalsorted は別の BookList
sorted の中の ArrayList は、original.books をコピーして作っている
sorted を並び替えても、original の順番は変わらない

という動きです。


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

今日いちばん大事なのは、
「ArrayList の“順番”と、“中身のオブジェクト”を分けて考えられるようになったかどうか」 です。

ArrayList の順番は、アプリの見え方に直結する
set を使うと「その場所の中身だけ」を入れ替えられる
自前でソートを書くと、「最小値を探す」「入れ替える」という基本パターンが見えてくる
new ArrayList<>(元リスト) で「同じ要素を持つ別リスト」を作れる
ただし、中のオブジェクトは同じ参照なので、「中身を書き換える」と両方に影響する

この感覚が入っていれば、
6日目以降にやる「標準ライブラリの sort を使う」「Comparator で並び替え条件を変える」
といった、より実践的なテクニックもスッと入ってくるようになります。

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