นากกายต้นฉบับกำลังเทเมล็ดจากตะกร้าเข้าเครื่องชั่งหลายหน้าปัดในรอบเดียว

Java summarizingInt: เก็บ count, min, max, sum และ average ใน pass เดียว

พี่โชว์Engineering

การเรียก stream แยกครั้งเพื่อหา count, min, max และ average ทำให้ต้องเก็บข้อมูลหรือสร้าง stream ใหม่หลายรอบครับ Collectors.summarizingInt สะสมสถิติพื้นฐานใน IntSummaryStatistics ผ่านข้อมูลครั้งเดียว เหมือนเครื่องชั่งที่นับจำนวนและจำค่าต่ำสุด–สูงสุดพร้อมกัน

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

public class Main {
    record Job(String name, int durationMs) {}

    public static void main(String[] args) {
        List<Job> jobs = List.of(
            new Job("index", 80),
            new Job("build", 140),
            new Job("verify", 110)
        );

        IntSummaryStatistics stats = jobs.stream()
            .collect(Collectors.summarizingInt(Job::durationMs));

        assert stats.getCount() == 3L;
        assert stats.getMin() == 80;
        assert stats.getMax() == 140;
        assert stats.getSum() == 330L;
        assert stats.getAverage() == 110.0;
        System.out.println("summarizingInt tests passed");
    }
}

อ่าน empty input ให้ถูก

เมื่อไม่มีสมาชิก count และ sum เป็นศูนย์, average เป็น 0.0, แต่ min/max ใช้ค่าขอบของ int จึงไม่ควรแสดงเป็นสถิติจริงก่อนเช็ก getCount() > 0 ตัว collector รองรับ parallel stream ผ่านการ combine accumulator แต่ไม่ได้ทำให้ mapper ที่มี side effect ปลอดภัย ควรให้ mapper เป็นฟังก์ชันบริสุทธิ์

ผลรวมเก็บเป็น long แต่ mapper คืน int; ถ้าข้อมูลต้นทางเกินช่วง int ให้ใช้ summarizingLong หรือ summarizingDouble ให้ตรงชนิด Average แบบ double อาจมีข้อจำกัดด้านความแม่นยำและสถิติเหล่านี้ไม่ได้ให้ percentile หาก latency tail สำคัญ ต้องเก็บ histogram/quantile แยก ไม่ควรใช้ค่าเฉลี่ยกลบ outlier

Recap

  • ใช้ summarizing collector เมื่ออยากได้สถิติพื้นฐานใน pass เดียว
  • เช็ก count ก่อนอ่าน min/max ของชุดว่าง
  • เลือก int, long หรือ double ให้ตรงช่วงข้อมูล
  • ใช้ histogram เพิ่มเมื่อ percentile สำคัญกว่าค่าเฉลี่ย