การขว้างและจับข้อยกเว้นในฟังก์ชั่น / วิธีการเดียวกัน


10

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

ฉันสงสัยว่านักพัฒนาคนอื่นคิดอย่างไรกับเรื่องนี้ ฉันอาจใช้ข้อยกเว้นในทางที่ผิดในฟังก์ชั่น นี่คือรหัสใน Java:

private static int sideInput()
{
    int side = 0;
    String input;
    Scanner scanner = new Scanner(System.in);

    do {
        System.out.print("Side length: ");
        input = scanner.nextLine();
        try {
            side = Integer.parseInt(input);
            if (side <= 0) {
                // probably a misuse of exceptions
                throw new NumberFormatException();
            }
        }
        catch (NumberFormatException numFormExc) {
            System.out.println("Invalid input. Enter a natural number.");
        }
    } while (side <= 0);

    return side;
}

ฉันสนใจสองสิ่ง:

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

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


ขึ้นอยู่กับภาษา บางภาษาใช้ข้อยกเว้นได้อย่างอิสระมากกว่าภาษาอื่น ๆ
มาร์ตินนิวยอร์ก

คำตอบ:


11

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

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


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

1
@usr: คำตอบนั้นขึ้นอยู่กับว่าระบบส่วนที่เหลือจะทำงานร่วมกันอย่างไร ข้อยกเว้นจำเป็นต้องได้รับการจัดการในบางจุด มีหลายวิธีที่คุณสามารถจัดระเบียบได้และนี่คือหนึ่งในนั้น สิ่งที่ดีที่สุดขึ้นอยู่กับข้อมูลอื่น ๆ ที่เราไม่มีที่นี่
unholysampler

4

นี่เป็นการใช้ข้อยกเว้นที่ไม่ดี ในการเริ่มต้นด้วยหมายเลขที่ไม่ใช่บวกไม่ใช่ข้อยกเว้นรูปแบบ

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

while (true)
{
   // Get user input.
   String input = scanner.nextLine();

   try
   {
      side = Integer.parseInt(input);

      break;
   }
   catch (NumberFormatException ex)
   {
      // Inform user of invalid input.
      System.out.println("Invalid input. Enter a natural number.");
   }
}

Integer.intParse ส่งข้อยกเว้นการจัดรูปแบบดังนั้นการใช้คำสั่ง catch จึงใช้ได้อย่างสมบูรณ์ ฉันต้องการทราบว่าการใช้คำสั่ง catch ในลูปในฟังก์ชั่นนั้นเป็นเรื่องปกติหรือไม่ฉันควรปล่อยให้ผู้เรียกใช้ของข้อยกเว้นรูปแบบการจัดการฟังก์ชัน
usr

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

ฉันได้แก้ไขตัวอย่างโค้ดเพื่อให้ชัดเจนยิ่งขึ้น
เบอร์นาร์ด

"และคุณจะไม่สามารถ) ยกเว้นตัวเอง" - คุณหมายถึงอะไรที่นั่น?
Michael Borgwardt

@Michael Borgwardt: ฉันหมายความว่าเนื่องจากInteger.parseInt()วิธีการจะยกเว้นสำหรับคุณถ้ามันเกิดขึ้นคุณจะไม่สามารถโยนมันด้วยตัวคุณเองหลังจากที่มันถูกโยนไปแล้ว
เบอร์นาร์ด

1

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

หนึ่งสามารถกำจัดลอง / จับที่นี่และเพียงเอกสารการเรียกวิธีการ:

//Throws NumberFormatException if read input is less than 0
private static int sideInput()

หนึ่งยังคงต้องจัดการข้อยกเว้นนั้นขึ้นสายโซ่ / กอง!


1
ข้อความมีไว้เพื่อ UI ที่ดีกว่าเท่านั้น จุดของฟังก์ชั่นคือมันจะกัดผู้ใช้สำหรับอินพุตจนกว่าเธอ / เขาจะเข้าอินพุตที่ถูกต้อง สิ่งนี้ไม่สามารถทำได้หากไม่มีการลองบล็อก คำถามของฉันคือถ้าจุดนั้นถูกต้อง ฉันคิดว่ามันเป็น แต่มีคนบอกฉันว่าฉันควรลบบล็อค try-catch และให้ผู้โทรจัดการข้อยกเว้นนี้โดยเฉพาะ แต่ฟังก์ชั่นจะไม่ทำงานตามที่ตั้งใจไว้
usr

1

คุณไม่ควรโยนและตรวจจับข้อยกเว้นเดียวกันในวิธีใดวิธีหนึ่งฉันยังคิดว่าบล็อกจับจะจับข้อยกเว้นเดียวกับที่คุณขว้างดังนั้นคุณจึงไม่ได้ขว้าง

หากประสบความสำเร็จแล้วก็ไม่ได้เป็นparseIntNumberFormatException

ถ้าด้านข้างมีค่าน้อยกว่าศูนย์คุณควรโยน a NegativeSideLengthException;

สร้างข้อยกเว้นแบบกำหนดเอง / ธุรกิจ NegativeSideLengthException

public class NegativeSideLengthException extends Exception
{


    public NegativeSideLengthException(Integer i)
    {
        super("Invalid negative side length "+i);        
    }

}

จากนั้นจึงsideInputขว้าง NegativeSideLengthException

private static int sideInput() throws NegativeSideLengthException
{
    int side = 0;
    String input;
    Scanner scanner = new Scanner(System.in);

    do {
        System.out.print("Side length: ");
        input = scanner.nextLine();
        try {
            side = Integer.parseInt(input);
            if (side <= 0) {
                throw new NegativeSideLengthException(side);
            }
        }
        catch (NumberFormatException numFormExc) {
            System.out.println("Invalid input. Enter a natural number.");
        }
    } while (side <= 0);

    return side;
}

คุณสามารถแม้กระทั่ง (ถ้าคุณต้องการ) เพิ่มบล็อก catch อื่นเพื่อจับNegativeSideLengthExceptionและไม่มีวิธีการโยน

do {
    System.out.print("Side length: ");
    input = scanner.nextLine();
    try {
        side = Integer.parseInt(input);
        if (side <= 0) {
            throw new NegativeSideLengthException(side);
        }
    }
    catch (NumberFormatException numFormExc) {
        System.out.println("Invalid input. Enter a natural number.");
    } catch (NegativeSideLengthException e){
        System.out.println("Invalid input. Enter a non-negative number.");
    }
} while (side <= 0);

การตั้งค่าสถานะไม่ใช่วิธีที่ดีในการจัดการข้อยกเว้น


-1

ข้อยกเว้นเป็นสิ่งที่น่าหวาดเสียวพวกเขานำความซับซ้อนมากกว่าที่พวกเขาแก้ปัญหา

ประการแรกหากคุณไม่ได้รับการยกเว้นผู้โทรสามารถทำได้on error resume nextนั่นคือหลังจากผ่านไปหนึ่งสัปดาห์คุณจะไม่ทราบว่าฟังก์ชันของคุณสามารถส่งสัญญาณอะไรได้บ้างและจะทำอย่างไรกับมัน:

{
    ...
}
catch(OutOfMemory, CorruptedMemory, BadData, DanglingPointers, UnfinishedCommit)
{
    Console.WriteLine("Nothing to see here, move on.");
    Console.WriteLine("The app is very stable, see, no crashing!");
}

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

นอกจากนี้สิ่งที่ตลกคือถ้าคุณมีโอกาสจัดการข้อยกเว้นใด ๆ คุณต้องใช้ภาษา RAII จริงซึ่งเป็นเรื่องตลกเนื่องจาก Java และ. NET เป็นข้อยกเว้น ...

ทำซ้ำอีกครั้ง แต่ ... :

http://blogs.msdn.com/b/oldnewthing/archive/2004/04/22/118161.aspx

http://blogs.msdn.com/b/oldnewthing/archive/2005/01/14/352949.aspx

http://www.joelonsoftware.com/items/2003/10/13.html


4
-1 สำหรับการโพสต์การพูดจาโผงผางตามแนวชายแดนเต็มไปด้วยความไม่ถูกต้อง - หรืออย่างน้อยต้องขึ้นอยู่กับบริบท / ภาษา - คำสั่งแทนที่จะตอบคำถามที่แท้จริง
PéterTörök

@ PéterTörök: "ให้ปลาแก่คุณและให้อาหารเขาหนึ่งวันสอนให้คนจับปลาและให้อาหารเขาตลอดชีวิต" มีปัญหาร้ายแรงมากที่อยู่เบื้องหลังข้อยกเว้นและผู้คนควรรู้จัก -1000 / + 1 ฉันไม่สนใจจริงๆ
Coder

1
รู้สึกอิสระที่จะเชื่อว่าคุณสามารถเขียนรหัสที่ถูกต้องได้ง่ายขึ้นโดยไม่มีข้อยกเว้น เพียงแค่ไม่ระบุมุมมองและความเชื่อของคุณเป็นข้อเท็จจริง (แม้ว่า Joel มีความคิดเห็นแบบเดียวกัน แต่ก็ยังเป็นความคิดเห็นไม่ใช่ความจริง) และไม่โพสต์คำตอบที่ไม่เกี่ยวข้องลงใน SE
PéterTörök

@ PéterTörök: ไม่ใช่ความเห็นมันเป็นความจริงทุกครั้งที่คุณใช้ส่วนประกอบที่มีข้อยกเว้นภายในคุณต้องรวบรวมข้อมูลลำดับชั้นทั้งหมดและตรวจสอบรหัสทุกบรรทัดเพื่อรู้ว่าจะจับอะไรและถ้าส่วนประกอบมีความแข็งแกร่ง รับประกันและทุกอย่างจะถูกย้อนกลับหรือถ้าการจับนั้นเป็นเพียงความรู้สึกผิด ๆ ของความปลอดภัย Heck คุณไม่รู้จักข้อยกเว้นทั้งหมด std :: string throws คุณสามารถค้นหา specs แต่คุณจะไม่พบ สิ่งที่ชอบ: throw(thisexception, thatexception)อย่างไม่ถูกต้องและไม่ควรใช้เพราะมิฉะนั้นคุณจะได้รับยกเว้น
Coder

2
ตกลงดังนั้นวิธีการเกี่ยวกับรหัสไม่ใช้ข้อยกเว้น? ใช่คุณต้องคลานผ่านโค้ดเพื่อตรวจสอบทุกบรรทัดเดียวเพื่อดูว่าค่าส่งคืนได้รับการจัดการอย่างถูกต้องหรือไม่สนใจ และเมื่อค่าส่งคืนถูกละเว้นไม่มีใครสังเกตจนกระทั่งแอปของคุณอาจล่มสองพันบรรทัดในภายหลัง ข้อยกเว้นอย่างน้อยบังคับให้คุณต้องแจ้งให้ทราบล่วงหน้า ใช่คุณสามารถกลืนพวกเขา - catchแต่ด้วยความชัดเจน แม้ว่าค่าที่ส่งคืนจะถูกเพิกเฉยไม่สามารถค้นหาได้ แต่สามารถระบุได้ผ่านการตรวจสอบโค้ดแบบบรรทัดต่อบรรทัดเท่านั้น สุดท้าย แต่ไม่ท้ายสุดคอนสตรัคเตอร์ไม่มีค่าตอบแทนนี่คือเหตุผลที่สำคัญที่สุดสำหรับการใช้ข้อยกเว้น
PéterTörök
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.