ฉันมีวิธีการที่ควรส่งคืนวัตถุหากพบ
หากไม่พบฉันควร:
- ส่งคืน null
- โยนข้อยกเว้น
- อื่น ๆ
ฉันมีวิธีการที่ควรส่งคืนวัตถุหากพบ
หากไม่พบฉันควร:
คำตอบ:
หากคุณคาดหวังที่จะหาค่าอยู่เสมอให้โยนข้อยกเว้นหากไม่มีอยู่ ข้อยกเว้นจะหมายความว่ามีปัญหา
หากค่าอาจหายไปหรือมีอยู่และทั้งสองอย่างนั้นถูกต้องสำหรับแอปพลิเคชันตรรกะแล้วส่งคืนค่า null
สำคัญกว่า: คุณทำอะไรที่อื่นในรหัส? ความมั่นคงเป็นสิ่งสำคัญ
GetPersonById(25)
จะโยนถ้าคนนั้นถูกลบ แต่GetPeopleByHairColor("red")
จะส่งกลับผลลัพธ์ที่ว่างเปล่า ดังนั้นฉันคิดว่าพารามิเตอร์พูดอะไรบางอย่างเกี่ยวกับความคาดหวัง
เพียงโยนข้อยกเว้นถ้ามันเป็นข้อผิดพลาดอย่างแท้จริง ถ้ามันเป็นพฤติกรรมที่คาดไว้สำหรับวัตถุที่ไม่มีอยู่กลับเป็นโมฆะ
มิฉะนั้นมันเป็นเรื่องของการตั้งค่า
ตามกฎทั่วไปหากเมธอดควรส่งคืนออบเจกต์เสมอให้ไปด้วยข้อยกเว้น หากคุณคาดหวังโมฆะเป็นครั้งคราวและต้องการจัดการกับมันในบางวิธีไปด้วยโมฆะ
ไม่ว่าคุณจะทำอะไรฉันขอแนะนำให้ใช้ตัวเลือกที่สาม: ส่งคืนสตริงที่ระบุว่า "WTF"
ถ้า null ไม่เคยระบุถึงข้อผิดพลาดแล้วเพียงแค่กลับ null
ถ้า null เป็นข้อผิดพลาดเสมอให้ทำการยกเว้น
หากบางครั้ง null เป็นข้อยกเว้นให้โค้ดสองรูทีน รูทีนหนึ่งโยนข้อยกเว้นและอีกชุดหนึ่งเป็นรูทีนการทดสอบบูลีนที่ส่งคืนวัตถุในพารามิเตอร์เอาต์พุตและรูทีนส่งคืนเท็จถ้าไม่พบวัตถุ
เป็นการยากที่จะใช้รูทีนทดลองในทางที่ผิด มันง่ายมากที่จะลืมตรวจสอบค่าว่าง
ดังนั้นเมื่อ null เป็นข้อผิดพลาดคุณเพิ่งเขียน
object o = FindObject();
เมื่อโมฆะไม่ใช่ข้อผิดพลาดคุณสามารถรหัสสิ่งที่ต้องการ
if (TryFindObject(out object o)
// Do something with o
else
// o was not found
find
และfindOrFail
จาก Laravel Eloquent
TryFindObject
วิธีการ? Tuples ดูกระบวนทัศน์ที่ขี้เกียจสำหรับโปรแกรมเมอร์ที่ไม่ต้องการใช้เวลาในการกำหนดวัตถุที่ห่อหุ้มหลายค่า นั่นคือสิ่งสำคัญ tuples ทั้งหมดอยู่ที่หลักอย่างไรก็ตาม
ฉันแค่อยากจะสรุปตัวเลือกต่าง ๆ ที่กล่าวถึงก่อนหน้านี้แล้วก็โยนตัวใหม่ใน:
หรือคุณอาจรวมตัวเลือกเหล่านี้:
จัดเตรียมเวอร์ชันที่โอเวอร์โหลดหลายเวอร์ชันของคุณดังนั้นผู้เรียกสามารถตัดสินใจว่าจะไปทางไหน ในกรณีส่วนใหญ่เพียงอันแรกเท่านั้นที่มีการใช้อัลกอริทึมการค้นหาและอีกอันหนึ่งเพิ่งสรุปไปรอบ ๆ อันแรก:
Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);
แม้ว่าคุณเลือกที่จะให้การใช้งานเพียงครั้งเดียว แต่คุณอาจต้องการใช้รูปแบบการตั้งชื่อเช่นนั้นเพื่อทำให้สัญญาของคุณชัดเจนยิ่งขึ้นและช่วยให้คุณควรตัดสินใจเพิ่มการใช้งานอื่นด้วยเช่นกัน
คุณไม่ควรใช้มากเกินไป แต่อาจเป็นประโยชน์อย่างมากเมื่อเขียนคลาสผู้ช่วยเหลือซึ่งคุณจะใช้ในแอพพลิเคชั่นหลายร้อยตัวที่มีข้อผิดพลาดที่แตกต่างกันมากมาย
Expected<T> findObject(String)
ที่Expected<T>
มีฟังก์ชั่นorNull()
, orThrow()
, ,orSupplied(Supplier<T> supplier)
orDefault(T default)
ข้อมูลนี้ได้จากการจัดการข้อผิดพลาด
ใช้รูปแบบวัตถุ null หรือโยนข้อยกเว้น
Person somePerson = personRepository.find("does-not-exist");
สมมติว่าวิธีการนี้ส่งกลับวัตถุ null สำหรับ does-not-exist
ID อะไรจะเป็นพฤติกรรมที่ถูกต้องเพื่อsomePerson.getAge()
? ตอนนี้ฉันยังไม่มั่นใจว่ารูปแบบวัตถุ null เป็นโซลูชันที่เหมาะสมสำหรับการค้นหาเอนทิตี
สอดคล้องกับ API ที่คุณใช้
ข้อดีของการโยนข้อยกเว้น:
สำหรับคำอธิบายเพิ่มเติมกับตัวอย่างดู: http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/
มันขึ้นอยู่กับว่าภาษาและรหัสของคุณส่งเสริม: LBYL (ดูก่อนที่คุณจะกระโดด) หรือ EAFP (ง่ายต่อการขอการให้อภัยมากกว่าการอนุญาต)
LBYL บอกว่าคุณควรตรวจสอบค่า (ดังนั้นส่งคืน null)
EAFP บอกให้ลองใช้การดำเนินการและดูว่ามันล้มเหลวหรือไม่ (โยนข้อยกเว้น)
แม้ว่าฉันเห็นด้วยกับข้างต้น .. ข้อยกเว้นควรใช้สำหรับเงื่อนไขพิเศษ / ข้อผิดพลาดและการคืนค่าเป็นโมฆะจะดีที่สุดเมื่อใช้เช็ค
EAFP vs. LBYL ใน Python:
http://mail.python.org/pipermail/python-list/2003-May/205182.html
( เว็บเอกสารเก่า )
แค่ถามตัวเองว่า: "เป็นกรณีพิเศษที่ไม่พบวัตถุ" หรือไม่? หากคาดว่าจะเกิดขึ้นในหลักสูตรปกติของโปรแกรมของคุณคุณอาจไม่ควรเพิ่มข้อยกเว้น (เนื่องจากไม่ใช่พฤติกรรมที่ผิดปกติ)
เวอร์ชั่นสั้น: ใช้ข้อยกเว้นเพื่อจัดการกับพฤติกรรมที่ยอดเยี่ยมไม่ใช่เพื่อจัดการการไหลปกติของการควบคุมในโปรแกรมของคุณ
-Alan
ข้อยกเว้นเกี่ยวข้องกับการออกแบบตามสัญญา
อินเทอร์เฟซของวัตถุเป็นสัญญาระหว่างวัตถุสองรายการผู้โทรต้องเป็นไปตามสัญญามิฉะนั้นผู้รับอาจจะล้มเหลวโดยมีข้อยกเว้น มีสัญญาที่เป็นไปได้สองข้อ
1) วิธีการป้อนข้อมูลทั้งหมดที่ถูกต้องซึ่งในกรณีนี้คุณจะต้องกลับเป็นโมฆะเมื่อวัตถุไม่พบ
2) การป้อนข้อมูลบางอย่างเท่านั้นที่ถูกต้องคือสิ่งที่ส่งผลให้วัตถุที่พบ ในกรณีนี้คุณต้องเสนอวิธีที่สองที่ช่วยให้ผู้โทรตรวจสอบว่าอินพุตนั้นถูกต้องหรือไม่ ตัวอย่างเช่น
is_present(key)
find(key) throws Exception
หากคุณให้ทั้งสองวิธีของสัญญาฉบับที่ 2 คุณจะได้รับอนุญาตให้ทำการยกเว้นยกเว้นไม่พบสิ่งใดเลย!
ฉันชอบที่จะคืนค่า null และพึ่งพาผู้เรียกเพื่อจัดการมันอย่างเหมาะสม ข้อยกเว้น (สำหรับการขาดคำที่ดีกว่า) คือถ้าฉัน 'แน่นอน' วิธีนี้จะส่งคืนวัตถุ ในกรณีนั้นความล้มเหลวเป็นสิ่งที่ควรทำและควรโยน
ขึ้นอยู่กับความหมายของวัตถุที่ไม่พบ
หากเป็นสถานการณ์ปกติให้ส่งคืนค่าว่าง นี่เป็นเพียงสิ่งที่อาจเกิดขึ้นเป็นครั้งคราวและผู้โทรควรตรวจสอบ
หากเป็นข้อผิดพลาดให้โยนข้อยกเว้นผู้เรียกควรตัดสินใจว่าจะทำอย่างไรกับเงื่อนไขข้อผิดพลาดของวัตถุที่หายไป
ในที่สุดก็จะได้ผลแม้ว่าคนส่วนใหญ่มักจะคิดว่าเป็นวิธีปฏิบัติที่ดีที่จะใช้ข้อยกเว้นเฉพาะเมื่อมีบางสิ่งที่ยอดเยี่ยมเกิดขึ้น
นี่เป็นคำแนะนำเพิ่มเติมอีกสองสามข้อ
หากส่งคืนคอลเล็กชันให้หลีกเลี่ยงการส่งคืน null ให้ส่งคืนคอลเล็กชันว่างซึ่งทำให้การจัดการง่ายขึ้นโดยไม่มีการตรวจสอบ null ก่อน
. NET API หลายตัวใช้รูปแบบของพารามิเตอร์ thrownOnError ซึ่งให้ตัวเลือกแก่ผู้โทรว่าเป็นสถานการณ์ที่พิเศษจริง ๆ หรือไม่หากไม่พบวัตถุ Type.GetType เป็นตัวอย่างของสิ่งนี้ รูปแบบทั่วไปอื่นที่มี BCL คือรูปแบบ TryGet ที่ส่งคืนบูลีนและค่าจะถูกส่งผ่านพารามิเตอร์เอาต์พุต
คุณสามารถพิจารณารูปแบบวัตถุ Null ในบางสถานการณ์ซึ่งอาจเป็นค่าเริ่มต้นหรือรุ่นที่ไม่มีพฤติกรรม ที่สำคัญคือหลีกเลี่ยงการตรวจสอบเป็นโมฆะตลอดทั้งฐานรหัส ดูที่นี่สำหรับข้อมูลเพิ่มเติมhttp://geekswithblogs.net/dsellers/archive/2006/09/08/90656.aspx
ในบางฟังก์ชั่นฉันเพิ่มพารามิเตอร์:
..., bool verify = true)
True หมายถึง throw, false หมายถึงส่งคืนค่าข้อผิดพลาดที่ส่งคืน วิธีนี้ใครก็ตามที่ใช้ฟังก์ชั่นนี้มีทั้งสองตัวเลือก ค่าเริ่มต้นควรเป็นจริงเพื่อประโยชน์ของผู้ที่ลืมเกี่ยวกับการจัดการข้อผิดพลาด
ส่งคืน null แทนการโยนข้อยกเว้นและบันทึกความเป็นไปได้ของค่าส่งคืน null ในเอกสาร API อย่างชัดเจน หากรหัสการโทรไม่เป็นไปตาม API และตรวจสอบกรณีที่เป็นโมฆะมันจะส่งผลให้เกิด "การยกเว้นตัวชี้โมฆะ" บางประเภท :)
ใน C ++ ฉันคิดได้สามวิธีในการตั้งค่าวิธีการค้นหาวัตถุ
ตัวเลือก A
Object *findObject(Key &key);
ส่งคืน null เมื่อไม่พบวัตถุ ดีและเรียบง่าย ฉันจะไปกับคนนี้ แนวทางอื่น ๆ ด้านล่างนี้สำหรับผู้ที่ไม่ได้เกลียดชัง
ตัวเลือก B
void findObject(Key &key, Object &found);
ผ่านการอ้างอิงถึงตัวแปรที่จะรับวัตถุ วิธีการโยนข้อยกเว้นเมื่อไม่พบวัตถุ อนุสัญญานี้น่าจะเหมาะสมกว่าหากไม่ได้คาดหวังว่าจะไม่พบวัตถุจริงๆ - ดังนั้นคุณจึงมีข้อยกเว้นเพื่อแสดงว่าเป็นกรณีที่ไม่คาดคิด
ตัวเลือก C
bool findObject(Key &key, Object &found);
วิธีการส่งกลับเท็จเมื่อไม่สามารถหาวัตถุ ข้อได้เปรียบของตัวเลือกที่มากกว่านี้คือคุณสามารถตรวจสอบกรณีข้อผิดพลาดได้ในขั้นตอนเดียวที่ชัดเจน:
if (!findObject(myKey, myObj)) { ...
อ้างถึงกรณีที่ไม่มีการพิจารณาว่าเป็นโมฆะพฤติกรรมพิเศษฉันแน่นอนสำหรับวิธีลองมันชัดเจนไม่จำเป็นต้อง "อ่านหนังสือ" หรือ "ดูก่อนที่คุณจะกระโดด" ตามที่ได้กล่าวไว้ที่นี่
ดังนั้นโดยทั่วไป:
bool TryFindObject(RequestParam request, out ResponseParam response)
และนี่หมายความว่ารหัสของผู้ใช้จะชัดเจนเช่นกัน
...
if(TryFindObject(request, out response)
{
handleSuccess(response)
}
else
{
handleFailure()
}
...
หากเป็นสิ่งสำคัญที่รหัสลูกค้าจะต้องทราบความแตกต่างระหว่างพบและไม่พบและนี่ควรจะเป็นพฤติกรรมประจำ รหัสลูกค้าสามารถตัดสินใจได้ว่าจะทำอย่างไร
โดยทั่วไปควรคืนค่าว่าง โค้ดที่เรียกใช้เมธอดควรตัดสินใจว่าจะโยนข้อยกเว้นหรือลองอย่างอื่น
หรือคืนตัวเลือก
ตัวเลือกนั้นเป็นคลาสของคอนเทนเนอร์ที่บังคับให้ไคลเอ็นต์จัดการเคสเคส Scala มีแนวคิดนี้ค้นหา API
จากนั้นคุณมีวิธีการเช่น T getOrElse (ค่า T ถ้า IfNull) บนวัตถุนี้พวกเขาทั้งคืนวัตถุที่พบหรือ allternative ลูกค้า specifieces
ชอบกลับ null -
หากผู้เรียกใช้โดยไม่ตรวจสอบข้อยกเว้นจะเกิดขึ้นตรงนั้น
หากผู้โทรไม่ได้ใช้จริง ๆ อย่าเสียภาษีเขาtry
/ catch
บล็อก
น่าเสียดายที่ JDK ไม่สอดคล้องกันหากคุณพยายามเข้าถึงคีย์ที่ไม่มีอยู่ในบันเดิลทรัพยากรคุณจะไม่พบข้อยกเว้นและเมื่อคุณขอค่าจากแผนที่คุณจะได้รับ null หากไม่มีอยู่ ดังนั้นฉันจะเปลี่ยนผู้ชนะคำตอบต่อไปนี้ถ้าพบว่าค่าเป็นโมฆะยกข้อยกเว้นเมื่อไม่พบมิฉะนั้นคืนโมฆะ ดังนั้นให้ปฏิบัติตามกฎโดยมีข้อยกเว้นหนึ่งข้อหากคุณต้องการทราบว่าทำไมไม่พบค่าจึงควรเพิ่มข้อยกเว้นเสมอหรือ ..
ตราบใดที่มันควรจะส่งคืนการอ้างอิงไปยังวัตถุการคืนค่า NULL ควรจะดี
อย่างไรก็ตามหากมันคืนเลือดทั้งหมด (เช่นใน C ++ ถ้าคุณทำ: 'return blah;' แทนที่จะ 'return & blah;' (หรือ 'blah' เป็นตัวชี้) คุณจะไม่สามารถส่งค่า NULL ได้เนื่องจากเป็น ไม่ใช่ของประเภท 'วัตถุ' ในกรณีนั้นการโยนข้อยกเว้นหรือส่งคืนวัตถุเปล่าที่ไม่มีชุดธงที่ประสบความสำเร็จคือฉันจะเข้าหาปัญหาได้อย่างไร
อย่าคิดว่าทุกคนพูดถึงค่าใช้จ่ายในการจัดการข้อยกเว้น - ใช้ทรัพยากรเพิ่มเติมเพื่อโหลดและประมวลผลข้อยกเว้นดังนั้นหากแอพพลิเคชั่นที่แท้จริงฆ่าหรือหยุดกิจกรรม (การดำเนินการต่อไปจะทำให้เกิดอันตรายมากกว่าดี) ค่าสภาพแวดล้อมการโทรสามารถตีความตามที่เห็นสมควร
ฉันเห็นด้วยกับสิ่งที่ดูเหมือนจะเป็นฉันทามติที่นี่ (กลับ null ถ้า "ไม่พบ" เป็นผลลัพธ์ที่เป็นไปได้ตามปกติหรือโยนข้อยกเว้นถ้าความหมายของสถานการณ์ต้องการให้วัตถุถูกพบเสมอ)
อย่างไรก็ตามมีความเป็นไปได้ครั้งที่สามที่อาจสมเหตุสมผลขึ้นอยู่กับสถานการณ์เฉพาะของคุณ วิธีการของคุณสามารถส่งคืนวัตถุเริ่มต้นของการจัดเรียงบางอย่างในเงื่อนไข "ไม่พบ" การอนุญาตให้ใช้รหัสที่จะมั่นใจได้ว่ามันจะได้รับวัตถุที่ถูกต้องโดยไม่ต้องตรวจสอบเป็นโมฆะหรือยกเว้นการจับ
ส่งกลับค่า null ข้อยกเว้นเป็นสิ่งที่แน่นอน: สิ่งที่รหัสของคุณทำไม่ได้คาดหวัง
ข้อยกเว้นควรจะได้รับการยกเว้น กลับ null ถ้ามันถูกต้องที่จะกลับโมฆะ
หากวิธีการส่งกลับคอลเลกชันแล้วส่งกลับคอลเลกชันที่ว่างเปล่า (เช่นที่กล่าวข้างต้น) แต่โปรดอย่า Collections.EMPTY_LIST หรือเช่นนั้น! (ในกรณีของ Java)
หากวิธีการ retrives วัตถุเดียวแล้วคุณมีตัวเลือกบางอย่าง
ระวังถ้าคุณตัดสินใจคืนค่าว่าง หากคุณไม่ได้เป็นโปรแกรมเมอร์คนเดียวในโครงการคุณจะได้รับ NullPointerExceptions (ใน Java หรือภาษาอื่น ๆ ) ในเวลาทำงาน! ดังนั้นอย่าส่งคืนค่า Null ซึ่งไม่ได้ตรวจสอบ ณ เวลารวบรวม
null
ไม่ได้ถ้ารหัสถูกเขียนอย่างถูกต้องที่จะคาดหวัง ดูคำตอบที่ได้รับการโหวตมากที่สุด
หากคุณกำลังใช้ห้องสมุดหรือระดับที่พ่นยกเว้นอื่นคุณควรrethrowมัน นี่คือตัวอย่าง Example2.java เป็นเหมือนห้องสมุดและ Example.java ใช้เป็นวัตถุ Main.java เป็นตัวอย่างในการจัดการข้อยกเว้นนี้ คุณควรแสดงข้อความที่มีความหมายและ (ถ้าจำเป็น) การติดตามสแต็กกับผู้ใช้ในด้านการโทร
Main.java
public class Main {
public static void main(String[] args) {
Example example = new Example();
try {
Example2 obj = example.doExample();
if(obj == null){
System.out.println("Hey object is null!");
}
} catch (Exception e) {
System.out.println("Congratulations, you caught the exception!");
System.out.println("Here is stack trace:");
e.printStackTrace();
}
}
}
Example.java
/**
* Example.java
* @author Seval
* @date 10/22/2014
*/
public class Example {
/**
* Returns Example2 object
* If there is no Example2 object, throws exception
*
* @return obj Example2
* @throws Exception
*/
public Example2 doExample() throws Exception {
try {
// Get the object
Example2 obj = new Example2();
return obj;
} catch (Exception e) {
// Log the exception and rethrow
// Log.logException(e);
throw e;
}
}
}
Example2.java
/**
* Example2.java
* @author Seval
*
*/
public class Example2 {
/**
* Constructor of Example2
* @throws Exception
*/
public Example2() throws Exception{
throw new Exception("Please set the \"obj\"");
}
}
ขึ้นอยู่กับว่าคุณคาดหวังว่าจะพบวัตถุหรือไม่ หากคุณทำตามโรงเรียนที่คิดว่าควรใช้ข้อยกเว้นเพื่อระบุบางสิ่งบางอย่างเอ่อไม่เป็นพิเศษเกิดขึ้นแล้ว:
มิฉะนั้นส่งคืน null