เชี่ยวชาญ Java Collections

นักพัฒนาส่วนใหญ่มักจะเลือกใช้ ArrayList หรือ HashSet เป็นค่าเริ่มต้น ซึ่งเพียงพอสำหรับงานง่ายๆ แต่จะเริ่มมีปัญหาเมื่อคุณต้องการความเร็วหรือการรองรับข้อมูลขนาดใหญ่ (scale)

ครั้งหนึ่งผมเคยสร้างตารางคะแนนเกม (leaderboard) โดยใช้ ArrayList ธรรมดา ผมต้องทำการเรียงลำดับใหม่ทุกครั้งที่มีการเปลี่ยนคะแนน ผลคือ UI ค้างอยู่ตลอดเวลา ผมกำลังต่อสู้กับตัวภาษาแทนที่จะใช้งานมันอย่างถูกวิธี

เลิกใช้เครื่องมือที่ไม่เหมาะสม แล้วหันมาใช้ Collection เฉพาะทาง 3 ชนิดนี้ เพื่อเขียนโค้ดที่เร็วขึ้นและสะอาดขึ้น

  1. EnumSet สำหรับ Enum Constants

หากคุณใช้ HashSet สำหรับ enums คุณจะต้องเสียต้นทุนด้านประสิทธิภาพ (performance tax) เพราะทุกครั้งที่มีการเพิ่มข้อมูล enum จะถูกทำ boxing ให้กลายเป็น object ซึ่งเป็นการเพิ่ม overhead โดยไม่จำเป็น

EnumSet ใช้ bit vector และทำการตรวจสอบโดยใช้คำสั่ง CPU เพียงคำสั่งเดียว

Before: Set<Ability> abilities = new HashSet<>(); abilities.add(Ability.FIRE);

After: EnumSet<Ability> abilities = EnumSet.of(Ability.FIRE);

  1. NavigableSet สำหรับการค้นหาแบบช่วง (Range Queries)

การวนลูปผ่าน list ที่เรียงลำดับแล้วด้วยตัวเองเพื่อหาช่วงข้อมูลนั้นทั้งช้าและเสี่ยงต่อข้อผิดพลาด คุณมักจะเจอบั๊กประเภท off-by-one (การนับตำแหน่งผิดไปหนึ่ง)

NavigableSet จะรักษาข้อมูลของคุณให้เรียงลำดับโดยอัตโนมัติ และให้ประสิทธิภาพการค้นหา subset ในระดับ O(log n)

Before: Collections.sort(scores); List<Integer> topTen = scores.subList(size - 10, size);

After: NavigableSet<Integer> scores = new TreeSet<>(Comparator.reverseOrder()); scores.add(1542); NavigableSet<Integer> topTen = scores.headSet(scores.first(), true).stream().limit(10).collect(Collectors.toCollection(TreeSet::new));

  1. CopyOnWriteArrayList สำหรับ List ที่เน้นการอ่านข้อมูลเป็นหลัก (Read-Heavy Lists)

การใช้ synchronized blocks กับ ArrayList จะทำให้การอ่านข้อมูลทุกครั้งช้าลง และยังอาจทำให้เกิด ConcurrentModificationException หากมี thread หนึ่งกำลังเขียนข้อมูลในขณะที่อีก thread หนึ่งกำลังอ่านอยู่

CopyOnWriteArrayList จะสร้างสำเนาใหม่ของ array ทุกครั้งที่มีการเขียนข้อมูล โดยผู้ที่อ่านข้อมูลจะมองเห็นข้อมูลในรูปแบบ snapshot ของ array นั้น

Before: List<String> log = Collections.synchronizedList(new ArrayList<>()); // Iterating here can crash if a writer joins in.

After: CopyOnWriteArrayList<String> log = new CopyOnWriteArrayList<>(); // Iteration is safe and never crashes.

เลิกใช้คอลเลกชันเดิมๆ เพียงแค่สองอย่างเป็นค่าเริ่มต้นเสียที เลือกเครื่องมือที่เหมาะสมกับรูปแบบข้อมูลของคุณ

ที่มา: https://dev.to/timevolt/the-java-collections-force-mastering-the-hidden-gems-like-a-jedi-4438