การทิ้ง RuntimeExceptions ใหม่ในโค้ดที่ไม่สามารถเข้าถึงได้เป็นสไตล์ที่ไม่ดีหรือไม่?


31

ฉันได้รับมอบหมายให้ดูแลรักษาแอปพลิเคชันที่เขียนเมื่อไม่นานมานี้โดยนักพัฒนาที่มีทักษะมากกว่า ฉันเจอโค้ดนี้แล้ว:

public Configuration retrieveUserMailConfiguration(Long id) throws MailException {
        try {
            return translate(mailManagementService.retrieveUserMailConfiguration(id));
        } catch (Exception e) {
            rethrow(e);
        }
        throw new RuntimeException("cannot reach here");
    }

ฉันอยากรู้ว่าการขว้างปาRuntimeException("cannot reach here")นั้นมีเหตุผลหรือไม่ ฉันอาจจะพลาดสิ่งที่เห็นได้ชัดว่ารู้ว่าโค้ดนี้มาจากเพื่อนร่วมงานที่มีประสบการณ์มากกว่า
แก้ไข: นี่คือร่างใหม่ที่บางคำตอบเรียก ฉันถือว่ามันไม่สำคัญในคำถามนี้

private void rethrow(Exception e) throws MailException {
        if (e instanceof InvalidDataException) {
            InvalidDataException ex = (InvalidDataException) e;
            rethrow(ex);
        }
        if (e instanceof EntityAlreadyExistsException) {
            EntityAlreadyExistsException ex = (EntityAlreadyExistsException) e;
            rethrow(ex);
        }
        if (e instanceof EntityNotFoundException) {
            EntityNotFoundException ex = (EntityNotFoundException) e;
            rethrow(ex);
        }
        if (e instanceof NoPermissionException) {
            NoPermissionException ex = (NoPermissionException) e;
            rethrow(ex);
        }
        if (e instanceof ServiceUnavailableException) {
            ServiceUnavailableException ex = (ServiceUnavailableException) e;
            rethrow(ex);
        }
        LOG.error("internal error, original exception", e);
        throw new MailUnexpectedException();
    }


private void rethrow(ServiceUnavailableException e) throws
            MailServiceUnavailableException {
        throw new MailServiceUnavailableException();
    }

private void rethrow(NoPermissionException e) throws PersonNotAuthorizedException {
    throw new PersonNotAuthorizedException();
}

private void rethrow(InvalidDataException e) throws
        MailInvalidIdException, MailLoginNotAvailableException,
        MailInvalidLoginException, MailInvalidPasswordException,
        MailInvalidEmailException {
    switch (e.getDetail()) {
        case ID_INVALID:
            throw new MailInvalidIdException();
        case LOGIN_INVALID:
            throw new MailInvalidLoginException();
        case LOGIN_NOT_ALLOWED:
            throw new MailLoginNotAvailableException();
        case PASSWORD_INVALID:
            throw new MailInvalidPasswordException();
        case EMAIL_INVALID:
            throw new MailInvalidEmailException();
    }
}

private void rethrow(EntityAlreadyExistsException e)
        throws MailLoginNotAvailableException, MailEmailAddressAlreadyForwardedToException {
    switch (e.getDetail()) {
        case LOGIN_ALREADY_TAKEN:
            throw new MailLoginNotAvailableException();
        case EMAIL_ADDRESS_ALREADY_FORWARDED_TO:
            throw new MailEmailAddressAlreadyForwardedToException();
    }
}

private void rethrow(EntityNotFoundException e) throws
        MailAccountNotCreatedException,
        MailAliasNotCreatedException {
    switch (e.getDetail()) {
        case ACCOUNT_NOT_FOUND:
            throw new MailAccountNotCreatedException();
        case ALIAS_NOT_FOUND:
            throw new MailAliasNotCreatedException();
    }
}

12
มันสามารถเข้าถึงได้ทางเทคนิคหากrethrowล้มเหลวในthrowการยกเว้นจริง (ซึ่งอาจเกิดขึ้นในบางวันหากการดำเนินการเปลี่ยนแปลง)
njzk2

34
นอกเหนือจากนั้น AssertionError อาจเป็นทางเลือกที่ดีกว่า semantically RuntimeException
JvR

1
การโยนครั้งสุดท้ายซ้ำซ้อน หากคุณเปิดใช้งาน findbugs หรือเครื่องมือวิเคราะห์แบบคงที่อื่น ๆ มันจะทำเครื่องหมายบรรทัดประเภทเหล่านี้เพื่อนำออก
Bon Ami

7
ตอนนี้ฉันเห็นรหัสที่เหลือฉันคิดว่าบางทีคุณควรเปลี่ยน "นักพัฒนาที่มีทักษะมากขึ้น" เป็น " นักพัฒนาที่อาวุโสมากขึ้น" การตรวจสอบรหัสยินดีที่จะอธิบายว่าทำไม
JvR

3
ฉันพยายามสร้างตัวอย่างสมมุติว่าทำไมข้อยกเว้นถึงแย่มาก แต่ไม่มีอะไรที่ฉันเคยทำมาถือเทียนนี้
พอลเดรเปอร์

คำตอบ:


36

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

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

ข้อผิดพลาดคือค่า

(แปลกใจมันเป็นที่รู้จักกันดีในระหว่างการเดินทาง )

ลองใช้ตัวอย่างที่เรียบง่ายอย่างใดอย่างหนึ่งที่ผมใช้มาก่อนการแก้ไขของคุณจึงคิดว่าคุณมีการบันทึกบางสิ่งบางอย่างและการสร้างข้อยกเว้นเสื้อคลุมเหมือนในคำตอบของคอนราด logAndWrapขอเรียกว่า

แทนที่จะโยนข้อยกเว้นเป็นผลข้างเคียงของlogAndWrapคุณสามารถปล่อยให้มันทำงานเป็นผลข้างเคียงและทำให้มันส่งกลับข้อยกเว้น (อย่างน้อยก็เป็นหนึ่งในอินพุต) คุณไม่จำเป็นต้องใช้ยาสามัญเพียงฟังก์ชั่นพื้นฐาน:

private Exception logAndWrap(Exception exception) {
    // or whatever it actually does
    Log.e("Ouch! " + exception.getMessage());
    return new CustomWrapperException(exception);
}

จากนั้นคุณอธิบายthrowอย่างชัดเจนและผู้แปลมีความสุข:

try {
     return translate(mailManagementService.retrieveUserMailConfiguration(id));
} catch (Exception e) {
     throw logAndWrap(e);
}

เกิดอะไรขึ้นถ้าคุณลืมthrow?

ตามที่อธิบายไว้ในความคิดเห็น Joe23 ของการเขียนโปรแกรมการป้องกันวิธีการเพื่อให้มั่นใจว่าข้อยกเว้นจะโยนมักจะประกอบด้วยใน explicitely ทำthrow new CustomWrapperException(exception)ในตอนท้ายของlogAndWrapตามที่มันจะกระทำโดยGuava.Throwables ด้วยวิธีนี้คุณรู้ว่าข้อยกเว้นจะถูกโยนทิ้งและตัววิเคราะห์ชนิดของคุณมีความสุข อย่างไรก็ตามข้อยกเว้นที่กำหนดเองของคุณจำเป็นต้องถูกตรวจสอบข้อยกเว้นซึ่งเป็นไปไม่ได้เสมอไป นอกจากนี้ฉันจะให้คะแนนความเสี่ยงของนักพัฒนาซอฟต์แวร์ที่พลาดการเขียนthrowให้อยู่ในระดับต่ำมาก: ผู้พัฒนาต้องลืมและวิธีการโดยรอบไม่ควรส่งคืนสิ่งใด นี่เป็นวิธีที่น่าสนใจในการต่อสู้กับระบบการพิมพ์และใช้งานได้

rethrow

จริงrethrowสามารถเขียนเป็นฟังก์ชันด้วย แต่ฉันมีปัญหากับการใช้ปัจจุบัน:

  • มีวรรณะไร้ประโยชน์มากมายเช่น อันที่จริงมันเป็นสิ่งจำเป็น (ดูความคิดเห็น):

    if (e instanceof ServiceUnavailableException) {
        ServiceUnavailableException ex = (ServiceUnavailableException) e;
        rethrow(ex);
    }
  • เมื่อขว้าง / ส่งคืนข้อยกเว้นใหม่อันเก่าจะถูกยกเลิก ในรหัสต่อไปนี้ a MailLoginNotAvailableExceptionไม่อนุญาตให้ฉันรู้ว่าการเข้าสู่ระบบไม่พร้อมใช้งานซึ่งไม่สะดวก ยิ่งไปกว่านั้นการเรียงซ้อนกันจะไม่สมบูรณ์:

    private void rethrow(EntityAlreadyExistsException e)
        throws MailLoginNotAvailableException, MailEmailAddressAlreadyForwardedToException {
        switch (e.getDetail()) {
            case LOGIN_ALREADY_TAKEN:
                throw new MailLoginNotAvailableException();
            case EMAIL_ADDRESS_ALREADY_FORWARDED_TO:
                throw new MailEmailAddressAlreadyForwardedToException();
        }
    }
  • ทำไมรหัสต้นทางไม่ส่งข้อยกเว้นพิเศษเหล่านั้นตั้งแต่แรก? ฉันสงสัยว่าrethrowใช้เป็นเลเยอร์ความเข้ากันได้ระหว่างระบบย่อย (การส่งเมล) และตรรกะธุรกิจ (อาจเจตนาคือซ่อนรายละเอียดการใช้งานเช่นข้อยกเว้นที่ส่งออกโดยแทนที่ด้วยข้อยกเว้นแบบกำหนดเอง) แม้ว่าฉันจะเห็นด้วยว่าจะเป็นการดีกว่าถ้ามีรหัสที่ดักฟังตามคำแนะนำในคำตอบของ Pete Beckerฉันไม่คิดว่าคุณจะมีโอกาสลบcatchและrethrowรหัสที่นี่ได้โดยไม่ต้องทำการปรับเปลี่ยนครั้งใหญ่


1
การปลดเปลื้องไม่ได้ไร้ประโยชน์ จำเป็นต้องมีเนื่องจากไม่มีการแจกจ่ายแบบไดนามิกตามประเภทอาร์กิวเมนต์ ต้องระบุชนิดอาร์กิวเมนต์ในเวลารวบรวมเพื่อเรียกใช้วิธีการที่เหมาะสม
Joe23

ในของคุณlogAndWrapวิธีการที่คุณจะโยนข้อยกเว้นแทนที่จะกลับ (Runtime)Exceptionแต่ให้พิมพ์กลับ วิธีนี้ catch catch สามารถคงอยู่ในแบบที่คุณเขียนได้ (โดยไม่ต้องใส่รหัสที่ไม่สามารถเข้าถึงได้) แต่มีข้อได้เปรียบเพิ่มเติมที่คุณไม่สามารถลืมthrowได้ หากคุณส่งคืนข้อยกเว้นและลืมการโยนสิ่งนี้จะนำไปสู่ข้อยกเว้นที่ถูกกลืนอย่างเงียบ ๆ การขว้างปาในขณะที่มีประเภทรันไทม์ RuntimeException จะทำให้คอมไพเลอร์มีความสุขในขณะที่หลีกเลี่ยงข้อผิดพลาดเหล่านี้ นั่นคือวิธีการนำฝรั่งThrowables.propagateไปปฏิบัติ
Joe23

@ Joe23 ขอบคุณสำหรับการชี้แจงเกี่ยวกับการจัดส่งคงที่ เกี่ยวกับการโยนข้อยกเว้นภายในฟังก์ชั่น: คุณหมายถึงว่าข้อผิดพลาดที่เป็นไปได้ที่คุณกำลังอธิบายคือบล็อก catch ที่เรียกlogAndWrapแต่ไม่ทำอะไรเลยกับข้อยกเว้นที่ส่งคืน? นั่นดูน่าสนใจ. ภายในฟังก์ชั่นที่ต้องคืนค่าคอมไพเลอร์จะสังเกตเห็นว่ามีเส้นทางที่ไม่มีค่าที่จะถูกส่งคืน แต่สิ่งนี้มีประโยชน์สำหรับวิธีการที่ไม่ส่งคืนสิ่งใด ขอบคุณอีกครั้ง.
coredump

1
นั่นคือสิ่งที่ฉันพูด และเพื่อเน้นจุดอีกครั้ง: มันไม่ใช่สิ่งที่ฉันคิดขึ้นมาและให้เครดิต แต่ถูกรวบรวมจากแหล่งที่มาของฝรั่ง
Joe23

@ Joe23 ฉันเพิ่มการอ้างอิงที่ชัดเจนไปยังห้องสมุด
coredump

52

rethrow(e);ฟังก์ชั่นนี้ละเมิดหลักการที่ระบุว่าภายใต้สถานการณ์ปกติฟังก์ชั่นจะกลับมาในขณะที่ภายใต้สถานการณ์พิเศษฟังก์ชั่นจะโยนข้อยกเว้น ฟังก์ชั่นนี้ละเมิดหลักการนี้โดยการโยนข้อยกเว้นภายใต้สถานการณ์ปกติ นั่นคือที่มาของความสับสนทั้งหมด

คอมไพเลอร์สันนิษฐานว่าฟังก์ชั่นนี้จะกลับมาภายใต้สถานการณ์ปกติดังนั้นเท่าที่คอมไพเลอร์สามารถบอกได้การดำเนินการอาจถึงจุดสิ้นสุดของretrieveUserMailConfigurationฟังก์ชั่น ณ จุดนี้มันเป็นข้อผิดพลาดที่จะไม่มีreturnคำสั่ง ผู้RuntimeExceptionขว้างมีควรที่จะบรรเทาความกังวลของคอมไพเลอร์นี้ แต่มันเป็นวิธีที่ค่อนข้าง clunky ในการทำมัน อีกวิธีในการป้องกันfunction must return a valueข้อผิดพลาดคือการเพิ่มreturn null; //to keep the compiler happyคำสั่ง

ดังนั้นโดยส่วนตัวฉันจะแทนที่สิ่งนี้:

rethrow(e);

ด้วยสิ่งนี้:

report(e); 
throw e;

หรือดีกว่ายัง (ตามที่แนะนำ coredump ) กับสิ่งนี้:

throw reportAndTransform(e);

ดังนั้นการไหลของการควบคุมจะทำให้ชัดเจนกับคอมไพเลอร์ดังนั้นสุดท้ายของคุณ throw new RuntimeException("cannot reach here");จะไม่เพียง แต่ซ้ำซ้อน แต่จริงๆแล้วไม่ได้คอมไพล์เพราะมันจะถูกตั้งค่าสถานะโดยคอมไพเลอร์เป็นรหัสที่ไม่สามารถเข้าถึงได้

นั่นเป็นวิธีที่ดีที่สุดและง่ายที่สุดในการออกจากสถานการณ์ที่น่าเกลียดนี้


1
-1 การแนะนำให้แบ่งฟังก์ชันออกเป็นสองประโยคอาจทำให้เกิดข้อผิดพลาดในการเขียนโปรแกรมเนื่องจากการคัดลอก / วางไม่ถูกต้อง นอกจากนี้ผมยังกังวลเล็กน้อยเกี่ยวกับความจริงที่คุณแก้ไขคำถามของคุณจะแนะนำไม่กี่นาทีหลังจากที่ผมโพสต์คำตอบของตัวเอง บางทีคุณอาจปรับเปลี่ยนคำถามของคุณอย่างเป็นอิสระและฉันต้องขออภัยล่วงหน้าหากเป็นเช่นนั้น แต่อย่างอื่นการให้เครดิตเล็กน้อยเป็นสิ่งที่คนทั่วไปมักจะทำ throw reportAndTransform(e)
coredump

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

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

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

2
ในขณะที่ภาษาสมัยใหม่จำนวนมากมีความซับซ้อนเพียงพอ การเปลี่ยนรูปแบบการออกแบบทุกอย่างให้กลายเป็นคุณสมบัติหลักภาษาจะขยายออกไปมากยิ่งขึ้น นี่เป็นตัวอย่างที่ดีของรูปแบบการออกแบบที่ไม่ได้อยู่ในภาษาแกนกลาง ตามที่เขียนไว้มันเข้าใจดีไม่เพียงแค่คอมไพเลอร์ แต่ยังมีเครื่องมืออื่น ๆ อีกมากมายที่ต้องแยกวิเคราะห์โค้ด
MSalters

7

throwอาจจะเพิ่มการรับรอบ "วิธีการจะต้องส่งคืนค่า" ความผิดพลาดที่อาจจะเกิดขึ้น - ข้อมูล Java ไหลวิเคราะห์เป็นพอสมาร์ทที่จะเข้าใจว่าไม่มีreturnความจำเป็นหลังจากที่throwแต่ไม่ได้หลังจากที่คุณกำหนดrethrow()วิธีการและไม่มี@NoReturnคำอธิบายประกอบ ที่คุณสามารถใช้เพื่อแก้ไขปัญหานี้

อย่างไรก็ตามการสร้างข้อยกเว้นใหม่ในโค้ดที่ไม่สามารถเข้าถึงได้ดูเหมือนว่าไม่จำเป็น ฉันจะเขียนเพียงreturn nullรู้ว่ามันเป็นจริงไม่เคยเกิดขึ้น


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

3
@SokPomaranczowy ใช่มันเป็นโปรแกรมที่ไม่ดี ว่าrethrow()วิธีการซ่อนความจริงที่ว่าcatchมีการ rethrowing ข้อยกเว้น ฉันจะหลีกเลี่ยงการทำอะไรแบบนั้น แน่นอนว่าrethrow()อาจล้มเหลวในการสร้างข้อยกเว้นขึ้นมาใหม่ซึ่งในกรณีนี้มีบางอย่างเกิดขึ้น
Ross Patterson

26
return nullกรุณาอย่าเปลี่ยนข้อยกเว้นด้วย ด้วยข้อยกเว้นหากบางคนในอนาคตแบ่งรหัสเพื่อให้บรรทัดสุดท้ายเป็นวิธีที่เข้าถึงได้ก็จะถูกล้างทันทีเมื่อข้อยกเว้นถูกโยน หากคุณแทนreturn nullตอนนี้คุณมีnullค่าที่ลอยไปมาในแอปพลิเคชันของคุณซึ่งไม่ได้คาดไว้ ใครจะรู้ได้ว่าในใบสมัครNullPointerExceptionจะเกิดอะไรขึ้น? นอกจากว่าคุณจะโชคดีและอยู่ตรงกลางหลังจากเรียกใช้ฟังก์ชั่นนี้มันจะยากมากที่จะติดตามปัญหาที่แท้จริง
unholysampler

5
@MatthewRead การเรียกใช้โค้ดที่ไม่สามารถเข้าถึงได้เป็นข้อบกพร่องที่ร้ายแรงreturn nullมีแนวโน้มที่จะปกปิดข้อผิดพลาดได้เนื่องจากคุณไม่สามารถแยกแยะกรณีอื่นที่ส่งคืนnullจากบั๊กนี้
CodesInChaos

4
นอกจากนี้หากฟังก์ชั่นส่งคืนค่า null ในบางสถานการณ์แล้วและคุณใช้การคืนค่าว่างในกรณีนี้ผู้ใช้จะมีสองสถานการณ์ที่เป็นไปได้ซึ่งอาจอยู่ในเมื่อได้รับคืนเป็นโมฆะ บางครั้งสิ่งนี้ไม่สำคัญเนื่องจากการคืนค่า Null หมายถึง "ไม่มีวัตถุแล้วและฉันไม่ได้ระบุสาเหตุ" ดังนั้นให้เพิ่มเหตุผลที่เป็นไปได้อีกประการหนึ่งว่าทำไมจึงสร้างความแตกต่างเล็กน้อย แต่บ่อยครั้งที่การเพิ่มความกำกวมนั้นไม่ดีและมันก็หมายความว่าบั๊กจะได้รับการปฏิบัติเหมือน "บางสถานการณ์" ในตอนแรกแทนที่จะมองทันทีว่า "นี่มันพัง" ล้มเหลว แต่เนิ่นๆ
Steve Jessop

6

The

throw new RuntimeException("cannot reach here");

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

อย่างไรก็ตามrethrow(e)ดูเหมือนผิด! ดังนั้นในกรณีของคุณฉันคิดว่าการเปลี่ยนรหัสเป็นตัวเลือกที่ดีกว่า ดูคำตอบอื่น ๆ (ฉันชอบที่สุดของ coredump) สำหรับวิธีจัดเรียงโค้ดของคุณ


4

ฉันไม่รู้ว่ามีการประชุมหรือไม่

อย่างไรก็ตามเคล็ดลับอื่นจะทำเช่นนั้น:

private <T> T rethrow(Exception exception) {
    // or whatever it actually does
    Log.e("Ouch! " + exception.getMessage());
    throw new CustomWrapperException(exception);
}

อนุญาตสำหรับสิ่งนี้:

try {
     return translate(mailManagementService.retrieveUserMailConfiguration(id));
} catch (Exception e) {
     return rethrow(e);
}

และไม่RuntimeExceptionจำเป็นต้องใช้สิ่งประดิษฐ์อีกต่อไป แม้ว่าจะrethrowไม่ได้คืนค่าใด ๆ แต่ก็ดีพอสำหรับคอมไพเลอร์แล้ว

มันส่งคืนค่าในทางทฤษฎี (วิธีการลงนาม) และจากนั้นก็จะได้รับการยกเว้นจากการทำเช่นนั้นเพราะมันจะโยนข้อยกเว้นแทน

ใช่มันอาจดูแปลก แต่แล้วอีกครั้ง - ขว้างปีศาจRuntimeExceptionหรือคืนโมฆะที่ไม่เคยเห็นในโลกนี้ - นั่นไม่ใช่เรื่องของความงาม

การดิ้นรนเพื่อความสามารถในการอ่านคุณสามารถเปลี่ยนชื่อrethrowและมีดังนี้:

} catch (Exception e) {
     return nothingJustRethrow(e);
}

2

หากคุณลบtryบล็อกสมบูรณ์แล้วคุณไม่จำเป็นต้องใช้หรือrethrow throwรหัสนี้ทำสิ่งเดียวกับของเดิม:

public Configuration retrieveUserMailConfiguration(Long id) throws MailException {
    return translate(mailManagementService.retrieveUserMailConfiguration(id));
}

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

แก้ไข: ฉันอ่านผิดrethrow(e)เพียงแค่โยนข้อยกเว้นอีกครั้งeอีกครั้ง หากrethrowวิธีการนั้นทำสิ่งอื่นที่ไม่ใช่การยกเว้นข้อผิดพลาดอีกครั้งการกำจัดมันจะเปลี่ยนซีแมนทิกส์ของวิธีการนี้


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

1
@msw - การเข้ารหัส Cargo - ลัทธิ
Pete Becker

@msw - ในทางกลับกันมันให้ที่สำหรับกำหนดจุดพัก
Pete Becker

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

1
@ jpmc26 คำถามหลักเกี่ยวกับข้อยกเว้น "ไม่สามารถเข้าถึงที่นี่" ซึ่งอาจเกิดขึ้นได้จากเหตุผลอื่นนอกเหนือจากบล็อก try / catch ก่อนหน้า แต่ฉันเห็นด้วยว่าบล็อกนั้นมีกลิ่นคาวและถ้าคำตอบนี้ถูกพูดอย่างระมัดระวังมากขึ้นในตอนแรกมันจะได้รับ upvotes มากขึ้น (ฉันไม่ได้ลงคะแนน btw) การแก้ไขครั้งสุดท้ายนั้นดี
coredump
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.