ทำไม java.util.ArrayList อนุญาตให้เพิ่ม null?


41

ผมสงสัยว่าทำไมช่วยให้การเพิ่มjava.util.ArrayList nullมีกรณีใดที่ฉันต้องการที่จะเพิ่มnullไปยังArrayList?

ฉันถามคำถามนี้เพราะในโครงการเรามีข้อผิดพลาดที่มีการเพิ่มรหัสบางส่วนnullลงไปArrayListและมันก็ยากที่จะทราบว่าจุดบกพร่องนั้นอยู่ที่ไหน เห็นได้ชัดว่าNullPointerExceptionถูกโยน แต่ไม่จนกว่ารหัสอื่นพยายามเข้าถึงองค์ประกอบ ปัญหาคือวิธีการค้นหารหัสที่เพิ่มnullวัตถุ มันจะง่ายกว่านี้หากArrayListมีข้อยกเว้นในรหัสที่มีการเพิ่มองค์ประกอบ


12
โครงการฝรั่งมีหน้าสวยน่าสนใจในหัวข้อที่ (พวกเขาไม่อนุญาตให้มีnullในส่วนของคอลเลกชันของพวกเขา)
Joachim Sauer

6
ฉันเชื่อว่าคำตอบที่ได้รับที่นี่ครอบคลุมคำถาม บางทีสิ่งหนึ่งที่ควรกล่าวถึงคืออย่าเอาทุกอย่างที่อยู่ใน JDK ออกมาเป็นฮอลลี่และสมบูรณ์แบบแล้วตีหัวของคุณพยายามที่จะเข้าใจว่าทำไมมันถึงสมบูรณ์แบบ บางสิ่งเป็นข้อผิดพลาด (เที่ยงตรง IMHO) ที่ยังคงอยู่เนื่องจากความเข้ากันได้ย้อนหลังและนั่นคือ แม้แต่ผู้สร้าง Java ก็ยอมรับเพียงแค่อ่านหนังสือของ Joshua Bloch เพื่อดูคำวิจารณ์ของเขาเกี่ยวกับ Java API บางตัว คำถามของคุณจะแปรปรวนตามสภาพอากาศไม่มีวิธีที่สง่างามกว่าการจับ NPE ใน Java คำตอบคือไม่ แต่ควรจะมี
Shivan Dragon

2
คุณสามารถให้ข้อมูลเพิ่มเติมว่าทำไมไม่ควรอนุญาตหรือไม่ หากเป็นเพียงเรื่องของรสนิยมก็ควรเลือกข้อ จำกัด ที่น้อยกว่า
Mare Infinitus

คำตอบง่ายๆคือnullวิธีการเริ่มต้นในการแสดงข้อมูลที่ขาดหายไปใน Java ไม่ว่าคุณจะชอบหรือไม่ก็ตาม ในความเป็นจริงผู้คนจำนวนมากไม่ชอบและทำให้มันเป็นอาร์กิวเมนต์สำหรับสิ่งที่ฟังก์ชั่นการเขียนโปรแกรมสไตล์ คำตอบที่ upvoted ที่สุดไม่สมเหตุสมผล / ไม่ได้จับสาระสำคัญของปัญหา
xji

@JIXiang คุณกำลังอธิบายสิ่งที่เกินnullจริง "ไม่มี" เป็นเพียงหนึ่งในหลาย ๆ การตีความที่เป็นnullไปได้ การตีความที่ถูกต้องอื่น ๆ อาจเป็น "ไม่ทราบ" "ไม่เกี่ยวข้อง" หรือ "ไม่เตรียมการ" สิ่งที่nullแสดงถึงขึ้นอยู่กับแอปพลิเคชัน ดังที่ชุมชนไพ ธ อนพูดว่า "เมื่อเผชิญกับความคลุมเครือปฏิเสธการล่อลวงที่จะคาดเดา" ปฏิเสธที่จะถือเป็นโมฆะในภาชนะที่มีความสามารถในการทำเช่นนั้นจะเป็นเพียงแค่ - เดา
riwalk

คำตอบ:


34

การตัดสินใจออกแบบนี้ส่วนใหญ่เกิดจากการตั้งชื่อ

ชื่อArrayListแนะนำให้ผู้อ่านอ่านฟังก์ชั่นที่คล้ายกับอาร์เรย์ - และเป็นเรื่องธรรมดาสำหรับนักออกแบบJava Collections Frameworkที่คาดหวังว่าผู้ใช้ API ส่วนใหญ่จะใช้ฟังก์ชันที่คล้ายกับอาร์เรย์

โดยเฉพาะอย่างยิ่งนี้เกี่ยวข้องกับการรักษาองค์ประกอบโมฆะ ผู้ใช้ API ทราบว่าด้านล่างใช้งานได้:

array[0] = null; // NPE won't happen here

จะค่อนข้างประหลาดใจที่พบว่ารหัสที่คล้ายกันสำหรับ ArrayList จะส่ง NPE หรือไม่:

arrayList.set(0, null); // NPE => WTF?

เหตุผลดังกล่าวข้างต้นจะถูกนำเสนอในจุดเน้นการสอนของ JCFที่แนะนำความคล้ายคลึงกันอย่างใกล้ชิดระหว่าง ArrayList และอาร์เรย์ธรรมดา:

ArrayList ... ให้การเข้าถึงตำแหน่งคงที่และรวดเร็วเพียงแค่ ...

หากคุณต้องการให้การติดตั้งแบบรายการไม่อนุญาตให้มีค่า Null จะเป็นการดีกว่าที่จะเรียกNonNullableArrayListเช่นนั้นเพื่อหลีกเลี่ยงผู้ใช้ API ที่สับสน


ข้อความด้านข้างมีการสนทนาเสริมในความคิดเห็นด้านล่างพร้อมกับการพิจารณาเพิ่มเติมที่สนับสนุนเหตุผลที่วางไว้ที่นี่


12
คำอธิบายนี้ไม่น่าเชื่อการพิจารณาว่าLinkedList ยังสนับสนุนnullรายการรายการ
สตีเฟ่นซี

12
ใช่แล้ว ... แต่คำอธิบายที่เป็นไปได้ง่ายขึ้นและมากขึ้น (IMO) ก็คือการอนุญาตให้nullรายการมีประโยชน์ในหลายกรณี
สตีเฟ่นซี

7
ArrayList ไม่ได้ถูกเรียกเช่นนั้นเพราะมันเลียนแบบอาร์เรย์ มันถูกเรียกเช่นนั้นเพราะมันเป็นรายการที่ใช้เป็นอาร์เรย์ เช่นเดียวกับ TreeMap ไม่ทำงานเหมือนต้นไม้
Florian F

11
คำตอบนี้ IMO เป็นเพียงผิดธรรมดา อนุญาตให้มีค่า Null ได้เนื่องจากใน Java สำหรับดีกว่าหรือแย่กว่านั้น (IMO, แย่กว่า) null จะถูกใช้บ่อยๆเพื่อแทนค่าที่ไม่ได้กำหนดค่าเริ่มต้นหรือขาดหายไป มันได้คะแนนมากที่สุดและเช็ค "ยอมรับ" ได้อย่างไร อย่างจริงจังฉันสูญเสียความเชื่อมั่นใน StackOverflow วันนี้
user949300

8
คำตอบนี้ผิดธรรมดา นี่เป็นเพียงการคาดเดาที่ไม่ได้รับการสนับสนุนเกี่ยวกับโมฆะที่ได้รับอนุญาตในการใช้งานรายการ นี่คือบทสรุปของคอลเลกชัน Java อนุญาต / ไม่อนุญาตให้เป็นโมฆะ; สังเกตว่ามันไม่มีอะไรเกี่ยวข้องกับอาร์เรย์
Andres F.

32

Null อาจเป็นค่าที่ถูกต้องสำหรับองค์ประกอบของรายการ สมมติว่ารายการของคุณมีองค์ประกอบซึ่งแสดงข้อมูลที่เป็นตัวเลือกบางอย่างเกี่ยวกับรายชื่อผู้ใช้และเก็บไว้ในลำดับเดียวกับผู้ใช้ หากมีการเติมข้อมูลเพิ่มเติมรายการของคุณจะมีข้อมูลเพิ่มเติมมิฉะนั้นช่องที่สอดคล้องกับผู้ใช้จะเป็นโมฆะ (ฉันแน่ใจว่ามีตัวอย่างที่ดีกว่า แต่คุณได้รับความคิด)

หากคุณไม่ต้องการอนุญาตให้มีการเพิ่มค่า null คุณสามารถใส่รายการอาร์เรย์ด้วย wrapper ของคุณเองซึ่งจะถูกโยนเมื่อเพิ่มค่า null


2
ดูเหมือนจะเป็นตัวอย่างที่ไม่ดีว่าทำไมการอนุญาตให้มีค่า Null - มีวิธีที่ดีกว่าในการแสดงข้อมูลทางเลือกที่ดีกว่าการใช้ค่า Null ในรายการ
casablanca

@casablanca ใช่ทั้งหมดเห็นด้วยมันไม่ใช่ตัวอย่างที่ดี
Sam Holder

ฉันไม่สามารถหาเหตุผลที่ดีสำหรับ ArrayList ที่มีค่า Null และสิ่งอื่น ๆ ที่น่าประหลาดใจสำหรับผู้พัฒนารายต่อไปที่จะ 'ค้นพบ': /
AndreasScheinert

7
@casablanca ในขณะที่ฉันเห็นด้วยกับคุณว่าควรหลีกเลี่ยง nulls สำหรับการแสดงข้อมูลเพิ่มเติมใน Java สำหรับดีขึ้นหรือแย่ลงนั่นคือ "ดั้งเดิม"
user949300

2
Solid use-case: คุณต้องการส่งผ่านพารามิเตอร์ไปยังฟังก์ชันไดนามิกบางรายการ คุณมีฟังก์ชั่นหลายอย่างแต่ละตัวมีชุดพารามิเตอร์ที่แตกต่างกันดังนั้นคุณต้องมีอาร์เรย์ที่มีขนาดแบบไดนามิกและคุณสามารถส่งผ่านค่า null เป็นอาร์กิวเมนต์ฟังก์ชันที่ถูกต้องได้เสมอ!
Falco

19

ArrayListอนุญาตให้เป็นโมฆะโดยการออกแบบ มันเป็นความตั้งใจ จากjavadoc :

"[ArrayList เป็น] การปรับใช้อาเรย์แบบปรับขนาดได้ของส่วนต่อประสานรายการดำเนินการรายการทางเลือกทั้งหมดและอนุญาตให้องค์ประกอบทั้งหมดรวมถึง null "

คำตอบของ "ทำไม" คือถ้าไม่ใช้ ArrayList จะไม่สามารถใช้งานได้ในกรณีที่จำเป็นต้องใส่nullในรายการ ในทางตรงกันข้ามคุณสามารถป้องกัน ArrayList ที่มีค่า Null โดยการทดสอบค่าก่อนที่จะเพิ่มหรือใช้ wrapper ที่ป้องกันไม่ให้สิ่งนี้เกิดขึ้น

มีกรณีใดบ้างที่ฉันต้องการเพิ่ม null ให้กับ ArrayList?

เห็นได้ชัดว่ากรณีใด ๆ ที่nullมีความหมายที่แตกต่าง ตัวอย่างเช่นมันอาจหมายความว่าค่าที่ตำแหน่งที่กำหนดในรายการไม่ได้เริ่มต้นหรือจัดจำหน่าย

มันจะง่ายขึ้นหาก ArrayList มีข้อยกเว้นในรหัสที่มีการเพิ่มองค์ประกอบ

คุณสามารถนำพฤติกรรมนั้นไปใช้ได้อย่างง่ายดายโดยการสร้างคลาส wrapper อย่างไรก็ตามนี่ไม่ใช่พฤติกรรมที่โปรแกรมเมอร์ / แอพพลิเคชันส่วนใหญ่ต้องการ


8

มีกรณีใดบ้างที่ฉันต้องการเพิ่ม null ให้กับ ArrayList?

แน่นอนว่ามีการจัดสรรล่วงหน้าอย่างไร คุณต้องการArrayListสิ่งที่คุณไม่สามารถสร้างได้เพราะคุณมีข้อมูลไม่เพียงพอ เพียงเพราะคุณไม่สามารถคิดเหตุผลว่าทำไมบางคนอาจต้องการทำบางสิ่งบางอย่างไม่ได้ทำให้มันเป็นความคิดที่ไม่ดี อะไรก็ตาม (ตอนนี้ฉันแน่ใจว่ามีบางคนเข้ามาและบอกว่าคุณควรมีวัตถุว่างที่ทำตามรูปแบบที่พวกเขาอ่านในบล็อกที่คลุมเครือและโปรแกรมเมอร์ควรเขียนโปรแกรมได้โดยไม่ต้องใช้ifคำสั่ง blah blah)

หากพวกคุณมีสัญญาที่ไม่ควรอยู่nullในภาชนะบรรจุมันก็ขึ้นอยู่กับคุณมากที่จะต้องทำให้แน่ใจว่าสัญญานั้นได้รับการสนับสนุน อาจเป็นเพราะคุณได้รับโค้ดสูงสุด 10 บรรทัด Java ทำให้คุณทำสิ่งนี้ได้ง่ายอย่างเหลือเชื่อ JDK ไม่สามารถอ่านใจคุณได้


1
อาร์กิวเมนต์การจัดสรรล่วงหน้าของคุณไม่ถูกต้องเนื่องจากสิ่งนี้ได้สร้างเป็น ArrayList ด้วยensureCapacity(int minCapacity)วิธีการและตัวArrayList(int initialCapacity)สร้างแล้ว
Philipp

7
@Philipp มันจะใส่ค่าอะไรลงในพื้นที่นั้น?
James

ตัวเลือกที่ชัดเจนคือการใส่nullในรายการที่จัดสรรล่วงหน้า (แต่ยังไม่ได้ใช้ ) ของรายการArrayList; แต่เราสามารถปล่อยให้ensureCapacityทำอย่างนั้นและยังไม่อนุญาตให้ทำหน้าที่อื่นเช่นsetทำ เหตุผลที่ให้ที่อื่นดูเหมือนแข็งแกร่ง
David K

@DavidK: มันทำให้ความรู้สึกที่จะบอกว่ามันควรจะเป็นไปได้ที่จะsetรายการไปยังค่าใด ๆ getซึ่งอาจจะส่งกลับโดย แม้ว่าความพยายามปกติของgetรายการที่มีการจัดสรรพื้นที่ แต่ไม่เคยเขียนควรทิ้งข้อยกเว้นแทนที่จะกลับมาnullก็ยังคงมีประโยชน์ที่จะมีคู่ของวิธีการที่จะอนุญาตlist1.setOrEraseIfNull(index, list2.getOrReturnNull(index))แทนที่จะต้องใช้if (list2.valueSet(index)) list1.set(index, list2.get(index)); else list1.unset(index);
supercat

1
@DavidK: ความพยายามที่จะอ่านรายการที่ได้รับการจัดสรร แต่ยังไม่ได้เขียนจะต้องให้ผลเป็นโมฆะหรือมีข้อยกเว้น; มันง่ายกว่าที่จะให้มันคืนค่าว่างเปล่า
supercat

4

นี่ดูเหมือนจะเป็นคำถามเชิงปรัชญามากกว่าหนึ่งเรื่องที่นี่

ArrayList เนื่องจากคลาสยูทิลิตี้ได้รับการออกแบบให้มีประโยชน์ในบริบทที่กว้างของกรณีใช้งานที่เป็นไปได้

ตรงกันข้ามกับการอ้างสิทธิ์ที่ซ่อนอยู่ของคุณที่ควรยอมรับว่าไม่มีค่าเป็นค่าที่ถูกต้อง แต่ก็มีตัวอย่างมากมายที่ค่า Null ถูกกฎหมายอย่างสมบูรณ์

เหตุผลที่สำคัญที่สุดเพียงอย่างเดียวคือสิ่งnullนั้นdo not knowเทียบเท่ากับประเภทการอ้างอิงใด ๆ รวมถึงประเภทของกรอบงาน นี่ก็หมายความว่า null ไม่สามารถแทนที่ในกรณีใด ๆ โดยรุ่นได้อย่างคล่องแคล่วมากขึ้นของnothingมูลค่า

ดังนั้นสมมติว่าคุณเก็บจำนวนเต็ม 1, 3, 7 ใน arraylist ของคุณที่ดัชนีที่สอดคล้องกัน: เนื่องจากการคำนวณบางอย่างคุณต้องการรับองค์ประกอบที่ดัชนี 5 ดังนั้นสิ่งที่อาร์เรย์ของคุณควรกลับคือ: "ไม่มีค่าที่เก็บไว้" ซึ่งอาจทำได้โดยการกลับ null หรือNullObject ในกรณีส่วนใหญ่การคืนค่าบิวด์อินที่สร้างขึ้นจะมีความหมายเพียงพอ หลังจากเรียกใช้เมธอดที่สามารถคืนค่า null และใช้ค่าส่งคืนการตรวจสอบค่าที่ส่งคืนกับค่า null นั้นเป็นเรื่องปกติในรหัสที่ทันสมัย


4

คำสั่ง

File f = null;

ถูกต้องและมีประโยชน์ (ฉันไม่คิดว่าฉันต้องอธิบายสาเหตุ) มันก็มีประโยชน์เช่นกันที่จะมีการรวบรวมไฟล์บางไฟล์อาจเป็นโมฆะ

List<File> files = new ArrayList<File>();
// use my collection of files
// ....
// not using this one anymore:
files.set(3, null);

ประโยชน์ของการเก็บรวบรวมที่อาจมีวัตถุที่เป็นโมฆะรายได้โดยตรงจากประโยชน์ของวัตถุที่อาจเป็นโมฆะ มันง่ายอย่างที่คิด


2

เป็นการง่ายกว่าที่จะยอมรับทุกสิ่งมากกว่าที่จะเข้มงวดและลองเปิดการออกแบบของคุณหลังจากข้อเท็จจริง

ตัวอย่างเช่นจะเกิดอะไรขึ้นถ้า oracle / sun ให้เฉพาะ NonNullableArrayList แต่คุณต้องการเพิ่ม Null ในรายการของคุณ คุณจะทำอย่างไร คุณอาจจะต้องสร้างวัตถุที่แตกต่างอย่างสิ้นเชิงคุณไม่สามารถใช้ขยาย NonNullableArrayList แต่ถ้าคุณมี ArrayList ที่ใช้ทุกอย่างคุณสามารถขยายได้อย่างง่ายดายและแทนที่การเพิ่มที่ไม่ยอมรับค่า Null


2
ไม่เห็นด้วย การอนุญาตให้มากเกินไปนั้นยากที่จะแก้ไขเมื่อความผิดพลาดได้เห็นการใช้อย่างแพร่หลาย หากนักออกแบบภาษาอนุญาตโมฆะในภายหลังโปรแกรมนั้นจะไม่หยุดโปรแกรมที่มีอยู่ แต่สิ่งที่ตรงกันข้ามนั้นไม่เป็นความจริง
Andres F.

2
แต่ฉันเห็นด้วย มันเป็นเรื่องเกี่ยวกับการเพิ่มฟังก์ชั่น คุณสามารถใช้รายการที่ยอมรับค่า null ได้แม้ว่าคุณไม่ต้องการใช้ คุณไม่สามารถใช้รายการที่ปฏิเสธโมฆะหากคุณต้องการโมฆะ
Florian F

-1

มีประโยชน์เต็มที่ของ null?

เป็นอย่างมากดังนั้นเมื่อคุณไปกับรายการของรายการเพื่อจำลองแผ่นชีวิตจริง 2D ที่มีตำแหน่งต่างกัน ครึ่งหนึ่งของตำแหน่งเหล่านั้นอาจว่างเปล่า (โดยการสุ่มพิกัด) ในขณะที่ตำแหน่งที่กรอกข้อมูลไม่ได้แสดงถึงintหรือStringอย่างง่ายแต่แสดงโดยวัตถุที่ซับซ้อน หากคุณต้องการเก็บข้อมูลตำแหน่งไว้คุณต้องเติมจุดว่างด้วย null เพื่อให้list.get (x) .get (y) ของคุณไม่นำไปสู่ความประหลาดใจที่น่ารังเกียจ ในการแก้ไขข้อยกเว้น null คุณสามารถตรวจสอบ null (เป็นที่นิยมมาก) หรือคุณสามารถใช้ตัวเลือก (ซึ่งฉันพบว่ามีประโยชน์ในกรณีนี้) อีกทางเลือกหนึ่งคือการเติมเต็มจุดว่างด้วยวัตถุ "ขยะ" ซึ่งสามารถนำไปสู่ความวุ่นวายทุกชนิด หากการตรวจสอบโมฆะของคุณล้มเหลวหรือถูกลืม Java จะแจ้งให้คุณทราบ ในทางตรงกันข้ามวัตถุตัวยึด "ขยะ" ที่ไม่ได้ตรวจสอบอย่างถูกต้องอาจผ่านการสังเกต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.