Menangkap banyak pengecualian di Java-8

71

Saat mencoba fitur multi-tangkapan yang saya temukan dalam m1()metode saya semuanya bekerja dengan baik seperti yang diharapkan.

Namun, dalam m2()kode yang sama tidak dikompilasi. Saya baru saja mengubah sintaks untuk mengurangi jumlah baris kode.

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 {
    }
}

Mengapa metode tidak m2()dikompilasi?

Pelawak
sumber
22
Apa kesalahan kompilasi yang Anda dapatkan?
Gavin

Jawaban:

79

Jenis ekspresi

b ? new Excep1() : new Excep2()

adalah Exception, karena itulah supertype umum dari Excep1dan Excep2.

Namun, Anda tidak menangkap Exception, jadi kompiler mengeluh tentang hal itu.

Jika Anda menangkap Exception, itu akan melewati kompilasi:

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

Saya mencoba untuk menemukan entri JLS yang menjelaskan jenis ekspresi ternary kondisional dalam contoh Anda.

Yang bisa saya temukan adalah bahwa ungkapan khusus ini adalah 15.25.3. Referensi Ekspresi Bersyarat .

Saya tidak sepenuhnya yakin apakah itu dianggap sebagai ekspresi poli atau ekspresi mandiri. Saya pikir itu standalone (karena ekspresi poli melibatkan konteks penugasan atau konteks doa, dan saya tidak berpikir throwpernyataan dianggap sebagai salah satu dari mereka).

Untuk ekspresi mandiri: "Jika operan kedua dan ketiga memiliki tipe yang sama (yang mungkin merupakan tipe null), maka itu adalah tipe ekspresi bersyarat."

Dalam kasus Anda, operan kedua dan ketiga memiliki tiga tipe umum - Object, Throwabledan Exception- tipe ekspresi harus salah satu dari dua yang terakhir, karena, "Ekspresi dalam pernyataan melempar harus menunjukkan variabel atau nilai dari tipe referensi yang ditugaskan (§5.2) ke tipe Throwable. "

Tampaknya kompiler memilih tipe umum yang paling spesifik ( Exception), dan karenanya catch (Exception e)memecahkan kesalahan kompilasi.

Saya juga mencoba mengganti dua pengecualian khusus Anda dengan dua sub-kelas IOException, dalam hal ini catch (IOException e)menyelesaikan kesalahan kompilasi.

Eran
sumber
11
@Smile tipe ekspresi kondisional ternary harus umum untuk operan ke-2 dan ke-3. Karena itu tidak bisa Excep1atau Excep2. Itu hanya bisa Exception.
Eran
2
Poin terakhir di 15.25.3 memiliki jawaban: "Jika tidak, operan kedua dan ketiga masing-masing adalah tipe S1 dan S2. Biarkan T1 adalah tipe yang dihasilkan dari penerapan konversi tinju ke S1, dan biarkan T2 menjadi tipe yang menghasilkan dari menerapkan konversi tinju ke S2. Jenis ekspresi kondisional adalah hasil dari menerapkan konversi tangkap (§5.1.10) ke lub (T1, T2). " lub di sini adalah Least Upper Bound, yang merupakan supertype umum terdekat yang dimiliki oleh dua tipe ekspresi.
amalloy
22

Anda mengacaukan kompiler dengan baris ini:

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

Kompilator melihat bahwa hasil dari ekspresi (di sebelah kiri lemparan) adalah kelas super umum antara exception1 dan exception2, yang merupakan pengecualian, dan karenanya tipe efektif yang Anda lempar menjadi pengecualian. Pernyataan tangkapan tidak dapat mengambil bahwa Anda mencoba untuk membuang Excep1 atau exception2.

GideonleGrange
sumber
4

Java membatasi Anda untuk menangkap atau mendeklarasikan semua tipe pengecualian yang dapat dilemparkan metode ini,

Ini mencari orang tua umum untuk kedua (/ semua) Pengecualian dan mengharapkan Anda untuk menangkap atau menyatakan sebagai lemparan, misalnya jika Excep1meluas ThrowableAnda harus menangkap juga Throwable

Dalam kasus pertama, Java yakin Anda melempar Excep1atauExcep2

pengguna7294900
sumber