Bagaimana saya bisa melewati kumpulan pengecualian sebagai penyebab root?

52

Beberapa metode,, myMethodmemanggil beberapa eksekusi paralel dan menunggu penghentian mereka.

Eksekusi paralel ini dapat diakhiri dengan pengecualian. Jadi myMethodmendapat daftar pengecualian.

Saya ingin meneruskan daftar pengecualian sebagai penyebab root, tetapi penyebab root mungkin hanya satu pengecualian. Tentu saya bisa membuat pengecualian sendiri untuk mencapai apa yang saya inginkan, tetapi saya ingin tahu apakah Java, Spring, atau Spring Batch memiliki sesuatu seperti ini di luar kotak.

gstackoverflow
sumber
3
.NET memiliki AggregateExceptionyang berisi daftar pengecualian. Gagasan itu juga berlaku untuk Jawa.
usr
1
Lihat juga stackoverflow.com/q/8946661/821436
Reinstate Monica - M. Schröder

Jawaban:

49

Saya tidak yakin saya akan melakukannya (walaupun diberi JavaDoc, saya tidak dapat memberi tahu Anda mengapa saya ragu), tetapi ada daftar pengecualian yang ditekan Throwable, yang dapat Anda tambahkan melalui addSuppressed. JavaDoc tampaknya tidak mengatakan ini hanya untuk JVM untuk digunakan dalam coba-dengan-sumber daya:

Menambahkan pengecualian yang ditentukan untuk pengecualian yang ditekan untuk memberikan pengecualian ini. Metode ini aman untuk thread dan biasanya dipanggil (secara otomatis dan implisit) oleh pernyataan coba-dengan-sumber daya.

Perilaku penindasan diaktifkan kecuali dinonaktifkan melalui konstruktor. Ketika penindasan dinonaktifkan, metode ini tidak melakukan apa pun selain untuk memvalidasi argumennya.

Perhatikan bahwa ketika satu pengecualian menyebabkan pengecualian lain, pengecualian pertama biasanya ditangkap dan kemudian pengecualian kedua dilontarkan sebagai respons. Dengan kata lain, ada hubungan sebab akibat antara dua pengecualian. Sebaliknya, ada situasi di mana dua pengecualian independen dapat dilemparkan ke dalam blok kode saudara, khususnya di blok percobaan pernyataan coba-dengan-sumber daya dan akhirnya blok yang dihasilkan kompiler yang menutup sumber daya. Dalam situasi ini, hanya satu dari pengecualian yang dilemparkan yang dapat diperbanyak. Dalam pernyataan coba-dengan-sumber daya, ketika ada dua pengecualian seperti itu, pengecualian yang berasal dari blok uji diperbanyak dan pengecualian dari blok akhirnya ditambahkan ke daftar pengecualian yang ditekan oleh pengecualian dari blok uji coba. Sebagai pengecualian membuka tumpukan,

Pengecualian mungkin telah menekan pengecualian sementara juga disebabkan oleh pengecualian lain. Apakah pengecualian memiliki sebab atau tidak diketahui secara semantik pada saat penciptaannya, tidak seperti apakah pengecualian akan menekan pengecualian lain yang biasanya hanya ditentukan setelah pengecualian dilemparkan.

Perhatikan bahwa kode tertulis pemrogram juga dapat mengambil keuntungan dari memanggil metode ini dalam situasi di mana terdapat beberapa pengecualian saudara dan hanya satu yang dapat diperbanyak.

Perhatikan bahwa paragraf terakhir, yang tampaknya sesuai dengan kasus Anda.

TJ Crowder
sumber
[...] apakah pengecualian akan menekan pengecualian lain [...] biasanya ditentukan setelah pengecualian dilemparkan. Saya membayangkan ini tidak akan menjadi kasus ketika beberapa pengecualian ditekan dikumpulkan dari berjalan paralel.
GOTO 0
24

Pengecualian dan penyebabnya selalu hanya merupakan hal 1: 1: Anda dapat melemparkan satu pengecualian dan setiap pengecualian hanya dapat memiliki satu penyebab (yang sekali lagi dapat memiliki satu penyebab ...).

Itu bisa dianggap sebagai kesalahan desain, terutama ketika mempertimbangkan perilaku multi-threaded seperti yang Anda gambarkan.

Itulah salah satu alasan mengapa Java 7 ditambahkan addSuppressedke throwable yang pada dasarnya dapat melampirkan jumlah pengecualian sewenang-wenang untuk satu sama lain (motivasi utama lainnya adalah sumber daya try-with-yang membutuhkan cara untuk menangani pengecualian di blok akhirnya tanpa diam-diam menjatuhkan mereka).

Jadi pada dasarnya ketika Anda memiliki 1 pengecualian yang menyebabkan proses Anda gagal, Anda menambahkan satu sebagai penyebab pengecualian tingkat yang lebih tinggi, dan jika Anda memiliki lagi, maka Anda menambahkannya ke yang asli menggunakan addSuppressed. Idenya adalah bahwa pengecualian pertama "menekan" yang lain menjadi anggota dari "rantai pengecualian nyata".

Kode sampel:

Exception exception = null;
for (Foobar foobar : foobars) {
  try {
    foobar.frobnicate();
  } catch (Exception ex) {
    if (exception == null) {
      exception = ex;
    } else {
      exception.addSuppressed(ex);
    }
  }
}
if (exception != null) {
  throw new SomethingWentWrongException(exception);
}
Joachim Sauer
sumber
4
Saya tidak akan melakukannya dengan cara yang Anda sarankan, kecuali salah satu pengecualian yang mendasarinya dapat benar-benar dipilih sebagai yang "utama". Jika Anda hanya secara sewenang-wenang memilih salah satu pengecualian sebagai yang utama dan yang lainnya sebagai tertekan, Anda mengundang penelepon untuk mengabaikan pengecualian yang ditekan dan hanya melaporkan yang utama - bahkan jika "utama" pengecualian adalah TypoInUserInputException dan salah satu yang ditekan adalah DatabaseCorruptedException.
Ilmari Karonen
1
... Sebagai gantinya, saya akan menandai semua pengecualian yang mendasarinya sebagai ditekan oleh SomethingWentWrongException, dan memberikan pengecualian pesan yang jelas menunjukkan bahwa satu atau lebih pengecualian yang ditekan harus mengikuti, misalnya sesuatu seperti " X dari tugas Y gagal, lihat daftar kegagalan di bawah ".
Ilmari Karonen