นากกายต้นฉบับกำลังวางหมุดตามทางทีละจุดจนถึงประตูกั้นบนโต๊ะมิ้นต์

Java Stream.iterate แบบมี hasNext: สร้างลำดับมีขอบเขตโดยไม่พึ่ง limit เดา ๆ

พี่โชว์Engineering

Stream.iterate(seed, next) สร้าง stream ไม่สิ้นสุด จึงมักตามด้วย limit() ที่จำนวนมาจากการคำนวณอีกชุดครับ overload แบบสาม argument รับ hasNext ทำให้เงื่อนไขหยุดอยู่ติดกับการสร้างลำดับและอ่านเหมือน for loop

WHY: ป้ายสุดทางควรอยู่บนถนน ไม่ใช่ในสมุดอีกเล่ม

เมื่อกติกาคือ “เริ่มวันแรก เพิ่มทีละวัน จนก่อนวันสิ้นสุด” predicate บอก boundary ตรง ๆ เหมือนป้ายปิดทางที่เห็นจากเส้นทางนั้น ไม่ต้องเดาว่าต้อง limit กี่ครั้งและเสี่ยง off-by-one เมื่อ step เปลี่ยน

import java.time.LocalDate;
import java.util.List;
import java.util.stream.Stream;

public class Main {
  static List<LocalDate> days(LocalDate start, LocalDate endExclusive) {
    return Stream.iterate(
        start,
        day -> day.isBefore(endExclusive),
        day -> day.plusDays(1)
    ).toList();
  }

  public static void main(String[] args) {
    LocalDate start = LocalDate.of(2026, 10, 6);
    assert days(start, start.plusDays(3)).equals(List.of(
        start,
        start.plusDays(1),
        start.plusDays(2)
    ));
    assert days(start, start).isEmpty();
    assert days(start, start.minusDays(1)).isEmpty();
  }
}

next ต้องพาเข้าใกล้ boundary จริง

API ไม่พิสูจน์ว่า next ทำให้คืบหน้า หากคืนค่าเดิมและ predicate ยัง true stream จะไม่จบ ตรวจ step เป็นศูนย์/ติดลบก่อนสร้างลำดับ และระวัง overflow ของชนิดตัวเลข สำหรับ domain เวลาให้ใช้ type เช่น LocalDate กับ plusDays แทนคำนวณ epoch ด้วยมือ

ผลลัพธ์เป็น ordered sequential stream โดยธรรมชาติของ iterate อย่าเปิด parallel แล้วคาดว่าจะกระจายการสร้างได้ดี เพราะสมาชิกถัดไปพึ่งค่าก่อนหน้า หากแต่ละงานอิสระจริง อาจสร้าง index range แล้ว map แทน

Recap

  • วางเงื่อนไขหยุดใน hasNext เมื่อ boundary เป็นส่วนของลำดับ
  • ตัดสินให้ชัดว่า end เป็น inclusive หรือ exclusive
  • ปฏิเสธ step ที่ไม่คืบหน้าหรือเดินผิดทิศ
  • ใช้ range อิสระเมื่ออยาก parallel จริง