Apakah tidak masalah memiliki pernyataan penangkapan kosong?

58

Saya memikirkannya dan tidak dapat memberikan contoh. Mengapa seseorang ingin menangkap pengecualian dan tidak melakukan apa-apa? Bisakah Anda memberi contoh? Mungkin itu hanya sesuatu yang tidak boleh dilakukan.

ysolik
sumber
Bagaimana dengan akhirnya?
Chris
2
btw - ini ditanyakan pada SO tahun lalu: stackoverflow.com/questions/1234343/...
warren
17
setidaknya harus berisi komentar mengapa itu kosong.
peterchen

Jawaban:

77

Saya selalu melakukannya dengan hal-hal seperti kesalahan konversi di D:

import std.conv, std.stdio, std.exception;

void main(string[] args) {  
    enforce(args.length > 1, "Usage:  foo.exe filename");

    double[] nums;

    // Process a text file with one number per line into an array of doubles,
    // ignoring any malformed lines.
    foreach(line; File(args[1]).byLine()) {
        try {
            nums ~= to!double(line);
        } catch(ConvError) {
            // Ignore malformed lines.
        }
    }

    // Do stuff with nums.
}

Yang mengatakan, saya pikir semua blok tangkap harus memiliki sesuatu di dalamnya, bahkan jika sesuatu itu hanya komentar yang menjelaskan mengapa Anda mengabaikan pengecualian.

Sunting: Saya juga ingin menekankan bahwa, jika Anda akan melakukan sesuatu seperti ini, Anda harus berhati-hati untuk hanya menangkap pengecualian spesifik yang ingin Anda abaikan. Melakukan hal yang biasa-biasa saja catch {}hampir selalu merupakan hal yang buruk.

dsimcha
sumber
15
+1 untuk komentar penjelasan.
Michael K
Beberapa IDE memungkinkan Anda menentukan bahwa nama tertentu untuk pengecualian (biasanya "abaikan") menunjukkan bahwa Anda sengaja mengabaikannya, yang menekan peringatan yang akan ditampilkan; ini menggantikan komentar.
Alex Feinman
Saya tidak terbiasa D, tapi saya berasumsi mungkin untuk melakukan sesuatu seperti bool TryParse (garis string, keluar valToParse ganda), yang mungkin lebih bersih.
ysolik
4
Wow, seseorang yang benar-benar menggunakan D! :-P
James McNellis
4
Seperti kata @Michael - itu tidak cukup kosong karena Anda punya komentar di sana; harus wajib menambahkan komentar "tangkapan ini sengaja dikosongkan" jika tidak ada pernyataan
STW
50

Salah satu contoh di mana saya pikir OK untuk hanya menelan pengecualian tanpa melakukan apa-apa, bahkan mencatat pengecualian, adalah di dalam kode logging itu sendiri.

Jika Anda mencoba mencatat sesuatu dan mendapat pengecualian, tidak banyak yang dapat Anda lakukan:

  • Anda tidak dapat mencatatnya tentu saja;
  • Anda mungkin dapat kembali ke mekanisme pencadangan cadangan, tetapi sebagian besar aplikasi tidak secanggih itu, dan bagi mereka yang cukup canggih masalah desain yang sama akan muncul dengan mekanisme pencatatan cadangan;
  • gagal cepat - akan menjadi solusi yang terlalu radikal untuk sebagian besar aplikasi;
  • melempar pengecualian akan sedikit bermanfaat karena akan berakhir dengan catch catch up stack yang hampir pasti akan mencoba mencatatnya ...

Itu membuat Anda memiliki opsi "yang paling tidak jahat" untuk menelannya dengan diam-diam, memungkinkan aplikasi untuk terus melakukan pekerjaan utamanya, tetapi mengkompromikan kemampuan untuk memecahkannya.

kdubinet
sumber
10
poin bagus. men-debug kode debug selalu merupakan tantangan.
DevSolo
7
Ini, jutaan kali. Terutama ketika Anda mempertimbangkan bahwa jika Anda login, Anda mungkin berada dalam kondisi yang mengerikan; Anda bisa kehabisan memori, bisa menabrak, bisa apa saja. Pada titik ini, ketika Anda mencatat kesalahan, dan ITU gagal, satu-satunya hal yang bertanggung jawab untuk dilakukan adalah tidak ada apa-apa; Anda tidak memiliki jaminan bahwa apa pun yang Anda coba tidak akan memperburuknya.
GWLlosa
Poin yang bagus. Dalam kode logging saya, saya juga ingin menambahkan InnerMessage sebagai pengecualian. Banyak kali ini adalah nol, jadi mencoba menambahkannya akan meledakkan penebangan itu sendiri.
Tangurena
@ Tangurena Jika sering null maka atasi itu, jangan meledak. Dalam C # saya sering menjaga hal-hal seperti itu oleh ?? "";
Loren Pechtel
8

Jika pengecualian dilemparkan oleh operasi yang opsional, mungkin tidak ada yang bisa dilakukan. Mungkin tidak berguna untuk mencatatnya. Dalam hal ini, Anda mungkin hanya ingin menangkapnya dan tidak melakukan apa pun.

Jika Anda melakukan ini, sertakan komentar. Selalu berkomentar apa pun yang tampak seperti bug (fallthrough dalam switchpernyataan, catchblok kosong , tugas dalam kondisi).

Anda mungkin berpendapat bahwa ini bukan penggunaan pengecualian, tapi itu untuk pertanyaan lain.

David Thornley
sumber
6

catchBlok kosong adalah bau kode di sebagian besar bahasa. Gagasan utamanya adalah menggunakan pengecualian untuk situasi luar biasa dan tidak menggunakannya untuk kontrol logis. Semua pengecualian harus ditangani di suatu tempat.

Sebagai konsekuensi dari mengambil pendekatan ini, ketika Anda memprogram satu lapisan aplikasi tertentu, Anda memiliki beberapa pilihan:

  • jangan lakukan apa-apa tentang pengecualian. Ini akan ditangkap dan ditangani oleh lapisan yang berbeda
  • tangkap dan lakukan tindakan korektif.
  • tangkap, lakukan sesuatu, tapi lemparkan kembali agar lapisan lain bisa ditangani

Ini tidak benar-benar meninggalkan ruang untuk melakukan apa-apa, catchblok kosong .

DIedit UNTUK MENAMBAH : misalkan Anda memprogram dalam bahasa di mana melemparkan pengecualian adalah cara normal untuk mengendalikan logika program (salah satu alternatif untuk goto). Kemudian catchblok kosong dalam program yang ditulis dalam bahasa ini sangat mirip dengan elseblok kosong dalam bahasa tradisional (atau tidak ada elseblok sama sekali). Namun, saya percaya ini bukan gaya pemrograman yang direkomendasikan oleh komunitas pengembangan C #, Java atau C ++.

azheglov
sumber
Saya pikir menggunakan pengecualian sebagai kontrol logika telah menjadi sangat umum, jadi saya menemukan diri saya dengan blok tangkap kosong atau hampir kosong cukup sering.
whatsisname
+1 untuk mengetahui bahwa blok tangkap kosong dapat menunjukkan penggunaan pengecualian untuk kontrol aliran.
John M Gant
Menggunakan pengecualian untuk logika pemrograman umumnya dianggap praktik yang buruk. Tapi, yang mengejutkan (argumen awal saya terhadap pengecualian) pengecualian tidak menyebabkan hit kinerja yang nyata. Lihat codeproject.com/KB/exception/ExceptionPerformance.aspx .
Evan Plaice
6

Dalam beberapa kasus, Java mengharuskan Anda untuk menangani pengecualian yang dapat, dalam keadaan apa pun, tidak pernah terjadi. Pertimbangkan kode ini:

try {
   bytes[] hw = "Hello World".getBytes("UTF-8");
}
catch(UnsupportedCodingException e) {
}

Setiap implementasi platform Java diperlukan untuk mendukung rangkaian karakter standar berikut.

...

UTF-8

Tanpa merusak platform Java Anda, tidak ada cara untuk menyebabkan pengecualian ini. Jadi mengapa repot-repot menanganinya? Tetapi Anda tidak bisa begitu saja menghilangkan klausa coba-tangkap.

pengguna281377
sumber
1
Dalam kasus seperti ini saya akan tergoda untuk menambahkan throw new Error(e)hanya untuk benar-benar yakin bahwa saya tidak melewatkan apa pun (atau melaporkan platform yang benar-benar rusak).
Halle Knast
@HalleKnast Ya. Ini telah dibahas secara terperinci di sini: softwareengineering.stackexchange.com/questions/122233/…
user281377
5

Sebagai aturan umum, tidak. Anda ingin melemparkan pengecualian ke tumpukan, atau mencatat apa yang terjadi.

Namun, saya sering melakukan ini ketika saya mem-parsing string dan mengkonversi ke angka (terutama dalam memetakan proyek yang digunakan-sekali dan membuang variasi).

boolean isNonZeroNumber = false;

try {
   if(StringUtils.isNotBlank(s) && new BigDecimal(s).compareTo(BigDecimal.ZERO) != 0) {
     b = true;
   }
} catch(NumberFormatException e) {
//swallow this exception; b stays false.
}

return b;
Fil
sumber
3

Dalam beberapa kasus, pengecualian sama sekali tidak luar biasa; bahkan diharapkan. Pertimbangkan contoh ini:

    /* Check if the process is still alive; exitValue() throws an exception if it is */
    try {
        p.exitValue();
        processPool.remove(p);
    }
    catch (IllegalThreadStateException e) { /* expected behaviour */ }

Karena tidak ada metode isAlive () di java.lang.Process (), satu-satunya cara untuk memeriksa apakah masih hidup adalah dengan memanggil exitValue (), yang melempar IllegalThreadStateException jika prosesnya masih berjalan.

pengguna281377
sumber
2

Dalam pengalaman saya yang sederhana, jarang hal yang baik ini. Jarak tempuh Anda mungkin bervariasi.

Hampir setiap kali saya melihat ini di basis kode kami, itu karena saya telah melacak bug yang disembunyikan oleh pengecualian yang dimakan. Dengan kata lain, dengan tidak memberikan kode apa pun, aplikasi tidak memiliki cara untuk menunjukkan kesalahan, atau melakukan tindakan lain.

Terkadang, pada lapisan API misalnya, Anda mungkin tidak ingin atau tidak dapat membiarkan pengecualian lewat, jadi dalam hal ini, saya cenderung mencoba dan menangkap yang paling umum, lalu mencatatnya. Sekali lagi, untuk setidaknya memberikan kesempatan sesi debug / diagnosis.

Biasanya, jika itu harus kosong, paling tidak saya lakukan adalah meletakkan semacam pernyataan, jadi setidaknya sesuatu terjadi selama sesi debug. Yang mengatakan, jika saya tidak bisa mengatasinya, saya cenderung menghilangkannya sepenuhnya.

DevSolo
sumber
2

IMO ada satu tempat di mana pernyataan penangkapan kosong OK. Dalam kasus uji di mana Anda mengharapkan pengecualian:

try
{
   DoSomething(); //This should throw exception if everything works well
   Assert.Fail('Expected exception was not thrown');
}
catch(<whatever exception>)
{
    //Expected to get here
}
Victor Hurdugaci
sumber
+1, saya benci saya melakukan ini tetapi ini bekerja di JUnit
sal
@sal: bagaimana dengan @Test (diharapkan = Exception.class)?
ysolik
@ysolik, kebiasaan buruk
sal
1
@sal: Mengapa itu kebiasaan buruk?
Adam Lear
ummmm ada cara untuk melakukan ini dengan kerangka pengujian unit. Ex. NUnit. Ada kasus tertentu di mana pengujian bahwa sesuatu yang diprediksi gagal mungkin berguna. Meskipun, saya tidak akan pernah melakukannya dalam kode produksi.
Evan Plaice
2

Saya percaya ada kasus-kasus tertentu di mana dibenarkan memiliki klausa tangkapan kosong - ini adalah kasus ketika Anda ingin kode terus berjalan jika operasi tertentu gagal. Namun, saya berpikir bahwa pola ini dapat dengan mudah digunakan secara berlebihan, sehingga setiap penggunaan harus diperiksa dengan cermat untuk memastikan tidak ada cara yang lebih baik untuk menanganinya. Secara khusus, ini tidak boleh dilakukan jika meninggalkan program dalam keadaan tidak konsisten atau jika itu dapat menyebabkan beberapa bagian lain dari kode gagal nanti.

Hai. nate
sumber
1

Saya tidak percaya tidak memiliki tingkat peringatan ketika pengecualian terjadi - tidakkah seharusnya salah satu tujuan pemrograman adalah untuk meningkatkan kode? Jika pengecualian terjadi 10% dari waktu, dan Anda tidak pernah mengetahuinya, maka pengecualian akan selalu seburuk itu, atau lebih buruk.

Namun, saya memang melihat sisi lain, bahwa jika pengecualian tidak membahayakan nyata dalam pemrosesan kode, lalu mengapa mengekspos pengguna untuk itu. Solusi yang biasanya saya terapkan adalah dengan login oleh kelas logger saya (yang ada di setiap kelas tunggal yang pernah saya tulis di tempat kerja).

Jika ini adalah pengecualian yang tidak berbahaya, maka saya melakukan panggilan ke metode .debug () Logger saya; jika tidak, Logger.Error () (dan (mungkin) melempar).

try
{
   doWork();
}
catch(BenignException x)
{
  _log.Debug("Error doing work: " + x.Message);
}

Omong-omong, dalam implementasi logger saya, membuat panggilan ke metode .Debug () hanya akan mencatatnya jika file App.Config saya menentukan bahwa level log eksekusi program dalam mode Debug.

Tim Claason
sumber
Bagaimana jika _log. Debug melempar pengecualian (untuk alasan apa pun)?
JohnL
Lalu. Debug () memakan pengecualian dan saya tidak pernah tahu tentang itu. Tetapi saya merasa jauh lebih percaya diri tentang logger saya daripada yang saya rasakan tentang kode yang sering memberikan pengecualian. Jika saya khawatir tentang itu, saya kira saya bisa menerapkan semacam pola yang mengawasi untuk masuk ke blok tangkap, dan menyimpannya untuk nanti. Dalam hal apa pun - poin diambil
Tim Claason
1

Pemeriksaan keberadaan adalah kasus penggunaan yang baik:

// If an exception happens, it doesn't matter. Log the initial value or the new value

function logId(person) {
    let id = 'No ID';
    try {
        id = person.data.id;
    } catch {}
    console.log(id);
}

Kasus lain adalah ketika finallyklausa digunakan:

 function getter(obj){}

 function objChecker()
   {
   try
     {
     /* Check argument length and constructor type */
     if (getter.length === 1 && getter.constructor === Function)
       {
       console.log("Correct implementation");
       return true;
       }
     else
       {
       console.log("Wrong implementation");
       return false;
       }
     }
   catch(e)
     {
     }
   finally
     {
     console.log(JSON.stringify(getter))
     }
   }

 // Test the override of the getter method 
 getter = getter;
 objChecker();
 getter = [];
 objChecker();
 getter = {};
 objChecker();
 getter = RegExp;
 objChecker();
 getter = Function;
 objChecker();

Ada proposal untuk memungkinkan penghilangan tangkapan yang mengikat dalam ECMAScript yang berkaitan dengan ini dan kasus penggunaan serupa.

Referensi

Paul Sweatte
sumber
Contoh lain: Dalam nodejs, metode fs.exists (yang mengembalikan benar atau salah) ditinggalkan ( nodejs.org/dist/latest-v10.x/docs/api/… ) yang mendukung fs.access yang melempar pengecualian dalam case file tidak ada. Jika seseorang ingin melakukan sesuatu hanya jika file itu ada, klausa tangkapan sama sekali tidak perlu.
systemovich
0

Satu-satunya waktu saya benar-benar perlu melakukan sesuatu seperti ini adalah dengan kelas logging untuk aplikasi konsol. Ada penangkap tangkapan global tingkat atas yang memancarkan kesalahan ke STDOUT, mencatat kesalahan ke file, lalu menutup aplikasi dengan kode kesalahan> 0.

Masalahnya di sini adalah bahwa kadang-kadang, logging ke file gagal. Izin direktori menghentikan Anda dari menulis file, file itu dikunci secara eksklusif, apa pun. Jika itu terjadi, saya tidak bisa menangani pengecualian dengan cara yang sama seperti di tempat lain (menangkap, mencatat detail yang relevan , membungkus dengan tipe pengecualian yang lebih baik, dll) karena mencatat detail pengecualian menyebabkan logger melakukan tindakan yang sama ( mencoba menulis ke file) yang sudah gagal. Ketika mereka gagal lagi ... Anda lihat ke mana saya pergi. Itu masuk ke loop tak terbatas.

Jika Anda membatalkan beberapa blok percobaan {}, Anda bisa berakhir dengan pengecualian yang muncul di kotak pesan (bukan yang Anda inginkan untuk aplikasi konfigurasi senyap). Jadi dalam metode yang menulis ke file log, saya memiliki penangan tangkapan kosong. Ini tidak mengubur kesalahan karena Anda masih mendapatkan kode kesalahan> 0, itu hanya menghentikan loop tak terbatas dan memungkinkan aplikasi untuk keluar dengan anggun.

Ada komentar tentu saja, menjelaskan mengapa itu kosong.

(Aku akan memposting ini sebelumnya, aku hanya takut dinyalakan dilupakan. Karena aku bukan satu-satunya, meskipun ...)

JohnL
sumber
0

Tidak apa-apa dalam situasi ketika beberapa urutan harus dieksekusi tidak peduli apa pun dengan bagian paling kritis yang ditempatkan di akhir.

Sebagai contoh. Komunikasi kontrol gerak dari host ke pengontrol. Dalam situasi darurat ada sejumlah langkah persiapan untuk menggagalkan gerakan, menghentikan generasi lintasan, memperlambat motor, mengaktifkan jeda, menonaktifkan amplifier dan setelah ini Anda harus mematikan daya bus. Semua harus terjadi secara berurutan dan jika salah satu dari langkah-langkah yang gagal, sisa dari langkah-langkah lainnya harus dieksekusi walaupun dengan risiko yang diterima dari kerusakan perangkat keras. Katakanlah bahkan jika semua di atas gagal, daya bunuh bus harus tetap terjadi.

pengguna7071
sumber
Itu tidak berarti Anda tidak melakukan apa-apa, hanya saja apa yang Anda lakukan tidak membatalkan arus. Tangkap pengecualian Anda, simpan di memori (tidak ada penundaan penulisan disk), lalu matikan daya pada pernyataan terakhir. Kemudian lakukan apa yang Anda mau dengan informasi yang disimpan.
Loren Pechtel
0

Menutup sumber daya sistem dengan anggun untuk memulihkan dari kesalahan

Misalnya. Jika Anda menjalankan layanan di latar belakang yang tidak memberikan umpan balik kepada pengguna, Anda mungkin tidak ingin mendorong indikasi kesalahan kepada pengguna tetapi Anda tidak perlu menutup sumber daya yang digunakan dengan cara yang anggun.

try
{
    // execution code here
}
catch(Exception e)
{
    // do nothing here
}
finally
{
    // close db connection
    // close file io resource
    // close memory stream
    // etc...
}

Idealnya, Anda akan menggunakan tangkapan dalam mode debug untuk menangkap kesalahan dan mencetaknya ke konsol atau ke file log untuk pengujian. Dalam lingkungan produksi, layanan latar belakang umumnya diharapkan tidak mengganggu pengguna ketika kesalahan dilemparkan sehingga output kesalahan harus ditekan.

Evan Plaice
sumber