การจับข้อยกเว้นหลายข้อใน Java-8


71

ในขณะที่ลองใช้คุณสมบัติมัลติแคปฉันพบว่าm1()วิธีการของฉันทุกอย่างทำงานได้ดีอย่างที่คาดไว้

อย่างไรก็ตามในm2()รหัสเดียวกันไม่ได้รวบรวม ฉันเพิ่งเปลี่ยนไวยากรณ์เพื่อลดจำนวนบรรทัดของรหัส

public class Main {

    public int m1(boolean bool) {
        try {
            if (bool) {
                throw new Excep1();
            }
            throw new Excep2();
            //This m1() is compiling  abs fine.
        } catch (Excep1 | Excep2 e) {
            return 0;
        }
    }

    public int m2(boolean b) {
        try {
            throw b ? new Excep1() : new Excep2();
            //This one is not compiling.
        } catch (Excep1 | Excep2 e) {
            return 0;
        }
    }

    private static interface I {
    }

    private static class Excep1 extends Exception implements I {
    }

    private static class Excep2 extends Exception implements I {
    }
}

ทำไมไม่m2()รวบรวมวิธี?


22
คุณได้รับข้อผิดพลาดในการรวบรวมอะไร
กาวิน

คำตอบ:


79

ประเภทของการแสดงออก

b ? new Excep1() : new Excep2()

คือExceptionตั้งแต่ที่เป็น supertype ทั่วไปของและExcep1Excep2

อย่างไรก็ตามคุณไม่ได้ดึงดูดExceptionคอมไพเลอร์จึงบ่นเกี่ยวกับมัน

ถ้าคุณจับExceptionมันจะผ่านการรวบรวม:

public int m2(boolean b) {
    try {
        throw b ? new Excep1() : new Excep2();
    } catch (Exception e) {
        return 0;
    }
}

ฉันพยายามค้นหารายการ JLS ที่อธิบายประเภทของการแปลที่เป็นเงื่อนไขในตัวอย่างของคุณ

ทั้งหมดที่ฉันพบคือว่าการแสดงออกเฉพาะนี้คือ15.25.3 อ้างอิงเงื่อนไขการแสดงออก

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

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

ในกรณีของคุณที่สองและถูกดำเนินการที่สามมีสามชนิดที่พบบ่อย - Object, ThrowableและException- ประเภทของการแสดงออกต้องเป็นหนึ่งในสองหลังตั้งแต่ "การแสดงออกในคำสั่งจากเส้นข้างจะต้องแสดงตัวแปรหรือมูลค่าของชนิดการอ้างอิง ซึ่งสามารถกำหนดได้ (§5.2) สำหรับประเภท Throwable "

ปรากฏว่าคอมไพเลอร์เลือกประเภททั่วไปที่เฉพาะเจาะจงที่สุด ( Exception) และดังนั้นจึงcatch (Exception e)แก้ข้อผิดพลาดในการรวบรวม

ฉันยังพยายามแทนที่ข้อยกเว้นที่กำหนดเองสองข้อของคุณด้วยคลาสย่อยสองคลาสIOExceptionซึ่งในกรณีนี้catch (IOException e)จะช่วยแก้ไขข้อผิดพลาดในการคอมไพล์


11
@Smile ชนิดของนิพจน์เงื่อนไขที่ประกอบไปด้วยสามจะต้องร่วมกันทั้งตัวถูกดำเนินการที่ 2 และ 3 ดังนั้นจึงไม่สามารถหรือExcep1 Excep2มันสามารถเป็นExceptionได้
Eran

2
สัญลักษณ์แสดงหัวข้อย่อยสุดท้ายใน 15.25.3 มีคำตอบ: "มิฉะนั้นตัวถูกดำเนินการที่สองและสามเป็นประเภท S1 และ S2 ตามลำดับให้ T1 เป็นประเภทที่เป็นผลมาจากการใช้การแปลงมวยเป็น S1 และให้ T2 เป็นประเภทที่ผลลัพธ์ จากการใช้การแปลงมวยเป็น S2 ประเภทของนิพจน์เงื่อนไขคือผลลัพธ์ของการใช้การแปลงการจับภาพ (§5.1.10) ถึง lub (T1, T2) " lub นี่คือ Least Upper Bound ซึ่งเป็น supertype ทั่วไปที่ใกล้ที่สุดซึ่งแบ่งประเภทของนิพจน์ทั้งสอง
amalloy

22

คุณกำลังสับสนคอมไพเลอร์กับบรรทัดนี้:

throw b ? new Excep1() : new Excep2();

คอมไพเลอร์เห็นว่าผลลัพธ์ของนิพจน์ (ทางซ้ายของการโยน) เป็นคลาสซุปเปอร์ทั่วไประหว่าง Except1 และ Except2 ซึ่งเป็นข้อยกเว้นดังนั้นประเภทที่มีประสิทธิภาพที่คุณโยนจะกลายเป็นข้อยกเว้น คำสั่ง catch ไม่สามารถรับได้ว่าคุณกำลังพยายามโยน Excep1 หรือ Except2


4

Java จำกัด ให้คุณตรวจจับหรือประกาศประเภทข้อยกเว้นทั้งหมดที่วิธีการสามารถทำได้

มันค้นหาผู้ปกครองทั่วไปสำหรับข้อยกเว้นทั้งสอง (/ ทั้งหมด) และคาดว่าคุณจะจับหรือประกาศเป็นการโยนตัวอย่างเช่นหากExcep1ขยายThrowableคุณจะต้องจับยัง Throwable

ในกรณีแรก Java แน่ใจว่าคุณกำลังขว้างExcep1หรือExcep2

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