IllegalArgumentException หรือ NullPointerException สำหรับพารามิเตอร์ null? [ปิด]


547

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

คำตอบ:


299

ดูเหมือนว่าIllegalArgumentExceptionจะเรียกว่าถ้าคุณไม่ต้องการnullที่จะเป็นค่าที่ได้รับอนุญาตและNullPointerExceptionจะถูกโยนถ้าคุณกำลังพยายามที่จะใช้nullตัวแปรที่จะออกมาเป็น


33
คำตอบสำหรับคำถามนี้ต่อไปนี้สร้างข้อโต้แย้งที่โน้มน้าวใจว่า NullPointerException เป็นข้อยกเว้นที่ถูกต้อง: stackoverflow.com/a/8160/372926 ; stackoverflow.com/a/8196334/372926 ; และstackoverflow.com/a/6358/372926
SamStephens

2
IllegalArgumentExceptionอยู่ในความขัดแย้งกับ Java ของObjects.requireNonNull (T)และฝรั่งของPreconditions.checkNotNull (T)NullPointerExceptionซึ่งพ่น แต่คำตอบที่เหมาะสมจะ definitelly IllegalArgumentExceptionที่อธิบายไว้ในคำตอบที่ดีเยี่ยมเจสันโคเฮนและมันส่วนความคิดเห็น
matoni

417

คุณควรใช้IllegalArgumentException(IAE) ไม่ใช่NullPointerException(NPE) ด้วยเหตุผลดังต่อไปนี้:

อันดับแรกNPE JavaDocแสดงรายการเคสที่เหมาะสมกับNPEอย่างชัดเจน ขอให้สังเกตว่าพวกเขาทั้งหมดจะถูกโยนโดยรันไทม์เมื่อnullมีการใช้อย่างไม่เหมาะสม ในทางตรงกันข้ามIAE JavaDocไม่ชัดเจนมากขึ้น: "โยนเพื่อระบุว่าวิธีการได้ผ่านการโต้แย้งที่ผิดกฎหมายหรือไม่เหมาะสม" ใช่นั่นคือคุณ!

ประการที่สองเมื่อคุณเห็น NPE ในการติดตามสแต็กคุณคิดอย่างไร น่าจะเป็นว่าคนที่ dereferenced nullเมื่อคุณเห็น IAE คุณถือว่าผู้เรียกใช้ของวิธีการที่ด้านบนของสแต็คที่ส่งผ่านในค่าที่ผิดกฎหมาย อีกครั้งสมมติฐานหลังเป็นจริงอดีตคือทำให้เข้าใจผิด

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

ประการที่สี่ข้อมูลพารามิเตอร์ที่ไม่ถูกต้องอื่น ๆ ทั้งหมดจะเป็น IAE ดังนั้นทำไมไม่สอดคล้องกัน ทำไมมันถึงเป็นเรื่องผิดกฎหมายnullจึงพิเศษเป็นพิเศษที่สมควรได้รับข้อยกเว้นแยกต่างหากจากการโต้แย้งที่ผิดกฎหมายประเภทอื่นทั้งหมด?

ในที่สุดฉันยอมรับข้อโต้แย้งที่ได้รับจากคำตอบอื่น ๆ ที่บางส่วนของ Java API ใช้ NPE ในลักษณะนี้ อย่างไรก็ตาม Java API นั้นไม่สอดคล้องกับทุกอย่างตั้งแต่ประเภทยกเว้นไปจนถึงการตั้งชื่ออนุสัญญาดังนั้นฉันคิดว่าเพียงแค่คัดลอก (ส่วนที่คุณโปรดปราน) Java API นั้นไม่ใช่ข้อโต้แย้งที่ดีพอที่จะพิจารณาสิ่งอื่น ๆ เหล่านี้


119
Java 2nd Edition ที่มีประสิทธิภาพ, Item 60: "Arguably, การเรียกใช้เมธอดที่ผิดพลาดทั้งหมดต้มลงไปในการโต้แย้งที่ผิดกฎหมายหรือสถานะที่ผิดกฎหมาย แต่ข้อยกเว้นอื่น ๆ จะถูกใช้อย่างเป็นมาตรฐานสำหรับการโต้แย้งและรัฐที่ผิดกฎหมายบางประเภท ไม่อนุญาตให้มีค่าว่างข้อตกลงกำหนดว่า NullPointerException จะถูกโยนมากกว่า IllegalArgumentException ในทำนองเดียวกันหากผู้เรียกส่งค่าช่วงนอกขอบเขตในพารามิเตอร์ที่แสดงดัชนีเป็นลำดับดัชนี IndexOutOfBoundsException
Gili

33
JavaDoc สำหรับ NPE ยังระบุสิ่งต่อไปนี้: "แอปพลิเคชันควรโยนอินสแตนซ์ของคลาสนี้เพื่อระบุการใช้วัตถุ null ที่ผิดกฎหมายอื่น ๆ " อันนี้น่าจะชัดเจนกว่า :(
R. Martinho Fernandes

12
น่าเสียดายที่วิธีการตรวจสอบValidate.notNull(คอมมอนส์ lang) และPreconditions.checkNotNull(ฝรั่ง) ทั้งคู่โยน NPE :-(
Aaron Digulla

2
แม้ว่า Guava ยังมี Preconditions.checkArgument () พ่น IllegalArgumentException ...
michaelok

16
@AaronDigulla จาก Guava docs: "เรารู้ว่ามีการโต้เถียงที่ถูกต้องหลายอย่างเพื่อสนับสนุนการขว้างปา IAE ให้เป็นโมฆะจริง ๆ แล้วถ้าเรามีเครื่องย้อนเวลากลับไป> 15 ปีเราอาจลองผลักสิ่งต่าง ๆ เข้าไป ทิศทางนั้นอย่างไรก็ตามเราได้ตัดสินใจที่จะใช้ JDK และการตั้งค่า Java ที่มีประสิทธิภาพของ NullPointerException หากคุณเชื่อมั่นว่า IAE นั้นถูกต้องคุณยังคงมีcheckArgument(arg != null)อยู่โดยไม่มีความสะดวกในการคืนค่า ARG หรือคุณสามารถสร้าง ยูทิลิตี้ท้องถิ่นสำหรับโครงการของคุณ " code.google.com/p/guava-l
ไลบรารี/wiki/IdeaGraveyard

162

NullPointerExceptionมาตรฐานคือการโยน "Java ที่มีประสิทธิภาพ" โดยผิดพลาดกล่าวถึงเรื่องนี้สั้น ๆ ในรายการ 42 (ฉบับพิมพ์ครั้งแรก), รายการ 60 (ฉบับที่สอง) หรือรายการ 72 (ฉบับที่สาม) "โปรดปรานการใช้ข้อยกเว้นมาตรฐาน":

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


95
ฉันไม่เห็นด้วยอย่างยิ่ง ควรโยน NullPointerExceptions เฉพาะถ้า JVM บังเอิญตามการอ้างอิงแบบ null นั่นคือความแตกต่างที่ช่วยให้คุณเมื่อโทรเข้าไปดูรหัสที่ 3 ในตอนเช้า
Thorbjørn Ravn Andersen

26
ฉันไม่จำเป็นต้องเห็นด้วยกับมาตรฐาน (จริง ๆ แล้วฉันสามารถไปทางใดทางหนึ่งในประเด็น) แต่นั่นคือสิ่งที่การใช้งานมาตรฐานทั่วทั้ง JDK เป็นดังนั้น Java ที่มีประสิทธิภาพทำให้เป็นกรณีสำหรับมัน ฉันคิดว่านี่เป็นกรณีของการเลือกว่าจะทำตามมาตรฐานหรือทำในสิ่งที่คุณรู้สึกว่าถูกต้อง ถ้าคุณไม่มีเหตุผลที่ดีมาก (และนี่อาจมีคุณสมบัติเหมาะสม) คุณควรปฏิบัติตามมาตรฐาน
GaryF

21
การติดตามข้อยกเว้นแสดงจุดของข้อยกเว้นดังนั้นหากความแตกต่างในประเภทของข้อยกเว้นทำให้เกิดนรกสำหรับคุณหรือเป็น "ความแตกต่างที่ช่วยให้คุณ" คุณกำลังทำสิ่งผิดปกติมาก
Jim Balter

8
จินตนาการและความซับซ้อน ด้านล่าง MB เขียนว่า "โปรดสังเกตว่าข้อโต้แย้งเกี่ยวกับการดีบักแบบยากนั้นเป็นของปลอมเพราะแน่นอนว่าคุณสามารถส่งข้อความถึง NullPointerException เพื่อบอกว่าอะไรที่เป็นโมฆะและทำไมมันไม่ควรจะว่างเปล่าเหมือนกับ IllegalArgumentException"
Jim Balter

10
ในฐานะผู้ตอบแบบดั้งเดิมที่นี่ให้ฉันบอกว่ามันไม่สำคัญเท่าไหร่ แน่นอนไม่รับประกัน 6 ปีของการสนทนา เลือกอย่างใดอย่างหนึ่งที่คุณชอบและมีความสอดคล้อง มาตรฐานตามที่ฉันชี้ให้เห็นคือ NPE ถ้าคุณชอบ IAE ไม่ว่าด้วยเหตุผลใดก็ตาม เพียงแค่ให้สอดคล้อง
GaryF

138

ฉันชอบโยนIllegalArgumentExceptionพารามิเตอร์ว่างจนถึงทุกวันนี้เมื่อฉันสังเกตเห็นjava.util.Objects.requireNonNullวิธีใน Java 7 ด้วยวิธีนั้นแทนที่จะทำ:

if (param == null) {
    throw new IllegalArgumentException("param cannot be null.");
}

คุณทำได้:

Objects.requireNonNull(param);

และมันจะโยนถ้าพารามิเตอร์คุณผ่านมันเป็นNullPointerExceptionnull

เนื่องจากวิธีการดังกล่าวถูกต้องในช่วงกลางของjava.utilฉันฉันใช้เวลาที่จะเป็นตัวบ่งชี้ที่แข็งแกร่งว่าการขว้างปาNullPointerExceptionเป็น "วิธีการทำสิ่ง Java"

ฉันคิดว่าฉันตัดสินใจในอัตราใด

โปรดทราบว่าข้อโต้แย้งเกี่ยวกับการดีบักแบบยากนั้นเป็นของปลอมเพราะแน่นอนว่าคุณสามารถให้ข้อความเพื่อNullPointerExceptionบอกว่าอะไรที่เป็นโมฆะและทำไมมันไม่ควรเป็นโมฆะ IllegalArgumentExceptionเช่นเดียวกับ

ข้อดีอย่างหนึ่งที่เพิ่มขึ้นของNullPointerExceptionคือในโค้ดที่มีประสิทธิภาพสูงคุณสามารถแจกจ่ายด้วยการตรวจสอบที่ชัดเจนสำหรับ null (และ a NullPointerExceptionพร้อมกับข้อความแสดงข้อผิดพลาดที่เป็นมิตร) และเพียงพึ่งพาที่NullPointerExceptionคุณจะได้รับโดยอัตโนมัติเมื่อคุณเรียกใช้เมธอด null พารามิเตอร์. ให้คุณเรียกใช้วิธีการได้อย่างรวดเร็ว (เช่นล้มเหลวอย่างรวดเร็ว) จากนั้นคุณมีเอฟเฟกต์เดียวกันโดยที่ไม่ได้เป็นมิตรกับผู้ใช้สำหรับนักพัฒนา เวลาส่วนใหญ่น่าจะดีกว่าที่จะตรวจสอบอย่างชัดเจนและส่งข้อความที่มีประโยชน์เพื่อระบุว่าพารามิเตอร์ใดเป็นโมฆะ แต่ก็ดีที่มีตัวเลือกในการเปลี่ยนว่าถ้าประสิทธิภาพกำหนดโดยไม่ทำลายสัญญาที่เผยแพร่ของเมธอด / ตัวสร้าง


14
ฝรั่งPreconditions.checkNotNull(arg)ยังโยน NPE
assylias

14
นี่ไม่ได้เป็นการเพิ่มน้ำหนักให้กับ NullPointerException มากนักเนื่องจากมีค่า NULL ที่ผิดกฎหมาย ทั้ง JDK requireNonNull () และ Guava checkNotNull () สามารถเรียกได้ทุกที่ในรหัสด้วยวัตถุใด ๆ คุณสามารถเรียกพวกมันได้ในวง requireNotNull () และ checkNotNull () อาจไม่สามารถสันนิษฐานได้ว่าจะเรียกใช้ด้วยอาร์กิวเมนต์เมธอดและโยน IllegalArgumentException โปรดทราบว่า Guava ยังมี Preconditions.checkArgument () ซึ่งจะขว้าง IllegalArgumentException
Bogdan Calmac

2
จุดยุติธรรมโดย Bogdan แม้ว่าฉันจะสงสัยว่าการใช้งานทั่วไป (และโดยทั่วไป) การใช้ requireNonNull สำหรับการตรวจสอบการโต้แย้ง หากคุณต้องการตรวจสอบว่ามีบางอย่างที่ไม่เป็นโมฆะฉันคิดว่าการยืนยันจะเป็นวิธีปกติ
MB

15
ผมคิดว่า JavaDoc ของ Object.requireNonNull () เพิ่มน้ำหนักให้กับอาร์กิวเมนต์: "วิธีการนี้ถูกออกแบบมาสำหรับการทำการตรวจสอบพารามิเตอร์ในวิธีการและการก่อสร้าง"
ริชาร์ด Zschech

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

70

ฉันมักจะติดตามการออกแบบห้องสมุด JDK โดยเฉพาะอย่างยิ่ง Collections and Concurrency (Joshua Bloch, Doug Lea พวกนั้นรู้วิธีออกแบบ API ที่เป็นของแข็ง) อย่างไรก็ตาม APIs จำนวนมากใน JDK NullPointerExceptionโปรแข็งขันพ่น

ตัวอย่างเช่น Javadoc สำหรับMap.containsKeyสถานะ:

@throws NullPointerException ถ้าคีย์นั้นเป็นโมฆะและแผนที่นี้ไม่อนุญาตให้ใช้คีย์ null (เป็นทางเลือก)

สามารถใช้งาน NPE ของคุณได้อย่างสมบูรณ์ การประชุมคือการรวมชื่อพารามิเตอร์ซึ่งเป็นโมฆะในข้อความของข้อยกเว้น

รูปแบบไป:

public void someMethod(Object mustNotBeNull) {  
    if (mustNotBeNull == null) {  
        throw new NullPointerException("mustNotBeNull must not be null");  
    }  
}

สิ่งที่คุณทำไม่อนุญาตให้มีค่าที่ไม่ดีในการตั้งค่าและโยนข้อยกเว้นในภายหลังเมื่อรหัสอื่นพยายามใช้มัน นั่นทำให้การดีบักฝันร้าย คุณควรปฏิบัติตามหลักการ "ล้มเหลวอย่างรวดเร็ว"


3
อาหารสำหรับความคิด: บางทีเหตุผลที่ NullPointerException ไม่ได้ขยาย IllegalArgumentException คืออดีตอาจเกิดขึ้นได้ในกรณีที่ไม่เกี่ยวข้องกับวิธีการโต้แย้ง
Gili

2
@Gili: ปัญหานี้อาจเกิดขึ้นตั้งแต่แรกเพราะ Java ไม่รองรับการสืบทอดหลายแบบ หาก Java รองรับ MI คุณจะสามารถโยนข้อยกเว้นที่สืบทอดมาจาก IllegalArgumentException และ NullPointerException
โกหก Ryan

7
ข้อความไม่จำเป็นต้องรวมอาร์กิวเมนต์เนื่องจากมันจะเป็นโมฆะเสมอโดยให้: "null ต้องไม่เป็นโมฆะ" ซึ่งไม่มีประโยชน์มาก :-) มิฉะนั้นฉันเห็นด้วยคุณสามารถสร้าง "รวย" NPE ด้วยข้อความที่มีความหมาย
PhiLho

5
ฉันต้องยอมรับ - ทำตาม API มาตรฐานเมื่อมีข้อสงสัย ไม่ใช่ทุกสิ่งทุกอย่างใน API นั้นเป็นสิ่งที่ดีที่สุดสำหรับคุณ แต่ก็ยังคงรักษาไว้และซ้ำซ้อนโดยนักพัฒนาหลายร้อยคนและใช้งานโดยโปรแกรมเมอร์หลายล้านคน ตอนนี้ใน Java 7 เรามีอีกตัวอย่างหนึ่งของ NPE ที่ใช้ในวิธีนี้ Objects.requireNonNull (T obj) วิธีการ - ระบุไว้อย่างชัดเจนสำหรับการตรวจสอบว่าการอ้างอิงวัตถุที่ไม่เป็นโมฆะระบุไว้อย่างชัดเจนสำหรับการตรวจสอบความถูกต้องพารามิเตอร์ในวิธีการ / ก่อสร้างและระบุอย่างชัดเจนที่จะโยน NPE หากวัตถุเป็นโมฆะ สิ้นสุด
flamming_python

44

โหวตให้อาร์กิวเมนต์ของ Jason Cohen เพราะได้รับการนำเสนออย่างดี ขอผมแยกชิ้นทีละขั้นตอน ;-)

  • JavaDoc NPEอย่างชัดเจนกล่าวว่า"การใช้งานผิดกฎหมายอื่น ๆ ของวัตถุโมฆะ" หากมันถูก จำกัด เฉพาะสถานการณ์ที่รันไทม์พบโมฆะเมื่อไม่ควรกรณีดังกล่าวทั้งหมดสามารถกำหนดได้ชัดเจนยิ่งขึ้น

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

  • ฉันเลือกNPEมากกว่าIAEด้วยเหตุผลหลายประการ

    • มีความเฉพาะเจาะจงมากขึ้นเกี่ยวกับลักษณะของการดำเนินการที่ผิดกฎหมาย
    • ลอจิกที่ผิดพลาดทำให้โมฆะมีแนวโน้มที่จะแตกต่างจากลอจิกที่ผิดพลาดทำให้ค่าผิดกฎหมาย ตัวอย่างเช่นถ้าฉันตรวจสอบความถูกต้องของข้อมูลที่ผู้ใช้ป้อนถ้าฉันได้รับค่าที่ไม่สามารถยอมรับได้แหล่งที่มาของข้อผิดพลาดนั้นก็คือผู้ใช้ปลายทางของแอปพลิเคชัน ถ้าฉันได้รับ null นั่นเป็นข้อผิดพลาดของโปรแกรมเมอร์
    • ค่าที่ไม่ถูกต้องอาจทำให้เกิดสิ่งต่าง ๆ เช่นสแต็คโอเวอร์โฟลว์หน่วยความจำไม่เพียงพอข้อผิดพลาดในการแยกวิเคราะห์ ฯลฯ โดยทั่วไปข้อผิดพลาดส่วนใหญ่จะปรากฏขึ้น ณ จุดหนึ่งเป็นค่าที่ไม่ถูกต้องในการเรียกใช้เมธอด ด้วยเหตุนี้ฉันจึงเห็นว่า IAE นั้นเป็นGENERAL ที่แท้จริงของข้อยกเว้นทั้งหมดภายใต้ RuntimeException
  • ที่จริงแล้วข้อโต้แย้งที่ไม่ถูกต้องอื่น ๆ อาจส่งผลให้เกิดข้อยกเว้นอื่น ๆ ทุกชนิด UnknownHostException , FileNotFoundException , ข้อผิดพลาดทางไวยากรณ์ที่หลากหลาย, IndexOutOfBoundsException , ความล้มเหลวในการตรวจสอบความถูกต้อง ฯลฯ

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


ความแตกต่างระหว่างข้อยกเว้นที่ไม่ได้ตรวจสอบส่วนใหญ่เป็นเพียงชื่อ
Thorbjørn Ravn Andersen

20

มันเป็นคำถามสไตล์ "สงครามศักดิ์สิทธิ์" ในคำอื่น ๆ ทั้งสองทางเลือกเป็นสิ่งที่ดี แต่คนจะมีการตั้งค่าของพวกเขาซึ่งพวกเขาจะปกป้องไปสู่ความตาย


ไม่มีคำตอบที่ถูกต้องเพียงข้อเดียวสำหรับคำถามนี้และนั่นคือการใช้การโยนข้อยกเว้น IllegalArgument เมื่ออินพุตของวิธีนั้นไม่ถูกต้อง นอกจากนี้ในสภาพแวดล้อมแบบ dev คุณสามารถใช้การยืนยันเพื่อตรวจสอบความถูกต้องของอินพุตและโยนข้อยกเว้นที่เหมาะสม;)
Mr.Q

@ Mr.Q และฉันคิดว่าNullPointerExceptionควรถูกโยน: มันเป็นแบบแผนที่ JDK ใช้และต้องการอินเทอร์เฟซมันมีความเฉพาะเจาะจงมากขึ้น (เช่นIndexOutOfBoundsExceptionฯลฯ )
โซโลมอนอุ๊

kekekekkek ... : D
Yousha Aleayoub

17

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

ดังนั้นถ้าคุณใช้มันและมันก็เป็นnullเช่นNullPointerนั้น ถ้ามันถูกส่งผ่านและเป็นnull, IllegalArgument.


9

Apache Commons Lang มีNullArgumentExceptionที่ทำสิ่งต่าง ๆ ที่กล่าวถึงในที่นี้: มันขยาย IllegalArgumentException และคอนสตรัคเตอร์รายเดียวใช้ชื่อของอาร์กิวเมนต์ที่ควรเป็นค่าว่าง

ในขณะที่ฉันรู้สึกว่าการขว้างปาบางอย่างเช่น NullArgumentException หรือ IllegalArgumentException อธิบายสถานการณ์ที่พิเศษกว่าได้อย่างแม่นยำยิ่งขึ้นเพื่อนร่วมงานของฉันและฉันเลือกที่จะปฏิบัติตามคำแนะนำของ Bloch ในเรื่องนี้


7
โปรดทราบว่าพวกเขาลบมันออกจาก commons-lang3: apache-commons.680414.n4.nabble.com/…
artbristol

7

ไม่สามารถเห็นด้วยเพิ่มเติมกับสิ่งที่พูด ล้มเหลวในช่วงต้นล้มเหลวอย่างรวดเร็ว มนต์ดียกเว้น

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

2 เซนต์ของฉัน


7

ที่จริงแล้วคำถามของการขว้างปา IllegalArgumentException หรือ NullPointerException นั้นอยู่ในมุมมองที่อ่อนน้อมถ่อมตนของฉันเท่านั้น "สงครามศักดิ์สิทธิ์" สำหรับชนกลุ่มน้อยที่มีความเข้าใจที่ไม่ถูกต้องเกี่ยวกับการจัดการข้อยกเว้นใน Java โดยทั่วไปแล้วกฎจะง่ายและเป็นดังนี้:

  • การละเมิดข้อ จำกัด การโต้แย้งจะต้องระบุโดยเร็วที่สุด (-> ล้มเหลวเร็ว) เพื่อหลีกเลี่ยงสถานะที่ผิดกฎหมายซึ่งยากต่อการแก้ไข
  • ในกรณีที่ตัวชี้โมฆะไม่ถูกต้องไม่ว่าด้วยเหตุผลใดก็ตามให้ขว้าง NullPointerException
  • ในกรณีของดัชนีอาเรย์ / คอลเลกชันที่ผิดกฎหมายให้โยน ArrayIndexOutOfBounds
  • ในกรณีที่ขนาดอาร์เรย์ / คอลเลกชันลบให้ลบ NegativeArraySizeException
  • ในกรณีที่มีข้อโต้แย้งที่ผิดกฎหมายซึ่งไม่ได้กล่าวถึงข้างต้นและคุณไม่มีประเภทข้อยกเว้นที่เฉพาะเจาะจงมากขึ้นให้โยน IllegalArgumentException เป็นตะกร้าขยะ
  • ในทางกลับกันในกรณีที่มีการละเมิดข้อ จำกัด ภายในฟิลด์ที่ไม่สามารถหลีกเลี่ยงได้โดยการล้มเหลวอย่างรวดเร็วด้วยเหตุผลที่ถูกต้องให้จับและสร้างใหม่เป็น IllegalStateException หรือข้อยกเว้นที่ตรวจสอบเฉพาะเจาะจงมากขึ้น อย่าปล่อยให้ผ่าน NullPointerException ดั้งเดิม ArrayIndexOutOfBounds ฯลฯ ในกรณีนี้!

มีเหตุผลที่ดีอย่างน้อยสามข้อในกรณีของการทำแผนที่การละเมิดข้อโต้แย้งทุกประเภทที่มีต่อการละเมิด IllegalArgumentException โดยที่สามอาจรุนแรงมากเพื่อทำเครื่องหมายการปฏิบัติที่ไม่ดี:

(1) โปรแกรมเมอร์ไม่สามารถสันนิษฐานได้อย่างปลอดภัยว่าทุกกรณีของการละเมิดข้อ จำกัด การโต้แย้งส่งผลให้ IllegalArgumentException เนื่องจากคลาสมาตรฐานขนาดใหญ่ส่วนใหญ่ใช้ข้อยกเว้นนี้แทนที่จะเป็นตะกร้าขยะหากไม่มีข้อยกเว้นที่เฉพาะเจาะจงมากขึ้น การพยายามแมปกรณีของการละเมิดข้อ จำกัด การโต้แย้งกับ IllegalArgumentException ใน API ของคุณจะนำไปสู่ความขัดข้องของโปรแกรมเมอร์ที่ใช้คลาสของคุณเนื่องจากไลบรารีมาตรฐานส่วนใหญ่จะปฏิบัติตามกฎที่แตกต่างกันซึ่งละเมิดคุณและผู้ใช้ API ส่วนใหญ่ก็จะใช้เช่นกัน!

(2) การแมปข้อยกเว้นจริง ๆ แล้วส่งผลให้เกิดความผิดปกติประเภทต่าง ๆ ที่เกิดจากการสืบทอดเดี่ยว: ข้อยกเว้น Java ทั้งหมดเป็นคลาสดังนั้นจึงรองรับการถ่ายทอดเดี่ยวเท่านั้น ดังนั้นจึงไม่มีวิธีสร้างข้อยกเว้นที่พูดทั้ง NullPointerException และ IllegalArgumentException อย่างแท้จริงเนื่องจากคลาสย่อยสามารถสืบทอดได้จากสิ่งใดสิ่งหนึ่งเท่านั้น การโยน IllegalArgumentException ในกรณีที่มีอาร์กิวเมนต์เป็นโมฆะทำให้ผู้ใช้ API สามารถแยกแยะปัญหาต่าง ๆ ได้ยากขึ้นเมื่อใดก็ตามที่โปรแกรมพยายามแก้ไขปัญหาทางโปรแกรมเช่นโดยป้อนค่าเริ่มต้นลงในการโทรซ้ำ!

(3) การทำแผนที่จริง ๆ แล้วสร้างอันตรายจากการปิดบังข้อผิดพลาด: ในการแมปการละเมิดข้อ จำกัด ของข้อโต้แย้งใน IllegalArgumentException คุณจะต้องเขียนโค้ดการลองจับด้านนอกภายในทุกวิธีที่มีข้อ จำกัด ที่ขัดแย้ง อย่างไรก็ตามการจับรันไทม์ RuntimeException ในบล็อก catch นี้เป็นไปไม่ได้เนื่องจากมีความเสี่ยงในการแมปเอกสาร RuntimeExceptions ที่จัดทำขึ้นโดยวิธีการใช้ที่ใช้ภายในของคุณเข้าสู่ IllegalArgumentException แม้ว่าพวกเขาจะไม่ได้เกิดจากการละเมิดข้อโต้แย้ง ดังนั้นคุณต้องมีความเฉพาะเจาะจงมาก ๆ แต่ความพยายามนั้นก็ไม่ได้ป้องกันคุณจากกรณีที่คุณบังเอิญทำแผนที่ข้อยกเว้นรันไทม์ที่ไม่มีเอกสารของ API อื่น (เช่นข้อผิดพลาด) ไปยัง IllegalArgumentException API ของคุณ

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


6

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

if( variable == null )
    throw new IllegalArgumentException("The object 'variable' cannot be null");

คุณไม่มีเหตุผลที่จะใช้ "NullPointerException" โดยปริยาย NullPointerException เป็นข้อยกเว้นที่เกิดจาก Java Virtual Machine เมื่อคุณพยายามเรียกใช้โค้ดโดยอ้างอิงเป็นศูนย์ (Like toString () )


6

การโยนข้อยกเว้นที่ไม่รวมถึงnullข้อโต้แย้ง ( NullPointerExceptionหรือประเภทที่กำหนดเอง) ทำให้การnullทดสอบอัตโนมัติน่าเชื่อถือมากขึ้น การทดสอบแบบอัตโนมัตินี้สามารถทำได้ด้วยการสะท้อนและชุดของค่าเริ่มต้นในขณะที่ฝรั่งNullPointerTester 's ตัวอย่างเช่นNullPointerTesterพยายามโทรวิธีต่อไปนี้ ...

Foo(String string, List<?> list) {
  checkArgument(string.length() > 0);
  // missing null check for list!
  this.string = string;
  this.list = list;
}

... ที่มีสองรายการของอาร์กิวเมนต์: และ"", null มันจะทดสอบว่าแต่ละสายเหล่านี้พ่นคาดว่าnull, ImmutableList.of() NullPointerExceptionสำหรับการใช้งานนี้การส่งnullรายการจะไม่สร้างNullPointerExceptionขึ้น มันไม่ แต่เกิดขึ้นในการผลิตIllegalArgumentExceptionเพราะเกิดขึ้นที่จะใช้สตริงเริ่มต้นของNullPointerTester ""หากNullPointerTesterคาดว่าเฉพาะNullPointerExceptionสำหรับnullค่าก็จับข้อผิดพลาด หากคาดว่าIllegalArgumentExceptionจะพลาด


5

คอลเลกชันบางคนคิดว่าnullจะถูกปฏิเสธการใช้มากกว่าNullPointerException IllegalArgumentExceptionตัวอย่างเช่นถ้าคุณเปรียบเทียบชุดมีnullชุดที่ปฏิเสธnullชุดแรกจะเรียกcontainsAllในที่อื่น ๆ และจับมันNullPointerException- IllegalArgumentExceptionแต่ไม่ (ฉันกำลังดูการนำไปปฏิบัติAbstractSet.equals)

คุณสามารถโต้แย้งได้อย่างสมเหตุสมผลว่าการใช้ข้อยกเว้นที่ไม่ได้ตรวจสอบด้วยวิธีนี้คือ antipattern การเปรียบเทียบคอลเลกชันที่มีnullคอลเลกชันที่ไม่สามารถมีได้nullคือข้อผิดพลาดที่น่าจะสร้างข้อยกเว้นจริง ๆ หรือการใส่nullคอลเลกชัน . อย่างไรก็ตามถ้าคุณไม่เต็มใจที่จะบอกว่าequalsควรทำให้เกิดข้อยกเว้นในกรณีเช่นนี้คุณก็จำไม่ได้ว่าNullPointerExceptionต้องใช้ในบางสถานการณ์ แต่ไม่ใช่ในกรณีอื่น ("IAE ก่อน NPE ยกเว้นหลังจาก 'c' ... ")


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

2
new TreeSet<>().containsAll(Arrays.asList((Object) null));พ่นNPEเพราะมีList null
Chris Povirk

1
แท้จริงแล้ว TreeSet # มีการส่ง NPE "ถ้าองค์ประกอบที่ระบุเป็นโมฆะและชุดนี้ใช้การเรียงตามธรรมชาติหรือตัวเปรียบเทียบไม่อนุญาตองค์ประกอบที่เป็นโมฆะ" ดูเฉพาะ AbstractSet ที่อนุญาตให้เป็น null เท่านั้น โดยส่วนตัวแล้วฉันคิดว่ามันแปลกมันไม่เพียงแค่ส่งคืนค่าเท็จ แต่เนื่องจากในกรณีนี้อาจไม่มีค่าเป็นศูนย์
Alowaniak

5

ในฐานะที่เป็นคำถามอัตนัยเรื่องนี้ควรปิด แต่ก็ยังคงเปิดอยู่:

นี่เป็นส่วนหนึ่งของนโยบายภายในที่ใช้ในสถานที่ทำงานก่อนหน้าของฉันและทำงานได้ดีจริงๆ ทั้งหมดนี้มาจากความทรงจำดังนั้นฉันจำคำศัพท์ไม่ได้ เป็นที่น่าสังเกตว่าพวกเขาไม่ได้ใช้ข้อยกเว้นที่ตรวจสอบแล้ว แต่อยู่นอกเหนือขอบเขตของคำถาม ข้อยกเว้นที่ไม่ได้ตรวจสอบพวกเขาใช้แบ่งออกเป็น 3 ประเภทหลัก

NullPointerException: อย่าโยนโดยเจตนา NPE จะถูกส่งออกไปโดย VM เท่านั้นเมื่อยกเลิกการอ้างอิงการอ้างอิง Null ความพยายามที่เป็นไปได้ทั้งหมดจะต้องทำเพื่อให้แน่ใจว่าสิ่งเหล่านี้จะไม่ถูกโยนทิ้ง @Nullable และ @NotNull ควรใช้ร่วมกับเครื่องมือวิเคราะห์รหัสเพื่อค้นหาข้อผิดพลาดเหล่านี้

IllegalArgumentException: ส่งออกมาเมื่อข้อโต้แย้งไปยังฟังก์ชั่นไม่สอดคล้องกับเอกสารสาธารณะเช่นว่าข้อผิดพลาดสามารถระบุและอธิบายในแง่ของการขัดแย้งส่งผ่านสถานการณ์ของ OP จะตกอยู่ในหมวดหมู่นี้

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

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

อย่างที่ฉันพูดไประบบนี้ใช้งานได้ดีมากและพาใครบางคนมาอธิบายว่าทำไมความแตกต่างอยู่ที่นั่น: "ขึ้นอยู่กับประเภทของข้อผิดพลาดมันค่อนข้างตรงไปตรงมาสำหรับคุณที่จะคิดว่าจะทำอย่างไร ว่ามีอะไรผิดพลาดคุณสามารถรู้ได้ว่าจะหาข้อผิดพลาดนั้นได้ที่ไหนและสร้างข้อมูลการดีบั๊กเพิ่มเติม "

NullPointerException: จัดการกับกรณี Null หรือใส่ในการยืนยันเพื่อที่จะไม่โยน NPE หากคุณใส่คำยืนยันเป็นเพียงหนึ่งในสองประเภทอื่น ๆ ถ้าเป็นไปได้ให้ทำการดีบั๊กต่อไปราวกับว่ามีการยืนยันในตอนแรก

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

IllegalStateException: คุณไม่ได้เรียกฟังก์ชันของคุณตามลำดับที่ถูกต้อง หากคุณกำลังใช้หนึ่งในข้อโต้แย้งของคุณตรวจสอบพวกเขาและโยน IllegalArgumentException อธิบายปัญหา จากนั้นคุณสามารถแพร่กระจายแก้มขึ้นกับกองซ้อนจนกว่าคุณจะพบปัญหา

อย่างไรก็ตามประเด็นของเขาคือคุณสามารถคัดลอก IllegalArgumentAssertions ขึ้นมาในสแต็กเท่านั้น ไม่มีวิธีที่คุณจะเผยแพร่ IllegalStateExceptions หรือ NullPointerExceptions ขึ้นสแต็กเพราะพวกเขามีบางอย่างที่เกี่ยวข้องกับการทำงานของคุณ


4

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


9
JavaDoc บน NPE มีความคิดเห็นอื่น: "แอปพลิเคชั่นควรใช้อินสแตนซ์ของคลาสนี้เพื่อระบุการใช้วัตถุ null ที่ผิดกฎหมาย" อย่าเด็ดขาด
Donz

4

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


ฉันยอมรับวิธี "โยน IllegalArgumentException ใหม่ (" foo == null ") วิธีการ" คุณต้องเข้าสู่ระบบชื่อตัวแปรต่อไป (เพื่อให้แน่ใจว่าคุณกำลังดู sttatement ที่เหมาะสม ฯลฯ )
Thorbjørn Ravn Andersen

4

ขั้วต่อ ... มันไม่ทับซ้อนกันใช่ไหม เฉพาะส่วนที่ไม่ทับซ้อนกันเท่านั้นที่สามารถสร้างขั้วคู่กันได้ ตามที่เห็น:

throw new IllegalArgumentException(new NullPointerException(NULL_ARGUMENT_IN_METHOD_BAD_BOY_BAD));

1
สิ่งนี้จะเพิ่มค่าใช้จ่ายเป็นสองเท่าสำหรับการสร้างข้อยกเว้นและจะไม่ช่วยอย่างที่จับได้จริง ๆNullPointerExceptionจะไม่ทำอะไรเลย สิ่งเดียวที่จะช่วยได้คือIllegalNullPointerArgumentException extends IllegalArgumentException, NullPointerExceptionแต่เราไม่มีมรดกหลายอย่าง
maaartinus

ฉันเชื่อว่าข้อยกเว้นที่เฉพาะเจาะจงมากขึ้นควรได้รับการห่อด้วยข้อยกเว้นทั่วไปเพิ่มเติม NPE ใช้สำหรับนิพจน์ในขณะที่ IAE ใช้สำหรับเมธอด เนื่องจากเมธอดมีข้อความสั่งที่ประกอบด้วยนิพจน์ IAE จึงเป็นเรื่องทั่วไป
Sgene9

เกี่ยวกับค่าใช้จ่ายฉันไม่มีความคิด แต่โดยพื้นฐานแล้วสแต็คตรัยจะเหมือนกันยกเว้นว่าชื่อของข้อยกเว้นเปลี่ยนไปตรงกลางฉันคิดว่าไม่ควรมีค่าใช้จ่ายมากเกินไปสำหรับข้อยกเว้นสองเท่า หากใครกังวลเรื่องค่าใช้จ่ายเขาสามารถใช้คำสั่ง "if" เพื่อส่งกลับค่า null หรือ -1 แทนการโยนข้อยกเว้น
Sgene9

4

NullPointerExceptionnullโยนเมื่อพยายามที่จะเข้าถึงวัตถุที่มีตัวแปรอ้างอิงที่มีค่าในปัจจุบัน

IllegalArgumentException โยนเมื่อวิธีการรับอาร์กิวเมนต์ที่จัดรูปแบบแตกต่างจากวิธีที่คาดไว้


3

ตามสถานการณ์ของคุณIllegalArgumentExceptionเป็นตัวเลือกที่ดีที่สุดเนื่องจากnullไม่ใช่ค่าที่ถูกต้องสำหรับคุณสมบัติของคุณ


0

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


-1

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

ความแตกต่างใหญ่ที่นี่คือควรใช้ IllegalArgumentException เมื่อตรวจสอบว่าอาร์กิวเมนต์ของวิธีการที่ถูกต้อง NullPointerException ควรจะใช้เมื่อใดก็ตามที่วัตถุ "ถูกใช้" เมื่อมันเป็นโมฆะ

ฉันหวังว่าจะช่วยให้ทั้งสองในมุมมอง


1
บิตสำคัญคือมันเป็นแอปพลิเคชั่นที่ใช้ null ไม่ใช่รันไทม์ ดังนั้นจึงมีการทับซ้อนที่ค่อนข้างใหญ่ระหว่าง "เมื่อวิธีการผ่านการโต้แย้งที่ผิดกฎหมายหรือไม่เหมาะสม" และ "เมื่อแอปพลิเคชันใช้โมฆะ" ตามทฤษฎีแล้วหากแอปผ่านค่า null สำหรับเขตข้อมูลที่ต้องใช้ค่าที่ไม่ใช่ค่า null ทั้งสองเกณฑ์จะต้องผ่านเกณฑ์
Christopher Smith

-1

หากเป็น "setter" หรืออื่น ๆ ที่ฉันได้รับสมาชิกเพื่อใช้ในภายหลังฉันมักจะใช้ IllegalArgumentException

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

หากฉันเอาชนะวิธีใดฉันจะใช้วิธีการที่ใช้แทน


-1

คุณควรโยน IllegalArgumentException เนื่องจากจะทำให้โปรแกรมเมอร์เห็นได้ชัดว่าเขาทำสิ่งที่ไม่ถูกต้อง นักพัฒนามักคุ้นเคยกับการเห็น NPE ที่ถูกโยนโดย VM ซึ่งโปรแกรมเมอร์คนใดจะไม่ตระหนักถึงข้อผิดพลาดของเขาในทันทีและจะเริ่มมองไปรอบ ๆ แบบสุ่มหรือแย่กว่านั้นโทษรหัสของคุณว่าเป็น 'รถม้าชนิดเล็ก'


4
ขออภัยหากโปรแกรมเมอร์ดูรอบ ๆ "สุ่ม" เมื่อได้รับข้อยกเว้นใด ๆ ... การเปลี่ยนชื่อของข้อยกเว้นจะไม่ช่วยอะไรมาก
Christopher Smith

-1

ในกรณีนี้ IllegalArgumentException ให้ข้อมูลที่ชัดเจนแก่ผู้ใช้โดยใช้ API ของคุณว่า "ไม่ควรเป็นโมฆะ" ตามที่ผู้ใช้งานฟอรัมคนอื่นชี้ให้เห็นคุณสามารถใช้ NPE หากคุณต้องการตราบเท่าที่คุณถ่ายทอดข้อมูลที่ถูกต้องไปยังผู้ใช้โดยใช้ API ของคุณ

GaryF และ tweakt ปล่อย "Effective Java" (ซึ่งฉันสาบานด้วย) อ้างอิงที่แนะนำให้ใช้ NPE และดูว่า API ที่ดีอื่นถูกสร้างขึ้นเป็นวิธีที่ดีที่สุดในการดูวิธีการสร้าง API ของคุณ

อีกตัวอย่างที่ดีคือการดู Spring APIs ตัวอย่างเช่น org.springframework.beans.BeanUtils.instantiateClass (ตัวสร้าง ctor, Object [] args) มีบรรทัด Assert.notNull (ctor "ตัวสร้างต้องไม่เป็นโมฆะ") org.springframework.util.Assert.notNull (วัตถุ Object, ข้อความ String) วิธีการตรวจสอบเพื่อดูว่าอาร์กิวเมนต์ (วัตถุ) ที่ผ่านมาเป็นโมฆะและถ้ามันจะโยน IllegalArgumentException ใหม่ (ข้อความ) ซึ่งจะถูกจับในองค์กร springframework.beans.BeanUtils.instantiateClass (... ) วิธีการ


-5

หากคุณเลือกที่จะโยน NPE และคุณกำลังใช้อาร์กิวเมนต์ในวิธีการของคุณมันอาจซ้ำซ้อนและมีค่าใช้จ่ายสูงในการตรวจสอบ null อย่างชัดเจน ฉันคิดว่า VM ทำเพื่อคุณแล้ว


เวลาทำงานจะไม่รวม msg ที่มีความหมาย
mP

จริงๆแล้วความคิดเห็นนี้อาจได้รับความเห็นอื่น ๆ ให้ VM พูดในNPEขณะที่โปรแกรมเมอร์พูดIAEต่อหน้า VM หากพวกเขาต้องการ
Jin Kwon

1
เเพง? ฉันไม่คิดว่า == null นั้นแพง ... นอกจากอาร์กิวเมนต์ null สามารถเก็บไว้เพื่อใช้ในภายหลังได้และจะโยนข้อยกเว้นนานหลังจากการเรียกใช้เมธอดทำให้ข้อผิดพลาดนั้นยากต่อการติดตาม หรือคุณสามารถสร้างวัตถุที่มีราคาแพงก่อนที่จะใช้อาร์กิวเมนต์เป็นโมฆะและอื่น ๆ การตรวจหาเร็วน่าจะเป็นตัวเลือกที่ดี
PhiLho

การลงคะแนนเสียงของคำตอบนี้เป็นความเข้าใจผิดของฮาร์ดแวร์ที่อยู่เบื้องหลัง แน่นอนว่าการตรวจสอบฮาร์ดแวร์ (CPU นั้นทำ) นั้นถูกกว่าการตรวจสอบที่ชัดเจน การยกเลิกการอ้างอิง null เป็นกรณีพิเศษ SegmentationFault (SegV) (การเข้าถึงเพจที่ไม่ได้เป็นเจ้าของโดยกระบวนการ) ซึ่งการตรวจสอบ CPU / OS และ JRE จัดการเป็นกรณีพิเศษที่ขว้าง NullPointerException
digital_infinity
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.