โซลูชัน True-way ใน Java: แยกวิเคราะห์ตัวเลข 2 ตัวจาก 2 สตริงแล้วส่งคืนผลรวม


84

ค่อนข้างเป็นคำถามโง่ ๆ ให้รหัส:

public static int sum(String a, String b) /* throws? WHAT? */ {
  int x = Integer.parseInt(a); // throws NumberFormatException
  int y = Integer.parseInt(b); // throws NumberFormatException
  return x + y;
}

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

ใครช่วยชี้แจงได้ไหมว่า:

  1. ฉันควรระบุNumberFormatExceptionเป็นส่วนหนึ่งของลายเซ็นของเมธอด
  2. ฉันควรกำหนดข้อยกเว้นการตรวจสอบของตัวเอง ( BadDataException) จับภายในวิธีการและอีกครั้งโยนมันเป็นNumberFormatExceptionBadDataException
  3. ฉันควรกำหนดข้อยกเว้นการตรวจสอบของฉันเอง ( BadDataException) ตรวจสอบความถูกต้องของสตริงทั้งสองด้วยวิธีใดวิธีหนึ่งเช่นนิพจน์ทั่วไปและโยนของฉันBadDataExceptionหากไม่ตรงกัน
  4. ความคิดของคุณ?

อัปเดต :

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

อัปเดต 2 :

มีบางความคิดเห็นบอกว่าของฉันsum(String, String)ออกแบบไม่ดี ฉันเห็นด้วยอย่างยิ่ง แต่สำหรับผู้ที่เชื่อว่าปัญหาดั้งเดิมจะไม่ปรากฏหากเรามีการออกแบบที่ดีคำถามเพิ่มเติมมีดังนี้:

นิยามปัญหาเป็นเช่นนี้คุณมีแหล่งข้อมูลที่จัดเก็บตัวเลขเป็นStrings แหล่งที่มานี้อาจเป็นไฟล์ XML หน้าเว็บหน้าต่างเดสก์ท็อปพร้อมช่องแก้ไข 2 ช่องอะไรก็ได้

เป้าหมายของคุณคือใช้ตรรกะที่ใช้ 2 Strings นี้แปลงเป็นints และแสดงกล่องข้อความว่า "ผลรวมเท่ากับ xxx"

ไม่ว่าคุณจะใช้แนวทางใดในการออกแบบ / ใช้งานสิ่งนี้คุณจะมีฟังก์ชันภายใน 2 จุดเหล่านี้ :

  1. สถานที่ที่คุณแปลงStringเป็นint
  2. สถานที่ที่คุณเพิ่ม 2 intวินาที

คำถามหลักของโพสต์เดิมของฉันคือ:

Integer.parseInt()คาดว่าถูกต้องสตริงที่จะผ่าน เมื่อใดก็ตามที่คุณส่งสตริงที่ไม่ถูกต้องหมายความว่าโปรแกรมของคุณไม่ถูกต้อง (ไม่ใช่ " ผู้ใช้ของคุณงี่เง่า") คุณจำเป็นต้องใช้ชิ้นส่วนของรหัสที่อยู่ในมือคนที่คุณมี Integer.parseInt () มีความหมายต้องและในมืออื่น ๆ ที่คุณจะต้องมีการตกลงกับกรณีเมื่อป้อนข้อมูลไม่ถูกต้อง - ความหมายควร

ดังนั้นโดยย่อ: ฉันจะใช้ความหมายได้อย่างไรหากฉันต้องมีไลบรารีเท่านั้น


13
นั่นไม่ใช่คำถามโง่ ๆ จริงๆแล้วมันดีทีเดียว! ฉันไม่แน่ใจว่าฉันจะเลือกตัวเลือกใดดี
martin

1
สำหรับการอัปเดตของคุณ: ใช่ตามหลักการล้มเหลวอย่างรวดเร็วสิ่งนี้ไม่จำเป็นต้องเป็นเรื่องเลวร้าย
Johan Sjöberg

1
ฉันเห็นด้วยกับมาร์ติน เป็นหนึ่งในแง่มุมของการเขียนโปรแกรม Java ซึ่งเข้าใจน้อยที่สุดซึ่งต้องใช้แนวทางปฏิบัติที่ดีที่สุด สิ่งนี้สามารถเห็นได้จากการไม่มีหน้าในเรื่องโดยมีเพียงไม่กี่หน้านอกจาก O'Reilly ที่พูดว่า "นี่คือวิธีที่ควรทำ"
James P.

2
อันที่จริงนี่เป็นคำถามที่ยอดเยี่ยม
Chris Cudmore

1
คำถามดีมาก! นอกจากนี้ยังมีคำตอบที่ยอดเยี่ยมอีกด้วย: D
Kheldar

คำตอบ:


35

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

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

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

เกี่ยวกับการประกาศ throws NumberFormatException - สิ่งนี้ไม่มีประโยชน์เพราะมีน้อยคนที่จะสังเกตเห็นเนื่องจากไม่มีการเลือก NumberFormatException อย่างไรก็ตาม IDE สามารถใช้ประโยชน์ได้และเสนอให้ห่อtry/catchอย่างถูกต้อง ตัวเลือกที่ดีคือใช้ javadoc ด้วยเช่น:

/**
 * Adds two string numbers
 * @param a
 * @param b
 * @return
 * @throws NumberFormatException if either of a or b is not an integer
 */
public static int sum(String a, String b) throws NumberFormatException {
    int x = Integer.parseInt(a); 
    int y = Integer.parseInt(b); 
    return x + y;
}

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

หากจะใช้วิธีนี้ทั่วทุกที่และสิ่งสำคัญคือผู้โทรทุกคนต้องจัดการกับปัญหาให้ประกาศวิธีนี้เป็นการทิ้งข้อยกเว้นที่ตรวจสอบแล้ว (บังคับให้ผู้โทรจัดการกับปัญหา) แต่ทำให้โค้ดยุ่งเหยิงด้วยtry/catchบล็อก

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


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

1
@G_H มีประเด็น บทช่วยสอน Java กล่าวว่า: "หากลูกค้าคาดว่าจะกู้คืนจากข้อยกเว้นได้อย่างสมเหตุสมผลให้ทำให้เป็นข้อยกเว้นที่ตรวจสอบแล้วหากไคลเอนต์ไม่สามารถดำเนินการใด ๆ เพื่อกู้คืนจากข้อยกเว้นให้ทำให้เป็นข้อยกเว้นที่ไม่เลือก" คำถามคือควรRuntimeExceptionจัดการที่ไหน? ควรเป็นผู้เรียกหรือควรปล่อยให้ Exception ลอยขึ้น? ถ้าเป็นเช่นนั้นควรจัดการอย่างไร?
James P.

1
ในการตอบคำถามนี้บางส่วนมีสองวิธีที่ฉันเคยเห็น: วิธีแรกคือการสกัดกั้นExceptionsจากเลเยอร์ที่ต่ำกว่าและรวมไว้ในข้อยกเว้นระดับที่สูงขึ้นซึ่งมีความหมายมากกว่าสำหรับผู้ใช้ปลายทางและวิธีที่สองคือการใช้ตัวจัดการข้อยกเว้นที่ไม่ถูกจับซึ่งสามารถเริ่มต้นได้ใน ตัวเรียกใช้แอปพลิเคชัน
James P.

2
IMHO มี NumberFormatException ใน javadoc ที่มีมากสำคัญมากขึ้น การใส่ไว้ในthrowsประโยคเป็นการเพิ่มที่ดี แต่ไม่จำเป็น
Dorus

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

49

ในความคิดของฉันควรจัดการตรรกะข้อยกเว้นให้มากที่สุด ดังนั้นฉันต้องการลายเซ็น

 public static int sum(int a, int b);

ด้วยลายเซ็นวิธีของคุณฉันจะไม่เปลี่ยนแปลงอะไร ไม่ว่าคุณจะเป็น

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

ดังนั้นการจัดการข้อยกเว้นในกรณีนี้จึงกลายเป็นปัญหาด้านเอกสาร


4
ฉันชอบสิ่งนี้. มันบังคับให้ผู้ใช้ทำตามสัญญาและทำให้วิธีการทำเพียงสิ่งเดียว
Chris Cudmore

ฉันไม่เข้าใจว่าการใช้วิธีนี้แตกต่างจากผู้ใช้ที่ทำ a + b อย่างไร ทำไมเราต้องใช้วิธีนี้?
Swati

4
@Swati: ฉันคิดว่ามันเป็นตัวอย่างซึ่งเป็นเทคนิคที่ดีในการแสดงสิ่งต่างๆอย่างเรียบง่าย วิธี sum อาจเป็น myVeryComplicatedMethodWhichComputesPhoneNumberOfMyIdealMatchGirl (int myID, int myLifeExpectancy) ...
Kheldar

3
เห็นด้วยอย่างยิ่งที่นี่ sumฟังก์ชั่นที่คาดว่าตัวเลขสองควรจะได้รับสองหมายเลข วิธีที่คุณได้รับนั้นไม่เกี่ยวข้องกับsumฟังก์ชัน เฉพาะกิจตรรกะของคุณได้อย่างถูกต้อง ฉันจะเชื่อมโยงสิ่งนี้กับปัญหาการออกแบบ
c00kiemon5ter

5

หมายเลข 4 ตามที่กำหนดวิธีนี้ไม่ควรใช้สตริงเป็นพารามิเตอร์ควรใช้จำนวนเต็ม ในกรณีนี้ (เนื่องจาก java ห่อแทนที่จะล้น) จึงไม่มีข้อยกเว้น

 x = sum(Integer.parseInt(a), Integer.parseInt(b))

มีความชัดเจนมากว่าหมายถึงอะไร x = sum(a, b)

คุณต้องการให้ข้อยกเว้นเกิดขึ้นใกล้เคียงกับแหล่งที่มา (อินพุต) มากที่สุด

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

อัปเดตเพื่อตอบสนองต่อการอัปเดตคำถาม:

ดังนั้นโดยย่อ: ฉันจะใช้ความหมายได้อย่างไรถ้าฉันมีเฉพาะไลบรารีเท่านั้น

วิธีแก้ปัญหานี้คือการรวมไลบรารี MUST และส่งคืนค่าควร ในกรณีนี้ฟังก์ชันที่ส่งคืนจำนวนเต็ม เขียนฟังก์ชันที่รับสตริงและส่งคืนอ็อบเจ็กต์จำนวนเต็มไม่ว่าจะใช้งานได้หรือส่งคืนค่า null (เช่น Ints.tryParse ของฝรั่ง) ทำการตรวจสอบความถูกต้องของคุณแยกจากการดำเนินการของคุณการดำเนินการของคุณควรใช้ ints ไม่ว่าการดำเนินการของคุณจะถูกเรียกด้วยค่าเริ่มต้นเมื่อคุณมีข้อมูลที่ป้อนไม่ถูกต้องหรือคุณทำอย่างอื่นจะขึ้นอยู่กับข้อกำหนดของคุณ - ส่วนใหญ่ที่ฉันสามารถพูดได้คือมันไม่น่าเป็นไปได้จริงๆที่สถานที่ในการตัดสินใจนั้นอยู่ในการดำเนินการ วิธี.


คุณมีความคิดอย่างไรที่นี่? ฉันจะได้รับปัญหาเดียวกันแม้ว่าฉันมีและsum(int, int) parseIntFromString(String)เพื่อให้ได้ฟังก์ชันเดียวกันไม่ว่าในกรณีใดฉันจะต้องเขียนโค้ดที่มีการโทร 2 ครั้งparseIntFromString()และการโทร 1 sum()ครั้ง ลองพิจารณากรณีนี้ถ้ามันสมเหตุสมผลสำหรับคุณ - ฉันไม่เห็นความแตกต่างจากมุมมองของปัญหาเดิม
Andrey Agibalov

@ loki2302: ประเด็นคือผู้โทรจะต้องตัดสินใจว่าพฤติกรรมใดเหมาะสมเมื่อไม่ใช่ตัวเลข นอกจากนี้หากพวกเขาไม่ทำการตรวจสอบข้อผิดพลาดความล้มเหลวจะเกิดขึ้นใกล้กับจุดที่กำหนดค่ามากขึ้นอีกหนึ่งขั้น - สำหรับวัตถุประสงค์ในการดีบักยิ่งใกล้กับงานที่มอบหมายมากเท่าไหร่การดีบักก็จะง่ายขึ้นเท่านั้น และคุณมีแนวโน้มที่จะพลาดการเขียนการทดสอบหน่วยที่เหมาะสมสำหรับผู้โทรหากคุณกำลังทำ TDD โดยทั่วไปคุณไม่ต้องการให้มีสตริงที่ให้มาใน method x ซึ่งควรจะเป็นตัวเลขจากนั้น 5 คลาสและ 20 เมธอดที่เรียกใช้ภายหลังจะถือเป็นข้อยกเว้นเมื่อคุณพยายามจัดการกับตัวเลข
jmoreno

ฉันไม่เข้าใจ คุณกำลังพยายามบอกว่าการจัดหาอินเทอร์เฟซint sum(String, String)นั้นไม่มีทางเป็นไปได้ในความเป็นจริงใช่หรือไม่?
Andrey Agibalov

1
@ loki2302: หากระบุรหัสที่แสดงไว้อาจเป็นไปได้ แต่เป็นความคิดที่ไม่ดี หากตัวเลขในสตริงอาจเป็นคำที่ "2", "สอง", "dos", "deux", "zwo" ทั้งหมดจะได้รับการปฏิบัติเหมือนกันดังนั้นลายเซ็นนั้นก็จะเหมาะสม แต่ตามที่เป็นอยู่วิธีนี้จะได้รับสองสตริงและถือว่าเป็นจำนวนเต็ม ทำไมคุณถึงอยากทำเช่นนั้น? เป็นความคิดที่ไม่ดีเลย
jmoreno

2
@ loki2302: คุณยอมรับคำตอบว่าเป็นเรื่องปกติที่จะทิ้งข้อยกเว้นที่ไม่ได้ตรวจสอบเมื่อส่งขยะไป แต่จุดสำคัญของภาษาที่พิมพ์อย่างรุนแรงคือการป้องกันไม่ให้ขยะถูกส่งผ่าน การมีเมธอดที่คาดว่าสตริงจะเป็นค่าจำนวนเต็มเสมอเป็นเพียงการถามปัญหา แม้แต่ Integer.parseInt ก็ไม่ได้จัดการกับสิ่งนั้น (ข้อยกเว้นในสิ่งที่ควรคาดหวังว่าอินพุตไม่ดีจำนวนเต็มของ. Net วิธีการ TryParse นั้นดีกว่ามากแม้ว่าการไม่มีพารามิเตอร์ out ของ Java ทำให้มันค่อนข้างใช้งานไม่ได้)
jmoreno

3

1. ฉันควรระบุ NumberFormatException เป็นส่วนหนึ่งของลายเซ็นของเมธอด

ฉันคิดอย่างนั้น เป็นเอกสารที่ดี

2. ฉันควรกำหนดข้อยกเว้นที่ตรวจสอบของฉันเอง (BadDataException) จัดการ NumberFormatException ภายในวิธีการและโยนใหม่เป็น BadDataException

บางครั้งใช่. ข้อยกเว้นที่ตรวจสอบแล้วถือว่าดีกว่าในบางกรณี แต่การทำงานกับข้อยกเว้นนั้นค่อนข้างเป็น PITA นั่นเป็นเหตุผลที่หลายเฟรมเวิร์ก (เช่นไฮเบอร์เนต) ใช้ข้อยกเว้นรันไทม์เท่านั้น

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

ไม่เลย ทำงานได้มากขึ้นความเร็วน้อยลง (เว้นแต่คุณจะคาดหวังว่าข้อยกเว้นจะเป็นกฎ) และไม่ได้รับผลตอบแทนเลย

4. ความคิดของคุณ?

ไม่มีเลย


2

หมายเลข 4.

ฉันคิดว่าฉันจะไม่เปลี่ยนวิธีการเลย ฉันจะลองใช้วิธีการโทรหรือสูงกว่าใน stack-trace ซึ่งฉันอยู่ในบริบทที่ฉันสามารถกู้คืนได้อย่างสง่างามด้วยตรรกะทางธุรกิจจากข้อยกเว้น

ฉันจะไม่ทำ # 3 อย่างแน่นอนเพราะฉันคิดว่ามันมากเกินไป


2

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


2
  1. ก่อนอื่นคุณต้องถามตัวเองก่อนผู้ใช้วิธีของฉันต้องกังวลเกี่ยวกับการป้อนข้อมูลผิดหรือคาดว่าเขาจะป้อนข้อมูลที่เหมาะสม (ในกรณีนี้คือ String) ความคาดหวังนี้เป็นที่รู้ว่าเป็นการออกแบบโดยการทำสัญญา

  2. และ 3. ใช่คุณควรกำหนด BadDataException หรือดีกว่าใช้สิ่งที่น่าตื่นเต้นบางอย่างเช่น NumberFormatException แต่ควรจะแสดงข้อความมาตรฐาน จับ NumberFormatException ในวิธีการและโยนใหม่พร้อมกับข้อความของคุณโดยไม่ลืมที่จะรวมการติดตามสแต็กดั้งเดิม

  3. ขึ้นอยู่กับสถานการณ์ bu ที่ฉันอาจจะไปกับ NumberFormatException ซ้ำพร้อมข้อมูลเพิ่มเติมบางอย่าง และจะต้องมีคำอธิบาย javadoc ว่าค่าที่คาดหวังคืออะไรString a, String b


1

ขึ้นอยู่กับสถานการณ์ที่คุณอยู่

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

โยน NumberFormatException เริ่มต้น

กรณีที่ 2: รหัสควรได้รับการบำรุงรักษาและเข้าใจได้อย่างดีเยี่ยม

กำหนดข้อยกเว้นของคุณเองและเพิ่มข้อมูลสำหรับการดีบักในขณะที่โยนทิ้ง

คุณไม่จำเป็นต้องตรวจสอบ regex เนื่องจากมันจะไปข้อยกเว้นสำหรับอินพุตที่ไม่ถูกต้องอยู่ดี

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

  1. ข้อยกเว้นรูปแบบตัวเลข
  2. ข้อยกเว้นล้น
  3. ข้อยกเว้น Null ฯลฯ ...

และจัดการกับสิ่งเหล่านี้แยกกัน


1
  1. คุณสามารถทำได้เพื่อให้ชัดเจนว่าสิ่งนี้อาจเกิดขึ้นเนื่องจากการป้อนข้อมูลที่ไม่ถูกต้อง อาจช่วยให้ใครบางคนที่ใช้รหัสของคุณจำการจัดการสถานการณ์นี้ได้ โดยเฉพาะอย่างยิ่งคุณกำลังทำให้ชัดเจนว่าคุณไม่ได้จัดการกับโค้ดด้วยตัวเองหรือส่งคืนค่าเฉพาะบางอย่างแทน แน่นอน JavaDoc ควรทำให้ชัดเจนเช่นกัน
  2. เฉพาะในกรณีที่คุณต้องการบังคับให้ผู้โทรจัดการกับข้อยกเว้นที่ตรวจสอบแล้ว
  3. ดูเหมือนว่า overkill ใช้การแยกวิเคราะห์เพื่อตรวจจับอินพุตที่ไม่ถูกต้อง

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


1

ควรมีการชี้แจงพฤติกรรมพิเศษใด ๆ ในเอกสารประกอบ ควรระบุว่าวิธีนี้จะส่งคืนค่าพิเศษในกรณีที่เกิดความล้มเหลว (เช่นnullโดยการเปลี่ยนประเภทการส่งคืนเป็นInteger) หรือกรณีที่ 1 ควรใช้ การระบุไว้อย่างชัดเจนในลายเซ็นของวิธีการทำให้ผู้ใช้สามารถเพิกเฉยได้หากมั่นใจว่าสตริงถูกต้องด้วยวิธีการอื่น แต่ก็ยังเห็นได้ชัดว่าวิธีนี้ไม่สามารถจัดการกับความล้มเหลวประเภทนี้ได้ด้วยตัวเอง


1

ตอบคำถามที่อัปเดตของคุณ

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

e.g ArrayIndexOutofBound

นอกจากนี้ข้อยกเว้นที่น่าแปลกใจทั่วไปสำหรับแต่ละลูป

ConcurrentModificationException or something like that

1

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

เกี่ยวกับการอัปเดตคำถาม "ลองนึกภาพมันไม่ใช่กรอบงานโอเพนซอร์สที่คุณควรใช้ด้วยเหตุผลบางประการคุณดูลายเซ็นของวิธีการและคิดว่า -" ตกลงมันไม่เคยพ่น "จากนั้นวันหนึ่งคุณได้รับข้อยกเว้น . ปกติมั้ย?” javadoc ของวิธีการของคุณควรกระจายพฤติกรรมของวิธีการของคุณเสมอ (ข้อ จำกัด ทั้งก่อนและหลัง) ลองนึกถึงบรรทัดของอินเทอร์เฟซการรวบรวมคำพูดโดยที่ถ้าไม่อนุญาตให้ใช้โมฆะ javadoc จะบอกว่าข้อยกเว้นของตัวชี้ว่างจะถูกโยนทิ้งแม้ว่าจะไม่ได้เป็นส่วนหนึ่งของลายเซ็นของวิธีการ


2
NumberFormatException เป็นคลาสย่อยของ IllegalArgumentException ดังนั้นการตัดนี้จึงไม่เพิ่มข้อมูล
Don Roby

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

1

ในขณะที่คุณกำลังพูดถึงการฝึกฝน java ที่ดีในความคิดของฉันมันดีกว่าเสมอ

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

  • นอกจากนี้ในขณะที่ทิ้งข้อยกเว้นที่ไม่ได้ทำเครื่องหมายที่กำหนดเองคุณสามารถเพิ่มข้อความ Exception ที่ไคลเอนต์ของคุณเข้าใจได้และพิมพ์การติดตามสแต็กของข้อยกเว้นดั้งเดิม

  • ไม่จำเป็นต้องประกาศข้อยกเว้นที่กำหนดเองเป็น "พ่น" เนื่องจากไม่ได้เลือกไว้

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

  • นอกจากนี้การจัดทำเอกสารอย่างถูกต้องใน java-doc ก็เป็นแนวทางปฏิบัติที่ดีและช่วยได้มาก


1

ฉันคิดว่ามันขึ้นอยู่กับวัตถุประสงค์ของคุณ แต่ฉันจะจัดทำเอกสารอย่างน้อยที่สุด:

/**
 * @return the sum (as an int) of the two strings
 * @throws NumberFormatException if either string can't be converted to an Integer
 */
public static int sum(String a, String b)
  int x = Integer.parseInt(a);
  int y = Integer.parseInt(b);
  return x + y;
}

หรือนำหน้าจากซอร์สโค้ด Java สำหรับคลาส java.lang.Integer:

public static int parseInt(java.lang.String string) throws java.lang.NumberFormatException;

1

รูปแบบการตรวจสอบอินพุตที่ใช้โดยไลบรารี 'Guava' ของ Googleหรือไลบรารี'Validator' ของ Apache ( การเปรียบเทียบ ) เป็นอย่างไร?

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

นอกจากนี้ฉันคิดว่าคำถามนี้ส่วนใหญ่ไม่ขึ้นกับภาษา 'แนวปฏิบัติที่ดี' ในที่นี้จะนำไปใช้กับทุกภาษาที่มีฟังก์ชันซึ่งสามารถใช้พารามิเตอร์ซึ่งอาจถูกต้องหรือไม่ก็ได้


1

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

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

  1. ตั้งค่าข้อความแสดงข้อผิดพลาดและหยุดการประมวลผลหรือเปลี่ยนเส้นทางไปยังหน้าข้อผิดพลาด
  2. ส่งคืนเท็จ (กล่าวคือจะใส่ผลรวมลงในวัตถุอื่นและไม่จำเป็นต้องส่งคืน)
  3. โยน BadDataException บางส่วนตามที่คุณกำลังแนะนำ แต่เว้นแต่การรวมของตัวเลขทั้งสองนี้มีความสำคัญมากนี่เป็นการใช้งานมากเกินไปและอย่างที่กล่าวไว้ข้างต้นนี่อาจเป็นการออกแบบที่ไม่ดีเนื่องจากแสดงว่าการแปลงกำลังเกิดขึ้นผิดที่

1

มีคำตอบที่น่าสนใจมากมายสำหรับคำถามนี้ แต่ฉันยังต้องการเพิ่มสิ่งนี้:

สำหรับการแยกวิเคราะห์สตริงฉันมักจะชอบใช้ "นิพจน์ทั่วไป" แพ็คเกจ java.util.regex พร้อมให้ความช่วยเหลือเรา ดังนั้นฉันจะจบลงด้วยสิ่งนี้ที่ไม่เคยมีข้อยกเว้นใด ๆ ขึ้นอยู่กับฉันที่จะส่งคืนค่าพิเศษหากฉันต้องการตรวจจับข้อผิดพลาด:

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public static int sum(String a, String b) {
  final String REGEX = "\\d"; // a single digit
  Pattern pattern = Pattern.compile(REGEX);
  Matcher matcher = pattern.matcher(a);
  if (matcher.find()) { x = Integer.matcher.group(); }
  Matcher matcher = pattern.matcher(b);
  if (matcher.find()) { y = Integer.matcher.group(); }
  return x + y;
}

อย่างที่เห็นรหัสยาวขึ้นเล็กน้อย แต่เราสามารถจัดการกับสิ่งที่เราต้องการได้ (และตั้งค่าเริ่มต้นสำหรับ x และ y ควบคุมสิ่งที่เกิดขึ้นกับส่วนคำสั่งอื่น ฯลฯ ... ) เรายังสามารถเขียนการแปลงทั่วไปได้มากขึ้น รูทีนซึ่งเราสามารถส่งผ่านสตริง, defaut return values, REGEX code to compile, error message to throw, ...

หวังว่ามันจะมีประโยชน์

คำเตือน: ฉันไม่สามารถทดสอบโค้ดนี้ได้ดังนั้นโปรดแก้ปัญหาไวยากรณ์ในที่สุด


1
เรากำลังพูดถึง Java หรือเปล่า? คืออะไรInteger.matcher? privateวิธีการตัวแปรภายใน? ที่ขาดหายไป()สำหรับไอเอฟเอจำนวนมากหายไป;, x, yไม่ได้ประกาศ, matcherประกาศเป็นครั้งที่สอง ...
user85421

ที่จริงคาร์ลอสฉันรีบและอย่างที่บอกว่าไม่สามารถทดสอบได้ในทันที ขออภัย. ฉันต้องการแสดงวิธีการทำ regex
Louis

ตกลง แต่สิ่งนี้ไม่สามารถแก้ปัญหาด้วย NumberFormatException - คำถามหลัก IMO - (สมมติว่าInteger.matcher.group()ควรจะเป็นInteger.parseInt(matcher.group()))
user85421

0

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

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

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

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