นากแม่น้ำต้นฉบับกำลังเปิดประตูให้ลูกปัดตัวเลขที่มีค่าไหลเข้าสายพาน และปิดช่องที่ว่าง

Java OptionalInt.stream: ต่อค่าที่อาจไม่มีเข้ากับ IntStream

พี่โชว์Engineering

ฟังก์ชัน parse ที่คืน OptionalInt บอกได้ชัดว่ามีค่าหรือไม่มี โดยไม่ต้องใช้ -1 เป็น sentinel เมื่อต้องต่อหลายผลเข้ากับ pipeline OptionalInt.stream() เปลี่ยนแต่ละผลเป็น IntStream ที่มีศูนย์หรือหนึ่งสมาชิกครับ

import java.util.List;
import java.util.OptionalInt;

public class Main {
  static OptionalInt parsePort(String raw) {
    try {
      int port = Integer.parseInt(raw);
      return port >= 1 && port <= 65535 ? OptionalInt.of(port) : OptionalInt.empty();
    } catch (NumberFormatException ignored) {
      return OptionalInt.empty();
    }
  }

  public static void main(String[] args) {
    int[] ports = List.of("443", "bad", "0", "8080").stream()
        .flatMapToInt(raw -> parsePort(raw).stream())
        .toArray();

    assert java.util.Arrays.equals(ports, new int[] {443, 8080});
  }
}

ภาพเปรียบเทียบคือประตูตรวจตั๋ว: ค่าที่ผ่านเงื่อนไขปล่อยลูกปัดหนึ่งเม็ดเข้าสายพาน ส่วนค่าที่ว่างไม่มีเม็ดออกมาเลย วิธีนี้รักษา primitive stream จึงไม่ต้องเปลี่ยนเป็น Optional<Integer> แล้ว boxing/unboxing ในทางเดินหลัก

แต่การทิ้งค่าที่ parse ไม่ผ่านทำให้เหตุผลหาย ถ้าต้องรายงานว่า input ไหนผิดและเพราะอะไร ให้คืน result type ที่มี error หรือเก็บ validation report แยก ไม่ควรใช้ Optional เป็นถังซ่อน exception

Recap

  • ใช้ OptionalInt.stream สำหรับผลแบบศูนย์หรือหนึ่งค่า
  • รักษา primitive pipeline ด้วย flatMapToInt
  • อย่าใช้ sentinel ที่ชนกับค่าจริงได้
  • ใช้ result/error type เมื่อผู้ใช้ต้องรู้สาเหตุที่ parse ไม่ผ่าน