เมื่อใดควรใช้การยืนยันและเมื่อใดที่ควรใช้ข้อยกเว้น


121

ส่วนใหญ่ฉันจะใช้ข้อยกเว้นในการตรวจสอบเงื่อนไขในรหัสของฉันฉันสงสัยว่าเวลาที่เหมาะสมในการใช้การยืนยันคืออะไร?

ตัวอย่างเช่น

Group group=null;
try{
    group = service().getGroup("abc");
}catch(Exception e){
    //I dont log error because I know whenever error occur mean group not found
}

if(group !=null)
{
    //do something
}

คุณช่วยระบุได้ไหมว่าการยืนยันเข้ากับที่นี่ได้อย่างไร? ฉันควรใช้คำยืนยันหรือไม่?

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

คำตอบ:


81

การยืนยันควรใช้เพื่อตรวจสอบบางสิ่งที่ไม่ควรเกิดขึ้นในขณะที่ควรใช้ข้อยกเว้นเพื่อตรวจสอบบางสิ่งที่อาจเกิดขึ้น

ตัวอย่างเช่นฟังก์ชันอาจหารด้วย 0 ดังนั้นควรใช้ข้อยกเว้น แต่สามารถใช้การยืนยันเพื่อตรวจสอบว่าฮาร์ดไดรฟ์หายไปในทันที

การยืนยันจะหยุดโปรแกรมไม่ให้ทำงาน แต่มีข้อยกเว้นที่ทำให้โปรแกรมทำงานต่อไปได้

โปรดทราบว่าif(group != null)ไม่ใช่การยืนยัน แต่เป็นเพียงเงื่อนไขเท่านั้น


3
"การยืนยันสามารถใช้เพื่อตรวจสอบว่าฮาร์ดไดรฟ์ขาดกะทันหัน" - ฉันว่ามันไม่ถูกต้อง: ทำไมคุณถึงต้องการให้จัดการสิ่งนี้ในระหว่างการพัฒนา แต่ไม่ได้อยู่ในการผลิต (เมื่อโดยทั่วไปแล้วการยืนยันจะถูกปิดใช้งาน)
herman

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

1
@Marius เงื่อนไขของคุณอาจถูกแทนที่ด้วยการยืนยันเช่นนี้: assert group! = null
IgorGanapolsky

1
ลดลงเนื่องจากตัวอย่างฮาร์ดไดรฟ์ขัดแย้งกับปรัชญาของคุณเอง ฮาร์ดไดรฟ์ "หายไป" (จากมุมมองของโค้ด) อาจเกิดขึ้นได้ในความเป็นจริงไม่ว่าจะเป็นไปไม่ได้เพียงใดก็ตาม เช่นเดียวกับที่ @IanGoldby กล่าวว่าการยืนยันควรขึ้นอยู่กับสิ่งที่ควบคุมโดยรหัสของคุณเท่านั้น
Vicky Chijwani

คำตอบที่ดีกว่ามากหากโพสต์โดย Gregory Pakosz โปรดอ่านโพสต์นั้น
ormurin

169

จากใจของฉัน (รายการอาจไม่สมบูรณ์และยาวเกินไปที่จะใส่ในความคิดเห็น) ฉันจะพูดว่า:

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

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

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


53
ผมชอบวิธีที่คุณ phrased นี้มีข้อยกเว้นอยู่ทนทานของแอพลิเคชันของคุณในขณะที่ยืนยันความถูกต้องของมันอยู่
M. Dudley

ฉันโพสต์สิ่งนี้ไปยังเว็บไซต์ของฉัน: pempek.net/articles/2013/11/16/assertions-or-exceptions
Gregory Pakosz

และถ้าคุณกำลังมองหาไลบรารียืนยัน C ++ ที่กำหนดเองฉันเปิดตัวgithub.com/gpakosz/Assert
Gregory Pakosz

26

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

นอกจากนี้คุณควรอ่านบทความ Oracle เกี่ยวกับการยืนยันเพื่อดูกรณีอื่น ๆ เพิ่มเติมว่าจะใช้ - หรือไม่ใช้ - ยืนยัน


Hue hue hue ฉันสงสัยว่าทำไมรหัสของฉันจึงล้มเหลวใน Eclipse แต่ทำงานได้ดีบนบรรทัดคำสั่ง
สตีฟ

15

ตามกฎทั่วไป:

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

รหัสต่อไปนี้จากคำถามของคุณเป็นรูปแบบที่ไม่ดีและอาจมีปัญหา

try {
    group = service().getGroup("abc");
} catch (Exception e) {
    //i dont log error because i know whenever error occur mean group not found
}

ปัญหาคือคุณไม่ทราบว่ามีข้อยกเว้นหมายความว่าไม่พบกลุ่ม นอกจากนี้ยังเป็นไปได้ว่าการservice()โทรดังกล่าวส่งข้อยกเว้นหรือการโทรกลับnullซึ่งทำให้เกิดไฟล์NullPointerException .

เมื่อคุณพบข้อยกเว้นที่ "คาดไว้" คุณควรจับเฉพาะข้อยกเว้นที่คุณคาดหวัง การจับjava.lang.Exception(และโดยเฉพาะอย่างยิ่งการไม่บันทึก) จะทำให้คุณวินิจฉัย / แก้ไขปัญหาได้ยากขึ้นและอาจทำให้แอปสร้างความเสียหายได้มากขึ้น


4

กลับมาที่ Microsoft คำแนะนำคือการโยนข้อยกเว้นใน API ทั้งหมดที่คุณเปิดเผยต่อสาธารณะและใช้ Asserts ในทุกประเภทของสมมติฐานที่คุณทำเกี่ยวกับโค้ดที่อยู่ภายใน มันเป็นคำจำกัดความที่หลวม ๆ แต่ฉันเดาว่ามันขึ้นอยู่กับนักพัฒนาแต่ละคนที่จะลากเส้น

เกี่ยวกับการใช้ข้อยกเว้นดังที่ชื่อกล่าวไว้การใช้งานของพวกเขาควรมีความพิเศษดังนั้นสำหรับรหัสที่คุณนำเสนอข้างต้นไฟล์ getGroupโทรควรส่งคืนnullหากไม่มีบริการ ข้อยกเว้นควรเกิดขึ้นก็ต่อเมื่อลิงก์เครือข่ายล่มหรืออะไรทำนองนั้น

ฉันเดาว่าข้อสรุปก็คือทีมพัฒนาสำหรับแต่ละแอปพลิเคชันจะกำหนดขอบเขตของการยืนยันและข้อยกเว้น


IMHO ปัญหาเกี่ยวกับคำแนะนำแบบนั้นก็คือใช้ได้ตราบเท่าที่ขอบเขตระหว่างส่วนสาธารณะและส่วนส่วนตัวของ API ได้รับการแก้ไขแล้ว หากคุณกำลังพัฒนาโค้ดใหม่ขอบเขตนั้นมักจะค่อนข้างลื่นไหล ...
Len Holgate

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

3

ตามเอกสารนี้http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#design-faq-general "คำแถลงยืนยันเหมาะสมสำหรับเงื่อนไขเบื้องต้นที่ไม่เป็นสาธารณะเงื่อนไขภายหลังและคลาสที่ไม่แปรเปลี่ยน การตรวจสอบการตรวจสอบเงื่อนไขเบื้องต้นสาธารณะควรดำเนินการโดยการตรวจสอบภายในวิธีการที่ส่งผลให้เกิดข้อยกเว้นที่เป็นเอกสารโดยเฉพาะเช่น IllegalArgumentException และ IllegalStateException "

หากคุณต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับสิ่งที่จำเป็น, postcondition และคงระดับการตรวจสอบเอกสารนี้: http://docs.oracle.com/javase/6/docs/technotes/guides/language/assert.html#usage-conditions นอกจากนี้ยังมีตัวอย่างการใช้การยืนยัน


1

การทดสอบ null จะจับเฉพาะ null ที่ทำให้เกิดปัญหาในขณะที่ลอง / จับตามที่คุณมีจะตรวจพบข้อผิดพลาดใด ๆ

โดยทั่วไปแล้วลอง / จับนั้นปลอดภัยกว่า แต่ช้ากว่าเล็กน้อยและคุณต้องระวังว่าคุณจะพบข้อผิดพลาดทุกประเภทที่อาจเกิดขึ้น ดังนั้นฉันจะบอกว่าใช้ try / catch วันหนึ่งรหัส getGroup อาจเปลี่ยนแปลงและคุณอาจต้องการเน็ตที่ใหญ่กว่านั้น


1

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


1

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

ดังนั้นการใช้การยืนยันใน Java

  1. เป็นวิธีการที่กระชับมากขึ้นในการเขียนเงื่อนไข / บล็อกโยน
  2. อนุญาตให้คุณเปิด / ปิดการตรวจสอบเหล่านี้ผ่านพารามิเตอร์ JVM โดยปกติฉันจะปล่อยการตรวจสอบเหล่านี้ไว้ตลอดเวลาเว้นแต่จะส่งผลกระทบต่อประสิทธิภาพการทำงานของรันไทม์หรือมีโทษในลักษณะเดียวกัน

AssertionError เป็นคลาสย่อยของ Error ไม่ใช่ RuntimeException
Stephen C

อา. แน่นอน. ฉันกำลังคิดว่าจะเลือก / ไม่เลือก แก้ไขแล้ว
Brian Agnew

อธิบายว่าการยืนยันคืออะไร (จากมุมมองที่ขัดแย้งกัน) แต่ไม่ใช่ว่าจะใช้เมื่อใดอย่างแน่นอน
Karl Richter

1

ดูหัวข้อ 6.1.2 (การยืนยันเทียบกับรหัสข้อผิดพลาดอื่น ๆ ) ของเอกสารของ Sun ที่ลิงค์ต่อไปนี้

http://www.oracle.com/technetwork/articles/javase/javapch06.pdf

เอกสารนี้ให้คำแนะนำที่ดีที่สุดที่ฉันเคยเห็นว่าควรใช้คำยืนยันเมื่อใด อ้างจากเอกสาร:

"หลักการง่ายๆคือคุณควรใช้การยืนยันสำหรับกรณีพิเศษที่คุณอยากจะลืมการยืนยันเป็นวิธีที่เร็วที่สุดในการจัดการและลืมเงื่อนไขหรือสถานะที่คุณไม่คาดคิดว่าจะต้องทำ จัดการกับ."


0

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

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