Java 逆引き集 | IntSummaryStatistics の活用 — 集計情報取得の便利型

Java Java
スポンサーリンク

IntSummaryStatistics の活用 — 集計情報取得の便利型

IntSummaryStatistics は「int の集計情報」をひとまとめに持つユーティリティです。件数・合計・最小値・最大値・平均を一発で計算・保持でき、Stream と相性抜群。レポートや検証に使うとコードがスッキリします。


しくみと特徴

  • 保持する情報:
    • 件数(count)、合計(sum)、最小値(min)、最大値(max)、平均(average)
  • 取得メソッド:
    • getCount(), getSum(), getMin(), getMax(), getAverage()
  • 利用場面:
    • Stream の summarizingInt と組み合わせる/自前で accept して集計する

基本コード例(すぐ試せる)

Stream で統計を一発取得

import java.util.*;
import java.util.stream.*;

public class IntStatsBasic {
    public static void main(String[] args) {
        List<Integer> nums = List.of(10, 20, 30, 40);

        IntSummaryStatistics stats =
            nums.stream()
                .collect(Collectors.summarizingInt(Integer::intValue));

        System.out.println("count=" + stats.getCount());
        System.out.println("sum=" + stats.getSum());
        System.out.println("min=" + stats.getMin());
        System.out.println("max=" + stats.getMax());
        System.out.println("avg=" + stats.getAverage());
    }
}
Java

自前で累積(accept を使う)

IntSummaryStatistics stats = new IntSummaryStatistics();
for (int n : new int[]{3, 7, 2}) {
    stats.accept(n); // 値を投入
}
System.out.println(stats); // IntSummaryStatistics{count=3, sum=12, min=2, average=4.0, max=7}
Java

例題で理解する

例題1: 学生の点数統計

record Student(String name, int score) {}

List<Student> students = List.of(
    new Student("Tanaka",80),
    new Student("Sato",55),
    new Student("Ito",90)
);

IntSummaryStatistics stats =
    students.stream()
            .collect(Collectors.summarizingInt(Student::score));

System.out.printf("人数=%d 合計=%d 最小=%d 最大=%d 平均=%.1f%n",
    stats.getCount(), stats.getSum(), stats.getMin(), stats.getMax(), stats.getAverage());
Java

例題2: 商品価格の統計レポート文字列

record Product(String name, int price) {}

List<Product> products = List.of(
    new Product("A",100),
    new Product("B",250),
    new Product("C",160)
);

IntSummaryStatistics stats =
    products.stream()
            .collect(Collectors.summarizingInt(Product::price));

String report = String.format(
    "価格統計: 件数=%d, 合計=%d, 最小=%d, 最大=%d, 平均=%.2f",
    stats.getCount(), stats.getSum(), stats.getMin(), stats.getMax(), stats.getAverage());

System.out.println(report);
Java

例題3: ファイルから読み込んだ数値の統計(行ごとに int)

import java.nio.file.*;
import java.io.IOException;

Path path = Paths.get("numbers.txt");
try (var lines = Files.lines(path)) {
    IntSummaryStatistics stats =
        lines.mapToInt(Integer::parseInt)
             .summaryStatistics();

    System.out.println(stats);
}
Java

応用パターン(組み合わせが効く)

  • groupingBy × summarizingInt(カテゴリ別統計)
record Item(String category, int value) {}

List<Item> items = List.of(
    new Item("A", 10),
    new Item("A", 25),
    new Item("B", 5)
);

Map<String, IntSummaryStatistics> byCat =
    items.stream()
         .collect(Collectors.groupingBy(
             Item::category,
             Collectors.summarizingInt(Item::value)
         ));

byCat.forEach((cat, stats) -> System.out.println(cat + " -> " + stats));
Java
  • partitioningBy × summarizingInt(条件で二分統計)
Map<Boolean, IntSummaryStatistics> passStats =
    students.stream()
            .collect(Collectors.partitioningBy(
                s -> s.score >= 60,
                Collectors.summarizingInt(Student::score)
            ));

System.out.println("合格側: " + passStats.get(true));
System.out.println("不合格側: " + passStats.get(false));
Java
  • map 経由で派生値の統計
IntSummaryStatistics lengthStats =
    Stream.of("Java", "Stream", "Stats")
          .mapToInt(String::length)
          .summaryStatistics();
Java

テンプレート集(そのまま使える)

  • 基本統計(int)
IntSummaryStatistics stats =
    stream.collect(Collectors.summarizingInt(x -> 値));
Java
  • プリミティブストリームで統計
IntSummaryStatistics stats =
    IntStream.of(値1, 値2, 値3).summaryStatistics();
Java
  • カテゴリ別の統計
Map<K, IntSummaryStatistics> map =
    stream.collect(Collectors.groupingBy(kFn, Collectors.summarizingInt(vFn)));
Java
  • 条件二分の統計
Map<Boolean, IntSummaryStatistics> map =
    stream.collect(Collectors.partitioningBy(cond, Collectors.summarizingInt(vFn)));
Java
  • 自前投入(外部ループから)
IntSummaryStatistics stats = new IntSummaryStatistics();
list.forEach(n -> stats.accept(n));
Java

落とし穴と回避策

  • 空データ: count=0、sum=0、minは Integer.MAX_VALUE、maxは Integer.MIN_VALUE、average は NaN。出力前に件数チェックや Double.isNaN を使う。
  • オーバーフロー: sum は int。合計が大きくなり得るなら LongSummaryStatistics を検討。
  • 型変換の負荷: Boxed の Integer を扱うより、mapToIntIntStream を使ってオートボクシングを避けると効率的。
  • 並列処理: summaryStatistics()summarizingInt は並列ストリームでも安全に集約される。副作用のある外部更新は避ける。
  • NPE 対策: 元データが null を含むなら事前に filter(Objects::nonNull) を挟む。

まとめ

  • IntSummaryStatistics は「件数・合計・最小・最大・平均」をひとまとめに管理できる便利型。
  • summarizingInt、summaryStatistics と組み合わせるだけで、単純からカテゴリ別・二分統計まで一気に書ける。
  • 空データやオーバーフローに注意しつつ、プリミティブストリームを活用すれば高速・安全なレポートが作れる。

👉 練習課題: 売上レコードから「店舗別の売上統計(件数・合計・最小・最大・平均)」を groupingBy + summarizingInt で作り、平均が NaN の店舗は「データなし」と表示してみてください。

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