นากกายต้นฉบับกำลังเทกล่องบางใบที่มีเมล็ดและบางใบว่างลงรางสีเขียวเส้นเดียว

Java Optional.stream: แบนค่าที่อาจหายโดยไม่แตก pipeline เป็น if

พี่โชว์Engineering

เมื่อ lookup หลายค่าแล้วแต่ละผลเป็น Optional<T> เรามักเห็น filter(Optional::isPresent) ตามด้วย map(Optional::get) ซึ่งทำงานได้แต่แยกกฎเดียวเป็นสองขั้น Optional.stream คืน stream หนึ่งสมาชิกเมื่อมีค่า และ stream ว่างเมื่อไม่มี จึงต่อกับ flatMap ได้ตรงความหมายครับ

import java.util.List;
import java.util.Map;
import java.util.Optional;

public class Main {
    static List<String> resolve(Map<String, String> users, List<String> ids) {
        return ids.stream()
                .map(id -> Optional.ofNullable(users.get(id)))
                .flatMap(Optional::stream)
                .toList();
    }

    public static void main(String[] args) {
        Map<String, String> users = Map.of("a", "Anan", "c", "Chaba");
        assert resolve(users, List.of("a", "b", "c"))
                .equals(List.of("Anan", "Chaba"));
        assert resolve(users, List.of("missing")).isEmpty();
        System.out.println("Optional.stream tests passed");
    }
}

เทคนิคนี้ดีเมื่อ “ไม่พบ” เป็นผลปกติที่ตัดออกได้ ถ้าทุก ID ต้องมีข้อมูล การแบน Optional จะซ่อนปัญหาและทำให้จำนวนผลไม่ตรง input ควรเปลี่ยนเป็น error ที่ระบุ ID หายหรือ validation ก่อนเริ่ม pipeline อีกอย่าง Optional ไม่ควรใช้แทน collection; ถ้ามีหลายค่าอยู่แล้วคืน Stream<T> หรือ List<T> ให้ตรงชนิด

Recap

  • ใช้ flatMap(Optional::stream) เมื่อค่าที่หายตัดออกได้
  • อย่าซ่อน missing record ที่เป็น invariant violation
  • ใช้ Optional กับศูนย์หรือหนึ่งค่าเท่านั้น
  • ทดสอบลำดับผลและกรณีหายทั้งหมด