Collections API: List, Set, Map, Queue

บทนำ: ทำไมต้องมี Collections?

เมื่อเขียนโปรแกรม เราบ่อยครั้งต้องเก็บข้อมูล หลายตัว แต่ประเภทเดียวกัน เช่น:

  • รายชื่อนักเรียน (หลายๆ คน)
  • ราคาสินค้า (หลายๆ ราคา)
  • ห้องพัก (หลายๆ ห้อง)

Array สามารถทำได้ แต่มีข้อจำกัด – ขนาดต้องกำหนดตั้งแต่แรก และ ถ้าต้อง insert หรือ delete ตรงกลาง ยุ่งยาก

Collections Framework คือ ชุดของ data structures (เหมือน “ตู้เก็บ”) ที่ Java มี built-in ให้ เพื่อเก็บข้อมูลได้ยืดหยุ่นกว่า

Collections Framework ที่สำคัญ:
├─ List → เก็บข้อมูลตามลำดับ (เหมือน queue คิวรอเข้า)
├─ Set → เก็บข้อมูลไม่ซ้ำกัน (เหมือน กลุ่ม ไม่มีสมาชิกซ้ำ)
├─ Map → เก็บคู่ key-value (เหมือนพจนานุกรม)
└─ Queue → ใหม่สำหรับ FIFO/LIFO (ลำดับเข้าก่อนออกก่อน)

1. List: เก็บข้อมูลตามลำดับ

ความเข้าใจพื้นฐาน

List = คอลเล็กชันที่เก็บข้อมูลตามลำดับ (ordered) คุณสามารถ:

  • เพิ่มข้อมูล
  • ลบข้อมูล
  • เข้าถึงข้อมูลด้วย index (ตำแหน่ง)
  • ข้อมูลสามารถซ้ำกันได้

Implementation ของ List

textList (Interface)
├─ ArrayList    ← ใช้งานบ่อยที่สุด (flexible, fast access)
├─ LinkedList   ← ใช้เมื่อต้อง insert/delete บ่อย
└─ Vector       ← เก่า (ไม่ใช้บ่อย)

ตัวอย่างที่ 1: ArrayList ใช้งานพื้นฐาน

javaimport java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        // ==== สร้าง ArrayList ====
        List<String> students = new ArrayList<>();
        
        // ==== เพิ่มข้อมูล (add) ====
        students.add("สมชาย");
        students.add("สมหญิง");
        students.add("สมศรี");
        students.add("สมชาย");  // ซ้ำกันได้
        
        // ==== ขนาด (size) ====
        System.out.println("จำนวนนักเรียน: " + students.size());
        
        // ==== เข้าถึงข้อมูล (get) ====
        System.out.println("นักเรียนคนที่ 1: " + students.get(0));
        System.out.println("นักเรียนคนแรกสุด: " + students.get(students.size() - 1));
        
        // ==== วนลูป ====
        System.out.println("\n=== รายชื่อทั้งหมด ===");
        for (String student : students) {
            System.out.println("- " + student);
        }
        
        // ==== ลบข้อมูล (remove) ====
        students.remove(1);  // ลบตำแหน่งที่ 1 (สมหญิง)
        System.out.println("\nหลังลบแล้ว: " + students);
        
        // ==== แก้ไขข้อมูล (set) ====
        students.set(0, "ชัยวัฒน์");
        System.out.println("หลังแก้ไขแล้ว: " + students);
        
        // ==== ตรวจสอบว่ามี (contains) ====
        System.out.println("มี 'สมศรี' หรือไม่? " + students.contains("สมศรี"));
    }
}

Output:

textจำนวนนักเรียน: 4
นักเรียนคนที่ 1: สมชาย
นักเรียนคนแรกสุด: สมชาย

=== รายชื่อทั้งหมด ===
- สมชาย
- สมหญิง
- สมศรี
- สมชาย

หลังลบแล้ว: [ชัยวัฒน์, สมศรี, สมชาย]
หลังแก้ไขแล้ว: [ชัยวัฒน์, สมศรี, สมชาย]
มี 'สมศรี' หรือไม่? true

คำอธิบาย:

  • ArrayList<String> = List ของ String
  • .add() = เพิ่มข้อมูลท้ายสุด
  • .get(index) = ได้ข้อมูลตำแหน่งที่ index
  • .remove(index) = ลบข้อมูล
  • .set(index, value) = แก้ไขข้อมูล
  • .contains(value) = ตรวจสอบว่ามี

ตัวอย่างที่ 2: List ของ Object

javaimport java.util.ArrayList;
import java.util.List;

// ==== Class ====
public class Product {
    private String name;
    private double price;
    
    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }
    
    @Override
    public String toString() {
        return name + " (" + price + " บาท)";
    }
}

// ==== การใช้งาน ====
public class Main {
    public static void main(String[] args) {
        // สร้าง List ของ Product
        List<Product> products = new ArrayList<>();
        
        // เพิ่มสินค้า
        products.add(new Product("Notebook", 50));
        products.add(new Product("Pen", 10));
        products.add(new Product("Pencil", 5));
        
        // แสดงสินค้า
        System.out.println("=== สินค้าทั้งหมด ===");
        for (Product product : products) {
            System.out.println("- " + product);
        }
        
        // คำนวณ total
        double total = 0;
        for (Product product : products) {
            total += product.price;  // ❌ error: price is private
        }
    }
}

หมายเหตุ: สำหรับ example นี้ คุณต้องทำให้ price เป็น public หรือสร้าง getter


2. Set: เก็บข้อมูลไม่ซ้ำกัน

ความเข้าใจพื้นฐาน

Set = คอลเล็กชันที่ไม่มีข้อมูลซ้ำกัน คุณสามารถ:

  • เพิ่มข้อมูล
  • ลบข้อมูล
  • ตรวจสอบว่ามีข้อมูล
  • ไม่สามารถเข้าถึงด้วย index ได้ (ไม่มี order)

Implementation ของ Set

textSet (Interface)
├─ HashSet         ← ใช้งานบ่อยที่สุด (fast, unordered)
├─ LinkedHashSet   ← เหมือน HashSet แต่ keep insertion order
└─ TreeSet         ← ข้อมูล sorted

ตัวอย่างที่ 3: HashSet ใช้งานพื้นฐาน

javaimport java.util.HashSet;
import java.util.Set;

public class Main {
    public static void main(String[] args) {
        // ==== สร้าง HashSet ====
        Set<String> fruits = new HashSet<>();
        
        // ==== เพิ่มข้อมูล (add) ====
        fruits.add("แอปเปิล");
        fruits.add("กล้วย");
        fruits.add("ส้ม");
        fruits.add("แอปเปิล");  // ลองเพิ่มซ้ำ
        
        // ==== ขนาด ====
        System.out.println("จำนวนผลไม้: " + fruits.size());
        // ❌ จะได้ 3 ไม่ใช่ 4 เพราะ "แอปเปิล" ซ้ำกัน
        
        // ==== วนลูป ====
        System.out.println("\n=== ผลไม้ทั้งหมด ===");
        for (String fruit : fruits) {
            System.out.println("- " + fruit);
        }
        // ⚠️ ลำดับอาจไม่ตามที่เพิ่ม (unordered)
        
        // ==== ตรวจสอบ (contains) ====
        System.out.println("\nมี 'กล้วย' หรือไม่? " + fruits.contains("กล้วย"));
        System.out.println("มี 'องุ่น' หรือไม่? " + fruits.contains("องุ่น"));
        
        // ==== ลบข้อมูล (remove) ====
        fruits.remove("กล้วย");
        System.out.println("\nหลังลบแล้ว: " + fruits);
        
        // ==== ลบทั้งหมด (clear) ====
        // fruits.clear();
        // System.out.println("หลังลบหมด: " + fruits);
    }
}

Output:

textจำนวนผลไม้: 3

=== ผลไม้ทั้งหมด ===
- ส้ม
- แอปเปิล
- กล้วย

มี 'กล้วย' หรือไม่? true
มี 'องุ่น' หรือไม่? false

หลังลบแล้ว: [ส้ม, แอปเปิล]

คำอธิบาย:

  • Set ไม่รับข้อมูลซ้ำ – “แอปเปิล” ที่สองถูก ignore
  • .add() = เพิ่มข้อมูล
  • .contains(value) = ตรวจสอบว่ามี
  • .remove(value) = ลบข้อมูล
  • ไม่มี .get(index) เพราะ Set ไม่มี order

3. Map: เก็บคู่ Key-Value

ความเข้าใจพื้นฐาน

Map = คอลเล็กชันที่เก็บคู่ key-value (เหมือนพจนานุกรม):

  • ค้นหาข้อมูลด้วย key (ไม่ใช่ index)
  • key ต้องไม่ซ้ำกัน (unique)
  • value สามารถซ้ำกันได้

Implementation ของ Map

textMap (Interface)
├─ HashMap         ← ใช้งานบ่อยที่สุด (fast lookup)
├─ LinkedHashMap   ← keep insertion order
└─ TreeMap         ← sorted by key

ตัวอย่างที่ 4: HashMap ใช้งานพื้นฐาน

javaimport java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        // ==== สร้าง HashMap ====
        Map<String, Integer> scores = new HashMap<>();
        
        // ==== เพิ่มข้อมูล (put) ====
        scores.put("สมชาย", 85);
        scores.put("สมหญิง", 90);
        scores.put("สมศรี", 78);
        
        // ==== ค้นหา (get) ====
        System.out.println("คะแนน สมชาย: " + scores.get("สมชาย"));
        System.out.println("คะแนน สมหญิง: " + scores.get("สมหญิง"));
        
        // ==== จำนวน entry ====
        System.out.println("จำนวน: " + scores.size());
        
        // ==== วนลูป แบบ 1: keys ====
        System.out.println("\n=== แบบ 1: วนลูป keys ===");
        for (String key : scores.keySet()) {
            System.out.println(key + " → " + scores.get(key));
        }
        
        // ==== วนลูป แบบ 2: values ====
        System.out.println("\n=== แบบ 2: วนลูป values ===");
        for (Integer value : scores.values()) {
            System.out.println("คะแนน: " + value);
        }
        
        // ==== วนลูป แบบ 3: entry ====
        System.out.println("\n=== แบบ 3: วนลูป entry ====");
        for (Map.Entry<String, Integer> entry : scores.entrySet()) {
            System.out.println(entry.getKey() + " ได้ " + entry.getValue());
        }
        
        // ==== ตรวจสอบ ====
        System.out.println("\nมี 'สมศรี' หรือไม่? " + scores.containsKey("สมศรี"));
        System.out.println("มีคะแนน 90 หรือไม่? " + scores.containsValue(90));
        
        // ==== แก้ไขข้อมูล ====
        scores.put("สมชาย", 95);
        System.out.println("หลังแก้ไข: " + scores);
        
        // ==== ลบข้อมูล ====
        scores.remove("สมศรี");
        System.out.println("หลังลบ: " + scores);
    }
}

Output:

textคะแนน สมชาย: 85
คะแนน สมหญิง: 90
จำนวน: 3

=== แบบ 1: วนลูป keys ===
สมศรี → 78
สมชาย → 85
สมหญิง → 90

=== แบบ 2: วนลูป values ===
คะแนน: 78
คะแนน: 85
คะแนน: 90

=== แบบ 3: วนลูป entry ===
สมศรี ได้ 78
สมชาย ได้ 85
สมหญิง ได้ 90

มี 'สมศรี' หรือไม่? true
มีคะแนน 90 หรือไม่? true
หลังแก้ไข: {สมศรี=78, สมชาย=95, สมหญิง=90}
หลังลบ: {สมชาย=95, สมหญิง=90}

คำอธิบาย:

  • HashMap<String, Integer> = key เป็น String, value เป็น Integer
  • .put(key, value) = เพิ่มคู่ key-value
  • .get(key) = ค้นหา value ด้วย key
  • .keySet() = ได้ทุก keys
  • .values() = ได้ทุก values
  • .entrySet() = ได้ทุก entry (key+value pairs)

4. Queue: FIFO (First In First Out)

ความเข้าใจพื้นฐาน

Queue = คิวของข้อมูล (เหมือนคิวรอเข้า):

  • ข้อมูลที่เพิ่มเข้ามา ก่อนสุด จะ ออกมา ก่อนสุด (FIFO)
  • เหมาะสำหรับ task scheduling, message queue

Implementation ของ Queue

textQueue (Interface)
├─ LinkedList      ← ใช้งานบ่อยที่สุด (implement both Queue + List)
└─ PriorityQueue   ← ข้อมูล sorted by priority

ตัวอย่างที่ 5: Queue ใช้งานพื้นฐาน

javaimport java.util.LinkedList;
import java.util.Queue;

public class Main {
    public static void main(String[] args) {
        // ==== สร้าง Queue ====
        Queue<String> taskQueue = new LinkedList<>();
        
        // ==== เพิ่มข้อมูล (offer / add) ====
        taskQueue.offer("ทำการบ้าน");
        taskQueue.offer("อ่านหนังสือ");
        taskQueue.offer("เล่นเกม");
        taskQueue.offer("นอน");
        
        System.out.println("Queue: " + taskQueue);
        
        // ==== ดู element หน้าสุด (peek) ====
        System.out.println("\nTask หน้าสุด: " + taskQueue.peek());
        System.out.println("Queue ยังคงเหมือนเดิม: " + taskQueue);
        
        // ==== ดึงข้อมูลออก (poll) ====
        System.out.println("\n=== ดำเนินการ task ===");
        while (!taskQueue.isEmpty()) {
            String task = taskQueue.poll();
            System.out.println("✓ " + task);
        }
        
        System.out.println("\nQueue หลังจบ: " + taskQueue);
    }
}

Output:

textQueue: [ทำการบ้าน, อ่านหนังสือ, เล่นเกม, นอน]

Task หน้าสุด: ทำการบ้าน
Queue ยังคงเหมือนเดิม: [ทำการบ้าน, อ่านหนังสือ, เล่นเกม, นอน]

=== ดำเนินการ task ===
✓ ทำการบ้าน
✓ อ่านหนังสือ
✓ เล่นเกม
✓ นอน

Queue หลังจบ: []

คำอธิบาย:

  • .offer(value) = เพิ่มข้อมูลท้ายสุด
  • .poll() = ดึงข้อมูลหน้าสุดออก (FIFO)
  • .peek() = ดู element หน้าสุดโดยไม่ดึงออก
  • .isEmpty() = ตรวจสอบว่าว่าง

ตัวอย่างรวม: ร้านค้า

javaimport java.util.*;

// ==== Product class ====
public class Product {
    private String id;
    private String name;
    private double price;
    
    public Product(String id, String name, double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }
    
    public String getId() { return id; }
    public String getName() { return name; }
    public double getPrice() { return price; }
    
    @Override
    public String toString() {
        return name + " (" + price + " บาท)";
    }
}

// ==== การใช้ Collections ====
public class Store {
    private List<Product> inventory;           // List: สินค้าทั้งหมด
    private Set<String> soldCategories;        // Set: หมวดหมู่ที่ขายแล้ว
    private Map<String, Integer> stock;        // Map: ราคา key = ID, value = จำนวน
    private Queue<String> orders;              // Queue: คิวคำสั่งซื้อ
    
    public Store() {
        this.inventory = new ArrayList<>();
        this.soldCategories = new HashSet<>();
        this.stock = new HashMap<>();
        this.orders = new LinkedList<>();
    }
    
    public void addProduct(Product product, int quantity) {
        inventory.add(product);
        stock.put(product.getId(), quantity);
    }
    
    public void sell(String productID) {
        if (stock.containsKey(productID)) {
            int qty = stock.get(productID);
            if (qty > 0) {
                stock.put(productID, qty - 1);
                soldCategories.add(productID);
                orders.offer(productID);
                System.out.println("✓ ขายสินค้า ID: " + productID);
            }
        }
    }
    
    public void processOrders() {
        System.out.println("\n=== ประมวลผลคำสั่งซื้อ ===");
        while (!orders.isEmpty()) {
            String orderedID = orders.poll();
            System.out.println("- ส่งสินค้า ID: " + orderedID);
        }
    }
    
    public void showStatus() {
        System.out.println("\n=== สถานะร้านค้า ===");
        System.out.println("สินค้าทั้งหมด: " + inventory.size());
        System.out.println("หมวดหมู่ที่ขายแล้ว: " + soldCategories);
        System.out.println("จำนวนคงคลัง: " + stock);
    }
}

// ==== Main ====
public class Main {
    public static void main(String[] args) {
        Store store = new Store();
        
        // เพิ่มสินค้า
        store.addProduct(new Product("P001", "Notebook", 50), 10);
        store.addProduct(new Product("P002", "Pen", 10), 20);
        store.addProduct(new Product("P003", "Pencil", 5), 15);
        
        store.showStatus();
        
        // ขายสินค้า
        store.sell("P001");
        store.sell("P002");
        store.sell("P001");
        store.sell("P003");
        
        store.processOrders();
        store.showStatus();
    }
}

Output:

text=== สถานะร้านค้า ===
สินค้าทั้งหมด: 3
หมวดหมู่ที่ขายแล้ว: []
จำนวนคงคลัง: {P001=10, P002=20, P003=15}
✓ ขายสินค้า ID: P001
✓ ขายสินค้า ID: P002
✓ ขายสินค้า ID: P001
✓ ขายสินค้า ID: P003

=== ประมวลผลคำสั่งซื้อ ===
- ส่งสินค้า ID: P001
- ส่งสินค้า ID: P002
- ส่งสินค้า ID: P001
- ส่งสินค้า ID: P003

=== สถานะร้านค้า ===
สินค้าทั้งหมด: 3
หมวดหมู่ที่ขายแล้ว: [P001, P002, P003]
จำนวนคงคลัง: {P001=8, P002=19, P003=14}

ตารางเปรียบเทียบ Collections

Collectionลักษณะใช้เมื่อไรตัวอย่าง
ListOrdered, ซ้ำได้ต้อง access ตามลำดับ, ต้อง indexรายชื่อนักเรียน
Setไม่ซ้ำ, unorderedต้องไม่ซ้ำ, ไม่สนใจลำดับหมวดหมู่, category
MapKey-value pairsต้องค้นหาด้วย keyราคาสินค้า, พจนานุกรม
QueueFIFOต้องลำดับเข้าก่อนออกก่อนtask scheduler

สรุป

Collections Framework คือชุดของ data structures ที่ Java มีให้ใช้สำหรับเก็บข้อมูลหลายตัวอย่างยืดหยุ่น:

  • List – ใช้เมื่อต้อง เก็บข้อมูลตามลำดับ และ เข้าถึงด้วย index
  • Set – ใช้เมื่อต้อง ไม่ให้ข้อมูลซ้ำ และ ไม่สนใจลำดับ
  • Map – ใช้เมื่อต้อง ค้นหาข้อมูลด้วย key (เหมือนพจนานุกรม)
  • Queue – ใช้เมื่อต้อง ลำดับ FIFO (ทำให้เข้ามาก่อนออกมาก่อน)

การเลือกใช้ collection ที่เหมาะสม จะทำให้ code มีประสิทธิภาพ อ่านเข้าใจง่าย และดูแลรักษาได้ดี