Java NavigableMap.subMap: เปิดหน้าต่างช่วงคีย์แบบ live view
ข้อมูลที่เรียงตามคีย์อยู่แล้วไม่จำเป็นต้อง filter ทั้ง map เพื่อหาเฉพาะช่วงครับ NavigableMap.subMap(from, fromInclusive, to, toInclusive) คืน view ของช่วงคีย์ พร้อมบอกชัดว่าขอบซ้ายและขวารวมอยู่หรือไม่
WHY: range semantics ต้องอยู่ใน API
ช่วงเวลา [09:00, 10:00) หมายถึงรวมเก้าโมงแต่ไม่รวมสิบโมง รูปแบบครึ่งเปิดนี้ช่วยต่อช่วงโดยไม่ซ้ำเหตุการณ์ตรงรอยต่อ ถ้าเขียน if เองหลายที่ เครื่องหมาย < กับ <= หลุดได้ง่าย subMap ย้ายกติกาไปไว้กับโครงสร้างที่เรียงคีย์และทดสอบได้
HOW: ใช้ view และเห็นผลที่ map ต้นทาง
import java.util.NavigableMap;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
NavigableMap<Integer, String> timeline = new TreeMap<>();
timeline.put(900, "open");
timeline.put(930, "sync");
timeline.put(1000, "handoff");
timeline.put(1030, "review");
NavigableMap<Integer, String> morning =
timeline.subMap(900, true, 1000, false);
assert morning.size() == 2 : morning;
assert morning.firstKey() == 900;
assert morning.lastKey() == 930;
morning.put(945, "checkpoint");
assert timeline.get(945).equals("checkpoint");
boolean rejected = false;
try {
morning.put(1030, "outside");
} catch (IllegalArgumentException expected) {
rejected = true;
}
assert rejected : "view must reject keys outside its range";
}
}
คำว่า view สำคัญมาก การเพิ่ม ลบ หรือแก้ค่าผ่านช่วงจะเปลี่ยน map ต้นทาง และการแก้ต้นทางก็สะท้อนใน view ถ้าต้องส่ง snapshot ให้โค้ดอื่น ให้ copy เป็น new TreeMap<>(view) หรือ immutable representation แทน
เลือกขอบให้สอดคล้องกับโดเมน
ช่วงเวลาและ pagination มักใช้ขอบขวา exclusive เพื่อไม่ซ้ำรายการ แต่ช่วงคะแนนอาจรวมทั้งสองขอบ เขียนชื่อ helper ให้เห็น semantics เช่น eventsFromInclusiveToExclusive และ test จุดขอบโดยตรง อย่าทดสอบแต่ค่ากลางช่วง
Recap
- ระบุ inclusive/exclusive ทั้งสองขอบ
- จำว่า
subMapเป็น live view ไม่ใช่ copy - copy ก่อนส่งข้าม ownership boundary
- ทดสอบคีย์ตรงขอบและคีย์นอกช่วง