Java Tips | コレクション:件数カウント

Java Java
スポンサーリンク

件数カウントは「どれくらいあるか」を正確に言葉にする技

業務では「何件あるか?」を数える場面が本当に多いです。
今日の注文件数、エラー件数、未処理タスク件数、特定条件を満たすユーザー数…。

だからこそ、「件数カウント」を毎回 for 文で手書きするのではなく、
“安全で読みやすいカウントユーティリティ”としてパターン化しておくと、
コード全体がかなりスッキリして、バグも入りにくくなります。


一番基本:List の件数を数える

size と stream().count の違いを押さえる

一番シンプルな件数カウントは、List#size() です。

import java.util.List;

public class CountBasic {

    public static void main(String[] args) {
        List<String> names = List.of("山田", "佐藤", "鈴木");

        int count = names.size();

        System.out.println(count); // 3
    }
}
Java

size() は「そのコレクションに何件入っているか」を返します。
これは「全部の件数」が欲しいときの基本形です。

一方、Stream を使うとこう書けます。

long count = names.stream().count();
Java

結果は同じですが、count() は戻り値が long です。
「全部の件数」だけなら size() の方がシンプルですが、
後で条件付きカウントに発展させたいときは stream() ベースで書いておくと自然に拡張できます。


条件付き件数カウント:「◯◯なものだけ何件?」

例:スコアが 80 点以上の件数を数える

業務では「全部の件数」よりも、
「条件を満たすものだけ何件あるか?」の方が圧倒的に多いです。

import java.util.List;

public class CountWithCondition {

    public static void main(String[] args) {
        List<Integer> scores = List.of(70, 85, 90, 60);

        long passedCount = scores.stream()
                                 .filter(score -> score >= 80)
                                 .count();

        System.out.println(passedCount); // 2
    }
}
Java

ここでの重要ポイントは二つです。

一つ目は、filter で「条件を満たすものだけ」に絞り込んでから count() していること。
「条件付き件数カウント」は、基本的に「filter → count」の形になります。

二つ目は、戻り値が long であることです。
件数が int の範囲を超えることはあまりありませんが、
API としては long を返すのが標準になっています。


条件付き件数カウントをユーティリティ化する

「毎回 filter と count を書きたくない」を解消する

同じような条件付きカウントを何度も書くなら、
ユーティリティメソッドにしてしまうとスッキリします。

import java.util.Collection;
import java.util.function.Predicate;

public final class Counts {

    private Counts() {}

    public static <T> long count(
            Collection<T> source,
            Predicate<? super T> condition
    ) {
        if (source == null || source.isEmpty()) {
            return 0L;
        }
        return source.stream()
                     .filter(condition)
                     .count();
    }
}
Java

使い方はこうなります。

import java.util.List;

public class CountUtilSample {

    public static void main(String[] args) {
        List<Integer> scores = List.of(70, 85, 90, 60);

        long passed = Counts.count(scores, s -> s >= 80);
        long failed = Counts.count(scores, s -> s < 80);

        System.out.println(passed); // 2
        System.out.println(failed); // 2
    }
}
Java

ここでの重要ポイントは、
Predicate<? super T> condition が“何を数えたいか”を表している」ことです。

Counts.count(scores, s -> s >= 80) と書けば、
「80 点以上の件数を数えているんだな」と一目で分かります。
条件をラムダで渡せるので、どんな業務ルールにも対応できます。


オブジェクト一覧から「特定条件を満たす件数」を数える

例:ユーザー一覧から「東京都在住ユーザー数」を数える

業務では、オブジェクトの特定のフィールドに基づいて件数を数えることが多いです。

class User {
    private final String name;
    private final String prefecture;
    public User(String name, String prefecture) {
        this.name = name;
        this.prefecture = prefecture;
    }
    public String getName() { return name; }
    public String getPrefecture() { return prefecture; }
}
Java

これを使って、「東京都在住ユーザー数」を数えます。

import java.util.List;

public class UserCountSample {

    public static void main(String[] args) {
        List<User> users = List.of(
                new User("山田", "東京都"),
                new User("佐藤", "大阪府"),
                new User("鈴木", "東京都")
        );

        long tokyoCount =
                Counts.count(users, u -> "東京都".equals(u.getPrefecture()));

        System.out.println(tokyoCount); // 2
    }
}
Java

ここでの重要ポイントは、
「業務ルール(東京都在住)が Predicate としてそのまま書かれている」ことです。

u -> "東京都".equals(u.getPrefecture()) というラムダが、
「都道府県が東京都であるユーザーだけを数える」という仕様を表現しています。
この形に慣れると、「何を数えているのか」がコードからすぐに読み取れるようになります。


グルーピングと組み合わせた「グループごとの件数」

例:都道府県ごとのユーザー数

件数カウントが本領を発揮するのは、「グルーピング」と組み合わせたときです。
例えば、「都道府県ごとのユーザー数」を出したい場合。

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

List<User> users = List.of(
        new User("山田", "東京都"),
        new User("佐藤", "大阪府"),
        new User("鈴木", "東京都")
);

Map<String, Long> countByPref =
        users.stream()
             .collect(Collectors.groupingBy(
                     User::getPrefecture,
                     Collectors.counting()
             ));

System.out.println(countByPref); // {東京都=2, 大阪府=1}
Java

ここでの重要ポイントは、
groupingBy(キー, counting()) という一行が、
“キーごとの件数を数える”という仕様をそのまま表している」ことです。

「Map を用意して、キーがなければ 0 で入れて、1 足して…」という手作業をしなくてよくなり、
読みやすさと安全性が一気に上がります。


null を含むデータの件数カウント

「null も数えるか」「null を除外するか」を決める

現実のデータには null が混ざります。
件数カウントで大事なのは、「null をどう扱うか」を決めることです。

例えば、「null 以外の件数だけ数えたい」なら、こう書けます。

import java.util.Collection;

public final class Counts {

    private Counts() {}

    public static <T> long countNonNull(Collection<T> source) {
        if (source == null || source.isEmpty()) {
            return 0L;
        }
        return source.stream()
                     .filter(v -> v != null)
                     .count();
    }
}
Java

使い方はこうです。

import java.util.List;

public class NonNullCountSample {

    public static void main(String[] args) {
        List<String> names = List.of("山田", null, "佐藤");

        long nonNullCount = Counts.countNonNull(names);

        System.out.println(nonNullCount); // 2
    }
}
Java

ここでの重要ポイントは、
「null の扱いも“件数カウントのルール”の一部」だと意識することです。

「null も 1 件として数えるのか」「null は除外するのか」を、
ユーティリティ側で決めておくと、呼び出し側の迷いがなくなります。


「size でいいところ」と「count を使うべきところ」

ただの件数なのか、条件付きなのか

整理すると、こんな感覚を持てると実務で強いです。

全部の件数が欲しいだけなら、list.size() が一番シンプル。
条件付き件数が欲しいなら、stream().filter(...).count() の形が基本。
何度も出てくる条件付きカウントは、Counts.count(コレクション, 条件) のようなユーティリティにする。
グルーピングと組み合わせると、「◯◯ごとの件数」を一行で書ける。

「これは size でいいのか?」「条件付きか?」と一瞬立ち止まって考える癖がつくと、
件数カウントのコードがかなり整理されていきます。


まとめ:件数カウントユーティリティで身につけてほしい感覚

件数カウントは、
単に「何件あるかを数えるテクニック」ではなく、
「どんな条件で、何を“1件”とみなすかをコードに刻む作業」です。

全部の件数なら size()、条件付きなら filter → count という基本パターンを押さえる。
Counts.count(コレクション, 条件) のようなユーティリティにして、「何を数えているか」をラムダで表現する。
グルーピング+counting() で、「◯◯ごとの件数」を一行で書けるようにする。
null を含む場合は、「null を数えるのか、除外するのか」をユーティリティ側で統一する。

あなたのコードのどこかに、
同じような for 文で if (...) count++ を繰り返している箇所があれば、
それを一度「件数カウントユーティリティ+Stream」に置き換えられないか眺めてみてください。

その小さな整理が、
「“何件あるか”を迷いなく、正確に言葉にできるエンジニア」への、
確かな一歩になります。

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