読み込み中...

Javaソートの究極プログラミングガイド!初心者からプロへの10ステップ

初心者でも理解できるJavaソートの方法と実用的なサンプルコードの図解 Java
この記事は約33分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Javaのソートは、配列やリストを目的の順序へ並べ替える処理で、プログラミングの学習でも業務アプリケーションの設計でも頻繁に扱います。そのため、Arrays.sortCollections.sortComparatorComparableの使い分けを押さえると、数値、文字列、オブジェクトを自然な形で整列できます。

このJavaソート方法の初心者ガイドでは、標準ライブラリを中心に、Javaソート例とソートアルゴリズムの考え方を結び付けて整理するのが基本です。ただし、コードの表示内容は環境や文字コードに影響される場合があるため、各サンプルでは実行断定ではなく期待される出力として示します。

動作確認環境
  • JDK 21
  • Java SE 21 API仕様を参照
  • 標準ライブラリ: java.utiljava.lang
📖 この記事で学べること
  • Arrays.sortCollections.sortの使い分け
  • ComparableComparatorによるオブジェクト整列
  • nullや型混在で起きる例外への対処
  • thenComparingStream.sortedを使うJavaソート例
  • ソート技法をプログラミング課題へ応用する考え方

Javaとソートの基本概念

ソートとは、データを一定の規則に沿って並べ替える処理です。数値なら昇順や降順、文字列なら辞書順、オブジェクトなら年齢や名前などの属性が基準になります。その基準をコードで表す部分が、Javaソート方法を理解する入り口になります。

Javaでは、配列向けにjava.util.Arrays、コレクション向けにjava.util.CollectionsList.sortが用意されているのが目安です。公式ドキュメントによれば、Arraysは配列の操作、検索、整列を扱うユーティリティクラスです。一方、CollectionsListなどのコレクションに対する多態的なアルゴリズムを提供します。

これらのAPIを使うと、単純なソート技法は短いコードで表現できます。ただし、どの順序で比べるのか、同じ値をどう扱うのか、nullを許すのかという判断はプログラム側に残りますし、ここがポイントです。初心者ガイドとして特に押さえたいのは、標準APIの呼び出し方だけでなく、比較条件を明確にする姿勢です。

対象主なAPI比較基準向く場面注意点
数値配列Arrays.sort自然順序昇順の整列元の配列を書き換える
文字列配列Arrays.sortString.compareTo辞書順の整列大文字小文字の扱いに注意
リストCollections.sort自然順序ArrayListの整列要素が相互比較可能である必要がある
カスタムクラスComparablecompareTo標準順序をクラスに持たせる基準を一種類に寄せやすい
カスタム条件Comparatorcompare画面や帳票ごとに順序を変える比較の一貫性を保つ
複数キーthenComparing主キーと副キー年齢順のあと名前順同値時の順序を明示する
Stream処理Stream.sorted自然順序または比較関数加工と整列をつなぐ新しいリストへ集約する

なぜJavaでソートを学ぶのか

JavaはWebアプリケーション、業務システム、Android関連のプログラミング、バッチ処理などで広く使われます。その中でソートは、一覧表示、ランキング、検索結果、ログ解析、CSV加工などに直結する操作です。データを見やすくするだけでなく、後続の二分探索や集計処理にも影響します。

一般に、初心者がつまずきやすいのは、配列とリストのAPIを混同する場面です。int[]にはArrays.sortを使い、List<String>にはCollections.sortlist.sortを使いるのがポイントです。この違いを覚えると、Javaソート例を読んだときに処理対象をすぐ判断できます。

そのうえで、ソートアルゴリズムの名前を丸暗記するより、入力、比較基準、出力の変化を追うほうが学習しやすくなります。バブルソート、選択ソート、挿入ソート、マージソートといった言葉は、標準APIの裏側を理解する手がかりになるのが一般的です。Javaソート方法を実務的に使うなら、標準APIを信頼しつつ、比較条件を自分で設計する流れが自然です。

関連する基礎として、リスト操作はJava List型完全ガイド、注釈の読み方はJavaアノテーションの12選も合わせて確認できます。こうした周辺知識があると、ソート技法を単独の文法ではなく、Javaプログラミング全体の部品として扱えます。

Javaソートの基本

Javaソートの基本は、自然順序で並べる処理と、独自の比較条件で並べる処理に分かれますが、これは押さえたい点です。自然順序とは、Integerなら数値の小さい順、Stringなら辞書順のように、型がもともと持つ並び方です。独自条件は、年齢順、価格順、更新日時順など、プログラムの目的に合わせて作ります。

ソートとは

ソートは、要素どうしを比較しながら順序を整える処理です。配列やリストの中身がランダムな順番でも、比較規則を与えることで一覧性が高まります。データ件数が増えるほど、手作業で並べ替える発想ではなく、再利用できるソート技法が必要になるのが現実的です。

ソートの種類

代表的なソートアルゴリズムには、隣接要素を入れ替えるバブルソート、最小値を探して配置する選択ソート、整列済み部分へ差し込む挿入ソート、分割と統合を使うマージソートがあります。ただし、通常のJavaプログラミングでは、これらを手で実装するより標準ライブラリを使うほうが読みやすくなります。

その理由は、標準APIが型ごとの最適化や安定性を考慮しているためです。学習段階ではソートアルゴリズムの考え方を理解し、実装ではArrays.sortCollections.sortComparator.comparingなどを選ぶと整理できると整理できます。

Javaでのソートの基本的な使い方

Javaで配列を整列するときはArrays、リストを整列するときはCollectionsまたはList.sortが出発点になります。この区別はJavaソート方法の土台です。型に合わないAPIを選ぶと、コンパイルエラーや意図しない処理につながります。

Arraysクラスを用いたソート

配列は固定長のデータ構造で、int[]String[]のように宣言すると理解できます。その配列を昇順に並べるJavaソート例では、Arrays.sortを呼び出すだけで十分です。

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] arr = {3, 5, 1, 4, 2};
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));
    }
}

結果: 期待される出力は[1, 2, 3, 4, 5]です。Arrays.toStringによって配列の中身を読みやすい文字列へ変換しています。

このとき、Arrays.sortは元のarr自体を書き換えます。元の順序を残したい場合は、Arrays.copyOfで複製してからソートする設計が扱いやすくなると覚えるとよいでしょう。

Collectionsクラスを用いたソート

リストは要素数を増減しやすいデータ構造で、ArrayListなどがよく使われます。Collections.sortListを自然順序で整列し、文字列なら辞書順に並びます。

import java.util.ArrayList;
import java.util.Collections;

public class Main {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("Banana");
        list.add("Apple");
        list.add("Cherry");
        Collections.sort(list);
        System.out.println(list);
    }
}

結果: 期待される出力は[Apple, Banana, Cherry]です。Collections.sortはリストを直接並べ替えるため、戻り値ではなくlistの中身が変わります。

💡 Tips: 新しいコードではlist.sort(Comparator.naturalOrder())のように、リスト自身のsortメソッドを使う書き方も一般的です。既存コードとの整合が必要な場面ではCollections.sortも読み解けるようにしておくと安心です。

詳細な使い方

基本データ型や文字列の整列では、比較関数を自作しなくても自然順序が使えます。こうしたJavaソート例は、初心者ガイドの中でも最初に動きをつかみやすい題材です。ただし、charfloatdoubleなどでは値の意味を考え、単なる昇順で目的を満たすか確認すると考えられます。

基本データ型のソート

基本データ型の配列では、int[]long[]double[]などに対してArrays.sortを使います。文字列配列は参照型ですが、StringComparableを実装しているため自然順序で整列できます。

サンプルコード1:整数のソート

整数配列のソートは、Javaソート方法の最小単位として理解しやすい例です。for文で表示することで、配列が昇順に変わったことを確認しやすくなると言えるでしょう。

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] numbers = {5, 3, 8, 1, 2};
        Arrays.sort(numbers);
        for (int num : numbers) {
            System.out.print(num + " ");
        }
    }
}

結果: 期待される出力は1 2 3 5 8 です。Arrays.sortnumbersを昇順へ並べ替え、拡張for文が順番に出力します。

この例では比較条件を明示していません。intの自然順序が使われるため、ソートアルゴリズムの詳細を知らなくても標準的な昇順を得られます。

サンプルコード2:文字列のソート

文字列のソートでは、String.compareToに基づく辞書順が使われますし、これが一つの目安です。英字の大文字小文字や日本語の並びはロケール要件によって解釈が変わるため、単純な辞書順で足りるか検討します。

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        String[] words = {"Banana", "Apple", "Cherry", "Dragonfruit", "Elderberry"};
        Arrays.sort(words);
        for (String word : words) {
            System.out.print(word + " ");
        }
    }
}

結果: 期待される出力はApple Banana Cherry Dragonfruit Elderberry です。String[]の各要素が自然順序で整列されます。

一方、日本語の五十音順や大文字小文字を無視した順序が必要なら、Collatorや独自のComparatorを検討します。単純なJavaソート例から要件に合わせたソート技法へ進むと、実用的な設計につながりますが、覚えておくと役立つでしょう。

オブジェクトのソート

オブジェクトのソートでは、どのフィールドを基準にするかをコードへ明示します。たとえばPersonnameageがある場合、年齢順と名前順では結果が変わります。その違いを表す仕組みがComparableComparatorです。

Comparableはクラス自身が標準の順序を持つときに使いるのが基本です。Comparatorは外側から比較条件を渡したいときに使うため、画面ごとに並びを変えるJavaプログラミングと相性がよいです。

サンプルコード3:カスタムオブジェクトのソート

クラスに自然順序を持たせる場合、Comparable<Person>を実装します。compareToでは減算ではなくInteger.compareを使うと、極端な値でも比較意図が明確になります。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Person implements Comparable<Person> {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(Person other) {
        return Integer.compare(this.age, other.age);
    }

    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("山田", 25));
        personList.add(new Person("佐藤", 30));
        personList.add(new Person("鈴木", 20));

        Collections.sort(personList);

        for (Person person : personList) {
            System.out.println(person.name + " : " + person.age);
        }
    }
}

結果: 期待される出力は年齢の昇順です。Collections.sortが各PersoncompareToを呼び出し、ageの小さい順に並べます。

鈴木 : 20
山田 : 25
佐藤 : 30

結果: 期待される出力例として、ageが20、25、30の順に並びます。名前は比較に使っていないため、年齢が同じ要素の順序は別の条件で決まりません。

そのため、クラスの標準順序として年齢順を採用してよいかを考える必要があるのが目安です。名前順、ID順、登録日時順など複数の並びがあり得る場合は、Comparatorで外部から条件を渡すほうが柔軟です。

サンプルコード4:Comparatorを使用したソート

Comparatorは、クラス定義を変更せずに比較条件を作れる仕組みです。公式ドキュメントのComparatorでは、比較結果として負数、ゼロ、正数を返す契約が示されています。

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("山田", 25));
        personList.add(new Person("佐藤", 30));
        personList.add(new Person("鈴木", 20));

        Collections.sort(personList, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.name.compareTo(o2.name);
            }
        });

        for (Person person : personList) {
            System.out.println(person.name + " : " + person.age);
        }
    }
}

class Person {
    String name;
    int age;

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

結果: 期待される出力は名前の辞書順です。compare内でname.compareToを使い、Personの並びを名前基準へ切り替えています。

佐藤 : 30
山田 : 25
鈴木 : 20

結果: 期待される出力例では、文字列比較に基づいて名前が並びます。日本語文字列の順序はUnicode上の比較で決まるため、五十音順を保証したい場合は別の比較器を用意するのがポイントです。

これにより、同じPersonでも年齢順と名前順を分けられます。Javaソート例としては、匿名クラスからラムダ式、Comparator.comparingへ発展させると読みやすさが増します。

詳細な対処法

ソート処理では、比較対象にnullが含まれる場合や、互いに比較できない型が混在する場合に例外が起きやすくなるのが一般的です。初心者がつまずきやすいのは、データの中身を確認せずにsortへ渡してしまうケースです。

そのため、Javaソート方法ではAPIの呼び出し前にデータ条件を確認します。NullPointerExceptionClassCastException、比較関数の不整合は、いずれもソート前の設計で減らせます。

ソート時の一般的なエラーとその解決法

一般的に、nullを許可するかどうかは配列やリストの設計段階で決めますし、ここを基本と考えるとよいでしょう。許可するならComparator.nullsFirstComparator.nullsLastを使い、許可しないなら入力時点で除外する方針が明確です。

⚠️ 注意: 比較関数が同じ入力に対して一貫した結果を返さない場合、ソート結果は理解しにくくなります。compare(a, b)compare(b, a)の符号関係を保つことが基本になります。

サンプルコード5:nullポインタ例外の対処

nullを含む文字列配列を自然順序だけで並べると、比較時に例外が起きる場合があるのが現実的です。この例ではnullを末尾に寄せる比較関数を定義します。

import java.util.Arrays;
import java.util.Comparator;

public class Main {
    public static void main(String[] args) {
        String[] strArray = {"apple", null, "banana", "cherry"};

        Arrays.sort(strArray, new Comparator<String>() {
            @Override
            public int compare(String s1, String s2) {
                if (s1 == null && s2 == null) return 0;
                if (s1 == null) return 1;
                if (s2 == null) return -1;
                return s1.compareTo(s2);
            }
        });

        for (String str : strArray) {
            System.out.println(str);
        }
    }
}

結果: 期待される出力はapplebananacherrynullの順です。s1 == nulls2 == nullを先に判定するため、compareTonullへ呼び出しません。

この書き方は比較処理を自力で表しています。実装を短くしたい場合は、Comparator.nullsLast(Comparator.naturalOrder())を使うと同じ意図を読み取りやすくできます。

サンプルコード6:クラスキャスト例外の対処

型が混在する配列をソートする設計は、可能なら避けるほうが保守しやすくなると整理できます。ただし、既存データの整理などでObject[]を扱う場合は、instanceofで型を判定してから比較します。

import java.util.Arrays;
import java.util.Comparator;

public class Main {
    public static void main(String[] args) {
        Object[] objArray = {"apple", 1, "banana", 2};

        Arrays.sort(objArray, new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof String && o2 instanceof String) {
                    return ((String) o1).compareTo((String) o2);
                }
                if (o1 instanceof Integer && o2 instanceof Integer) {
                    return ((Integer) o1).compareTo((Integer) o2);
                }
                return o1.getClass().getName().compareTo(o2.getClass().getName());
            }
        });

        for (Object obj : objArray) {
            System.out.println(obj);
        }
    }
}

結果: 期待される出力は、型名の順序を優先し、同じ型の中では値を比較した並びです。String同士、Integer同士だけをキャストするため、ClassCastExceptionを避けやすくなります。

もっとも、異なる型の値を同じ配列へ入れると、比較規則が複雑になります。プログラミング上はList<String>List<Integer>のように型をそろえる設計が基本になると理解できます。

詳細な注意点

効率的なソートを考えるときは、データ量、比較コスト、メモリ使用量、安定性、スレッド利用の有無を同時に見ます。小さな配列なら読みやすさを優先し、大量データならデータベース側のORDER BYやインデックスも含めて検討します。

Javaの標準APIは多くの場面で十分に実用的です。ただし、比較関数の中で重い計算や外部アクセスを行うと、ソート中に何度も呼ばれて処理が遅くなると覚えるとよいでしょう。比較に使う値は、事前にフィールドへ持たせるか、軽いメソッドで返す形にすると扱いやすくなります。

効率的なソートのための注意点

特に押さえたいのは、データの種類と量に合ったJavaソート方法を選ぶことです。配列ならArrays.sort、リストならList.sort、並列処理が適する大きな配列ならArrays.parallelSortも候補になります。

ただし、並列化は常に速いわけではありません。タスク分割やスレッド管理のコストがあるため、小規模データでは通常のソートのほうが現実的です。初心者ガイドとしては、標準の逐次ソートを理解してから並列版へ進む順序が無理のない学び方になると考えられます。

比較関数では、p1.getAge() - p2.getAge()のような減算よりInteger.compareが読みやすく、オーバーフローも避けやすいです。細かな書き方の差が、長く使うソート技法の品質に影響します。

サンプルコード7:効率的なソートの実装

次の例では、Comparator.comparingIntで年齢順の比較関数を作ります。プリミティブintを扱うため、年齢の比較意図が明確になると言えるでしょう。

import java.util.Arrays;
import java.util.Comparator;

public class EfficientSortExample {
    public static void main(String[] args) {
        Person[] people = {
            new Person("John", 30),
            new Person("Anna", 25),
            new Person("Mike", 35)
        };

        Comparator<Person> ageComparator = Comparator.comparingInt(Person::getAge);
        Arrays.sort(people, ageComparator);

        for (Person person : people) {
            System.out.println(person.getName() + ": " + person.getAge());
        }
    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

結果: 期待される出力は年齢が25、30、35の順です。Comparator.comparingIntgetAgeの戻り値を比較し、Arrays.sortが配列を並べ替えます。

Anna: 25
John: 30
Mike: 35

結果: 期待される出力例では、Person配列が年齢の昇順で表示されます。nameは表示用であり、比較基準には使っていません。

同じ値を持つ要素がある場合の順序も要件になるのが基本です。帳票や画面一覧では、年齢が同じとき名前順にするなど、副条件を用意するとユーザーにとって予測しやすい並びになります。

詳細なカスタマイズ方法

Javaのソートをカスタマイズする中心はComparatorです。comparingcomparingIntreversedthenComparingを組み合わせると、複雑な条件も短く表せます。

その一方で、短い記述に寄せすぎると比較条件が読み取りにくくなる場合があるのが目安です。チームで読むコードでは、ラムダ式、メソッド参照、変数名を使い分け、何を基準にしているかが伝わる形を選びます。

Javaソートのカスタマイズテクニック

カスタマイズでは、昇順と降順、主キーと副キー、nullの位置、ロケールに応じた文字列比較を分けて考えます。これらを混ぜて書くと複雑に見えるため、ひとつずつ比較器として組み立てると読みやすくなるのがポイントです。

サンプルコード8:カスタム比較関数の作成

Comparator.comparingは、オブジェクトから比較キーを取り出すメソッドを受け取ります。年齢で並べるJavaソート例なら、Person::getAgeを渡すだけで意図が伝わります。

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class CustomSortExample {
    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person("山田", 25));
        people.add(new Person("田中", 30));
        people.add(new Person("佐藤", 20));

        people.sort(Comparator.comparing(Person::getAge));
        people.forEach(person -> System.out.println(person.getName() + ": " + person.getAge() + "歳"));
    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

結果: 期待される出力は佐藤: 20歳山田: 25歳田中: 30歳の順です。people.sortがリスト自身を並べ替え、forEachが整列後の要素を表示します。

このソート技法は、getAge以外のメソッドにも応用できます。価格順ならgetPrice、登録日時順ならgetCreatedAtのように、比較キーを取り出すメソッドを統一すると保守しやすくなるのが一般的です。

サンプルコード9:ソートの安定性を保つ方法

安定なソートでは、比較上等しい要素の相対的な順序が保たれます。ただし、複数条件で明確な順序を作りたい場合は、安定性だけに頼らずthenComparingで副条件を明示します。

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class StableSortExample {
    public static void main(String[] args) {
        List<Person> people = new ArrayList<>();
        people.add(new Person("山田", 25));
        people.add(new Person("田中", 25));
        people.add(new Person("佐藤", 20));

        people.sort(Comparator.comparing(Person::getAge).thenComparing(Person::getName));
        people.forEach(person -> System.out.println(person.getName() + ": " + person.getAge() + "歳"));
    }
}

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

結果: 期待される出力は年齢の昇順で、同じ年齢では名前の辞書順です。thenComparingにより、ageが同じ要素の並びがnameで決まります。

ℹ️ 補足: Collections.sortの仕様では、リストのソートは安定であることが示されています。とはいえ、同じキーの表示順に意味がある場合は、副条件をコードへ書くほうが意図を共有しやすくなるのが現実的です。

こうしたカスタマイズは、Javaソート方法を実務へ近づける部分です。初心者ガイドとしては、単一キーの昇順、降順、複数キーの順に練習すると、ソートアルゴリズムの抽象的な説明も理解しやすくなります。

応用例とサンプルコード

応用的なJavaソート例では、複数キーの整列やストリーム処理がよく使われます。データベースから取得した一覧を画面表示用に並べ替える、CSVを読み込んで条件順に出力する、数値リストを加工してから整列するなど、プログラミング課題の形はさまざまです。

この領域では、ソート技法とデータ構造の選択がつながりますし、ここがポイントです。Listの基礎はJava List型完全ガイド、条件分岐を含む日付判定はJavaでうるう年を判定、文字列処理はJavaエスケープ処理、継承設計はJavaのオーバーライド解説も参考になります。

実用的なJavaソートの応用例

実用例で多いのは、主キーと副キーを組み合わせる並びです。社員一覧なら年齢順の中で名前順、商品一覧ならカテゴリ順の中で価格順、ログ一覧なら日付順の中でID順といった形になります。

サンプルコード10:複数のキーでのソート

複数キーの準備として、Employeeクラスを定義すると整理できます。比較に使う値はgetNamegetAgeから取得できるようにします。

public class Employee {
    private String name;
    private int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}

結果: 期待される状態は、Employeeが名前と年齢を持ち、外部からgetterで値を読めることです。このクラスを使って複数キーのソート処理を組み立てます。

そのクラスを使い、年齢を主条件、名前を副条件にしたJavaソート例を作ります。Comparator.comparingIntthenComparingを組み合わせると、匿名クラスより短く読めると理解できます。

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

public class MultiKeySort {
    public static void main(String[] args) {
        List<Employee> employees = new ArrayList<>();
        employees.add(new Employee("Alice", 30));
        employees.add(new Employee("Bob", 30));
        employees.add(new Employee("Charlie", 25));

        employees.sort(
            Comparator.comparingInt(Employee::getAge)
                      .thenComparing(Employee::getName)
        );

        for (Employee employee : employees) {
            System.out.println(employee.getName() + " - " + employee.getAge());
        }
    }
}

結果: 期待される出力はCharlie - 25Alice - 30Bob - 30の順です。年齢が同じAliceBobは、名前の辞書順で並びます。

この書き方は、画面の並び替え条件をコードに落とし込むときに扱いやすい形です。降順にしたい場合は、対象の比較器へreversedを加えます。

サンプルコード11:ストリームを使用したソート

Streamを使うと、データの変換、フィルタ、ソート、集約を流れとして書けると覚えるとよいでしょう。元のリストを変更せず、整列済みの新しいリストを作りたい場合に向いています。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class StreamSortExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(5, 3, 8, 1, 2);

        List<Integer> sortedNumbers = numbers.stream()
                                              .sorted()
                                              .collect(Collectors.toList());

        sortedNumbers.forEach(System.out::println);
    }
}

結果: 期待される出力は12358の順です。streamで要素を流し、sortedで自然順序に整え、collectで新しいListへ集約します。

ただし、Stream.sortedは中間操作であり、collectforEachなどの終端操作が呼ばれるまで処理されません。この性質を理解すると、Javaプログラミングでストリームを使ったソート技法を安全に組み込めます。

まとめ

Javaのソートは、配列ならArrays.sort、リストならCollections.sortList.sortを使うところから始まりますが、これは押さえたい点です。自然順序で足りる場面は短く書けますが、オブジェクトを扱う場面ではComparableComparatorの役割を分けることが大切です。

そのうえで、nullの扱い、型混在の回避、比較関数の一貫性、複数キーの指定を押さえると、Javaソート方法を実用的に使えます。初心者ガイドとして学ぶ段階でも、コードが何を比較しているのかを言葉で説明できるようにすると、ソートアルゴリズムの理解が深まります。

Javaソート例を読み比べると、同じデータでも基準を変えれば結果が変わることが分かりますし、これが一つの目安です。プログラミングでは、この基準を要件として明確にし、Comparator.comparingthenComparingreversedStream.sortedなどを適切に選ぶ流れが実践的です。

関連する学習では、リスト、アノテーション、日付判定、文字列エスケープ、オーバーライドを合わせて理解すると、ソート技法を含むJavaプログラミング全体の見通しがよくなります。標準APIの仕様を確認しながら、小さなJavaソート例を積み重ねることが、安定したコードを書く近道になります。

関連記事

著者: Japanシーモア編集部

Japanシーモアは、Web/IoT/APP/SYS 分野のプログラミング情報を体系的に提供するメディアです。本記事は編集部による執筆とAI支援を組み合わせて制作し、公開前に編集部が校正しています。誤りや改善案がございましたらお問い合わせよりご連絡ください。

※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。