1. บทนำ
เมื่อเขียนโปรแกรมด้วย Java, List เป็นโครงสร้างข้อมูลที่ใช้บ่อยและสำคัญที่สุดอย่างหนึ่ง การใช้ List ช่วยให้คุณเก็บหลายรายการในลำดับและทำการดำเนินการต่าง ๆ เช่น การเพิ่ม, การลบ, และการค้นหาองค์ประกอบได้อย่างง่ายดายตามต้องการ
อย่างไรก็ตาม เพื่อใช้ List อย่างมีประสิทธิภาพ การเข้าใจ วิธีการเริ่มต้น (initialization methods) อย่างครบถ้วนเป็นสิ่งจำเป็น การเริ่มต้นที่ไม่ถูกต้องอาจทำให้เกิดข้อผิดพลาดหรือบั๊กที่ไม่คาดคิดและส่งผลอย่างมากต่อความอ่านง่ายและการบำรุงรักษาโค้ด
ในบทความนี้เราจะมุ่งเน้นที่หัวข้อ “การเริ่มต้น Java List” และอธิบายทุกอย่างตั้งแต่วิธีการเริ่มต้นพื้นฐานที่เป็นมิตรกับผู้เริ่มต้นจนถึงเทคนิคเชิงปฏิบัติและข้อผิดพลาดที่พบบ่อย เราจะเปรียบเทียบความแตกต่างระหว่างเวอร์ชันของ Java และแนะนำแนวปฏิบัติที่ดีที่สุดตามสถานการณ์การเขียนโค้ดจริง
ไม่ว่าคุณจะเพิ่งเริ่มเรียน Java หรือใช้ List อย่างสม่ำเสมอแล้ว นี่เป็นโอกาสที่ดีในการทบทวนและจัดระเบียบรูปแบบการเริ่มต้นที่หลากหลาย
ส่วนคำถามที่พบบ่อย (FAQ) จะอยู่ในตอนท้ายเพื่อช่วยแก้ไขข้อสงสัยและปัญหาที่พบบ่อย
2. วิธีการเริ่มต้น List พื้นฐาน
เมื่อเริ่มใช้ List ใน Java ขั้นตอนแรกคือการสร้าง “List ว่าง” หมายถึงการเริ่มต้น List ที่นี่เราจะอธิบายวิธีการเริ่มต้นพื้นฐานโดยใช้การทำงานที่พบมากที่สุดคือ ArrayList
2.1 การสร้าง List ว่างด้วย new ArrayList<>()
วิธีการเริ่มต้นที่ใช้บ่อยที่สุดคือการใช้ new ArrayList<>() ซึ่งเขียนได้ดังนี้
List<String> list = new ArrayList<>();
นี่จะสร้าง List ว่างที่ไม่มีองค์ประกอบใด ๆ
จุดสำคัญ:
Listเป็นอินเทอร์เฟซ ดังนั้นคุณต้องสร้างอ็อบเจกต์จากคลาสที่เป็นคอนกรีตเช่นArrayListหรือLinkedList- โดยทั่วไปแนะนำให้ประกาศตัวแปรเป็นชนิด
Listเพื่อความยืดหยุ่น
2.2 การเริ่มต้นด้วยความจุเริ่มต้นที่กำหนดไว้
หากคุณคาดว่าจะเก็บข้อมูลจำนวนมากหรือทราบจำนวนองค์ประกอบล่วงหน้า การระบุความจุเริ่มต้นจะช่วยเพิ่มประสิทธิภาพ
ตัวอย่าง:
List<Integer> numbers = new ArrayList<>(100);
วิธีนี้จะสำรองพื้นที่สำหรับ 100 องค์ประกอบภายใน ลดค่าใช้จ่ายจากการปรับขนาดใหม่เมื่อเพิ่มรายการและทำให้ประสิทธิภาพดีขึ้น
2.3 การเริ่มต้น LinkedList
คุณสามารถใช้ LinkedList ได้เช่นกัน ขึ้นอยู่กับความต้องการของคุณ การใช้งานค่อนข้างเหมือนกัน:
List<String> linkedList = new LinkedList<>();
LinkedList มีประสิทธิภาพเป็นพิเศษในสถานการณ์ที่มีการเพิ่มหรือเอาออกองค์ประกอบบ่อยครั้ง
Java ทำให้การเริ่มต้น List ว่างเป็นเรื่องง่ายด้วย new ArrayList<>() หรือ new LinkedList<>()
3. การสร้าง List พร้อมค่าตั้งต้น
ในหลายกรณีคุณอาจต้องการสร้าง List ที่มีค่าตั้งต้นอยู่แล้ว ด้านล่างนี้เป็นรูปแบบการเริ่มต้นที่พบบ่อยที่สุดและลักษณะของแต่ละวิธี
3.1 การใช้ Arrays.asList()
หนึ่งในวิธีที่ใช้บ่อยที่สุดใน Java คือ Arrays.asList()
ตัวอย่าง:
List<String> list = Arrays.asList("A", "B", "C");
วิธีนี้จะสร้าง List ที่มีค่าตั้งต้น
หมายเหตุสำคัญ:
- List ที่คืนค่ามีขนาด คงที่ ไม่สามารถเปลี่ยนความยาวได้ การเรียก
add()หรือremove()จะทำให้เกิดUnsupportedOperationException - การแทนที่องค์ประกอบ (ด้วย
set()) สามารถทำได้
3.2 การใช้ List.of() (Java 9+)
ตั้งแต่ Java 9 เป็นต้นไป List.of() ทำให้การสร้าง List ที่ไม่เปลี่ยนแปลง (immutable) เป็นเรื่องง่าย:
List<String> list = List.of("A", "B", "C");
ลักษณะเด่น:
- List ที่ไม่เปลี่ยนแปลงอย่างสมบูรณ์—
add(),set(), และremove()ถูกห้ามใช้ทั้งหมด - อ่านง่ายและเหมาะสำหรับค่าคงที่
3.3 การสร้าง Mutable List จาก Arrays.asList()
หากคุณต้องการ List ที่มีค่าตั้งต้นแต่ยังต้องการแก้ไขต่อไปในภายหลัง วิธีนี้จะเป็นประโยชน์:
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
วิธีนี้จะสร้าง List ที่สามารถแก้ไขได้
add()และremove()ทำงานตามปกติ
3.4 Double‑Brace Initialization
เทคนิคขั้นสูงที่ใช้คลาสนิรนาม:
List<String> list = new ArrayList<>() {{
add("A");
add("B");
add("C");
}};
ลักษณะและคำเตือน:
- สร้างโค้ดที่กระชับแต่แนะนำคลาสนิรนาม ทำให้เกิดภาระเพิ่มเติมและอาจทำให้เกิดการรั่วของหน่วยความจำ
- ใช้เฉพาะสำหรับการสาธิตอย่างรวดเร็วหรือโค้ดทดสอบ; ไม่แนะนำสำหรับการใช้งานจริง
สิ่งนี้แสดงให้เห็นว่า Java มีวิธีต่าง ๆ ในการสร้าง List พร้อมค่าตั้งต้นตามความต้องการของคุณ
5. เกณฑ์การเปรียบเทียบและการเลือก
Java มีวิธีการเริ่มต้น List หลากหลาย และการเลือกที่ดีที่สุดขึ้นอยู่กับ กรณีการใช้งาน ส่วนนี้สรุปแต่ละวิธีและอธิบายว่าเมื่อใดควรเลือกใช้
5.1 รายการที่เปลี่ยนแปลงได้ vs รายการที่ไม่เปลี่ยนแปลงได้
- รายการที่เปลี่ยนแปลงได้
- สามารถเพิ่ม, ลบ หรือแก้ไของค์ประกอบได้
- ตัวอย่าง:
new ArrayList<>(),new ArrayList<>(Arrays.asList(...)) - เหมาะสำหรับการดำเนินการแบบไดนามิกหรือการเพิ่มรายการในลูป
- รายการที่ไม่เปลี่ยนแปลงได้
- ไม่มีการเพิ่ม, ลบ หรือแก้ไข
- ตัวอย่าง:
List.of(...),Collections.singletonList(...),Collections.nCopies(...) - เหมาะสำหรับค่าคงที่หรือการส่งค่าที่ปลอดภัย
5.2 ตารางเปรียบเทียบของวิธีทั่วไป
| Method | Mutability | Java Version | Characteristics / Use Cases |
|---|---|---|---|
new ArrayList<>() | Mutable | All Versions | Empty List; add elements freely |
Arrays.asList(...) | Fixed Size | All Versions | Has initial values but size cannot change |
new ArrayList<>(Arrays.asList(...)) | Mutable | All Versions | Initial values + fully mutable; widely used |
List.of(...) | Immutable | Java 9+ | Clean immutable List; no modifications allowed |
Collections.singletonList(...) | Immutable | All Versions | Immutable List with a single value |
Collections.nCopies(n, obj) | Immutable | All Versions | Initialize with n identical values; useful for testing |
Stream.generate(...).limit(n) | Mutable | Java 8+ | Flexible pattern generation; good for random or sequential data |
5.3 แนะนำรูปแบบการเริ่มต้นตามกรณีการใช้งาน
- เมื่อคุณต้องการ List ว่างเปล่าเท่านั้น
new ArrayList<>()- เมื่อคุณต้องการค่าตั้งต้นและต้องการแก้ไขต่อไป
new ArrayList<>(Arrays.asList(...))- เมื่อใช้เป็นค่าคงที่โดยไม่มีการแก้ไข
List.of(...)(Java 9+)Collections.singletonList(...)- เมื่อคุณต้องการจำนวนค่าที่เหมือนกันคงที่
Collections.nCopies(n, value)- เมื่อค่าต้องถูกสร้างแบบไดนามิก
Stream.generate(...).limit(n).collect(Collectors.toList())

5.4 หมายเหตุสำคัญ
- การพยายามแก้ไข List ที่ไม่เปลี่ยนแปลงหรือขนาดคงที่จะทำให้เกิดข้อยกเว้น
- เลือกวิธีที่เหมาะสมกับความต้องการในการเปลี่ยนแปลงและเวอร์ชันของ Java ของคุณ
การเลือกวิธีการเริ่มต้นที่ถูกต้องช่วยป้องกัน บั๊กที่ไม่คาดคิด และเพิ่มความอ่านง่ายและความปลอดภัย
6. ข้อผิดพลาดทั่วไปและวิธีแก้ไข
ข้อผิดพลาดบางอย่างมักเกิดขึ้นบ่อยเมื่อเริ่มต้นหรือใช้ List ใน Java ต่อไปนี้คือตัวอย่างทั่วไปและวิธีแก้ของพวกมัน
6.1 UnsupportedOperationException
สถานการณ์ทั่วไป:
- เรียก
add()หรือremove()บน List ที่สร้างจากArrays.asList(...) - แก้ไข List ที่สร้างจาก
List.of(...),Collections.singletonList(...)หรือCollections.nCopies(...)
ตัวอย่าง:
List<String> list = Arrays.asList("A", "B", "C");
list.add("D"); // Throws UnsupportedOperationException
สาเหตุ:
- เมธอดเหล่านี้สร้าง List ที่ไม่สามารถเปลี่ยนขนาดได้หรือเป็นแบบไม่เปลี่ยนแปลงเลย
วิธีแก้:
- ห่อด้วย List ที่เปลี่ยนแปลงได้:
new ArrayList<>(Arrays.asList(...))
6.2 NullPointerException
สถานการณ์ทั่วไป:
- เข้าถึง List ที่ไม่เคยถูกกำหนดค่า
ตัวอย่าง:
List<String> list = null;
list.add("A"); // NullPointerException
สาเหตุ:
- เมธอดถูกเรียกบนอ้างอิงที่เป็น
null
วิธีแก้:
- ควรกำหนดค่าให้ก่อนใช้งานเสมอ:
List<String> list = new ArrayList<>();
6.3 ปัญหาเกี่ยวกับประเภท
- การสร้าง List โดยไม่มี generic จะเพิ่มความเสี่ยงของข้อผิดพลาดประเภทใน runtime
ตัวอย่าง:
List list = Arrays.asList("A", "B", "C");
Integer i = (Integer) list.get(0); // ClassCastException
วิธีแก้:
- ควรใช้ generic เสมอเมื่อทำได้
การเข้าใจข้อผิดพลาดทั่วไปเหล่านี้จะช่วยให้คุณ หลีกเลี่ยงปัญหาเมื่อเริ่มต้นหรือใช้ List
7. สรุป
บทความนี้อธิบายวิธีการเริ่มต้น List ต่าง ๆ ใน Java และวิธีเลือกใช้ให้เหมาะสม เราได้ครอบคลุม:
- การสร้าง List ว่างเปล่า ด้วย
new ArrayList<>()และnew LinkedList<>() - List ที่มีค่าตั้งต้น ด้วย
Arrays.asList(),List.of(), และnew ArrayList<>(Arrays.asList(...)) - รูปแบบการเริ่มต้นพิเศษ เช่น
Collections.singletonList(),Collections.nCopies(), และStream.generate() - ความแตกต่างสำคัญระหว่าง List ที่เปลี่ยนแปลงได้และไม่เปลี่ยนแปลงได้
- ข้อผิดพลาดทั่วไปและการจัดการข้อผิดพลาด
แม้ว่าการเริ่มต้น List จะดูง่าย แต่การเข้าใจความแตกต่างเหล่านี้และเลือกวิธีที่เหมาะสมเป็นสิ่งสำคัญสำหรับการเขียนโค้ดที่ปลอดภัยและมีประสิทธิภาพ.
8. คำถามที่พบบ่อย (FAQ)
ถาม 1: ฉันสามารถเพิ่มองค์ประกอบลงใน List ที่สร้างด้วย Arrays.asList() ได้หรือไม่?
A1: ไม่. Arrays.asList() คืนค่า List ที่มีขนาดคงที่. การเรียก add() หรือ remove() จะทำให้เกิด UnsupportedOperationException. ใช้ new ArrayList<>(Arrays.asList(...)) เพื่อสร้าง List ที่สามารถแก้ไขได้.
ถาม 2: ความแตกต่างระหว่าง List.of() กับ Arrays.asList() คืออะไร?
List.of()(Java 9+) → ไม่เปลี่ยนแปลงได้อย่างสมบูรณ์; แม้set()ก็ไม่ได้รับอนุญาต.Arrays.asList()→ มีขนาดคงที่แต่สามารถใช้set()ได้.
ถาม 3: ควรใช้ Double‑Brace Initialization หรือไม่?
A3: ไม่แนะนำเนื่องจากมันสร้างคลาสนิรนามและอาจทำให้เกิดการรั่วของหน่วยความจำ. ควรใช้การกำหนดค่าแบบมาตรฐานแทน.
ถาม 4: การระบุความจุเริ่มต้นมีประโยชน์อย่างไร?
A4: ช่วยลดการปรับขนาดภายในเมื่อเพิ่มหลายองค์ประกอบ, ทำให้ประสิทธิภาพดีขึ้น.
ถาม 5: ควรใช้ generic เสมอเมื่อสร้าง List หรือไม่?
A5: แน่นอน. การใช้ generic ช่วยเพิ่มความปลอดภัยของประเภทและป้องกันข้อผิดพลาดขณะรันไทม์.
ถาม 6: จะเกิดอะไรขึ้นหากใช้ List ที่ยังไม่ได้กำหนดค่า?
A6: การเรียกใช้เมธอดใด ๆ กับมันจะทำให้เกิด NullPointerException. ควรกำหนดค่าให้ก่อนเสมอ.
ถาม 7: มีความแตกต่างของเวอร์ชันในการกำหนดค่า List หรือไม่?
A7: มี. List.of() มีให้ใช้ตั้งแต่ Java 9 ขึ้นไป.

