Java Collections.disjoint: ตรวจสิทธิ์สองชุดว่าไม่ทับกัน
กฎ “ชุดสิทธิ์ที่ขอกับชุดที่ห้ามต้องไม่มีสมาชิกซ้ำ” มักถูกเขียนเป็น loop แล้วซ่อนเจตนา Collections.disjoint(a, b) ตอบ true เมื่อสอง collection ไม่มี element เท่ากันเลย จึงอ่านเป็นภาษากฎได้ตรงครับ
WHY: เขียนคำถามให้ตรงโดเมน
เหมือนตรวจรายชื่อแขกสองงานว่าไม่มีชื่อซ้ำ คำว่า disjoint แปลว่าไม่ทับกัน ทำให้ reviewer เห็นทันทีว่าเราตรวจ overlap ไม่ใช่นับสมาชิกหรือเทียบทั้งชุด
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;
public class Main {
static Set<String> normalize(Collection<String> values) {
return values.stream()
.map(v -> v.trim().toLowerCase(Locale.ROOT))
.collect(Collectors.toUnmodifiableSet());
}
static boolean policyIsConsistent(Collection<String> allowed, Collection<String> denied) {
return Collections.disjoint(normalize(allowed), normalize(denied));
}
public static void main(String[] args) {
assert policyIsConsistent(Set.of("read"), Set.of("write"));
assert !policyIsConsistent(Set.of(" Admin "), Set.of("admin"));
assert policyIsConsistent(Set.of(), Set.of("delete"));
System.out.println("disjoint policy verified");
}
}
HOW: equality ต้องเป็นกติกาเดียวกัน
ผลลัพธ์พึ่ง equals ของสมาชิก หากชื่อสิทธิ์ไม่สนตัวพิมพ์หรือช่องว่าง ต้อง normalize ก่อนเหมือนตัวอย่าง มิฉะนั้น Admin กับ admin จะถูกมองคนละค่า สำหรับ object โดเมน ให้ equals/hashCode สอดคล้องและไม่เปลี่ยน field ที่ใช้ hash หลังใส่ Set
เอกสารเตือนว่าผลอาจ undefined ถ้าสอง collection ใช้กฎ equality ไม่สอดคล้องกัน เช่น sorted set ที่ comparator ไม่ตรงกับ equals นอกจากนี้อย่าแก้ collection พร้อมกันระหว่างตรวจ ถ้านี่คือ authorization boundary ให้ snapshot immutable ก่อนและ log policy version ที่ตัดสินใจ
Recap
- ใช้
disjointเมื่อต้องถามว่าไม่มีสมาชิกซ้ำหรือไม่ - normalize ตามกฎโดเมนก่อนเปรียบเทียบ
- ใช้ equality semantics เดียวกันทั้งสองฝั่ง
- snapshot policy ก่อน authorization check