Java summarizingInt: เก็บ count, min, max, sum และ average ใน pass เดียว
การเรียก 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 สำคัญกว่าค่าเฉลี่ย