Apakah perlu menambahkan case standar saat menggunakan switch case?

41

Selama ulasan kode baru-baru ini saya diminta untuk meletakkan defaultcase di semua file di mana pun switchblok digunakan, bahkan jika tidak ada hubungannya default. Itu berarti saya harus meletakkan defaultkasing dan tidak menulis apa pun di dalamnya.

Apakah ini hal yang benar untuk dilakukan? Apa tujuannya?

Ankit
sumber
9
Terserah Anda ... maksud saya gaya kode supervisor.
SD
1
Saya pikir bahkan ada kasus di mana Anda tidak ingin kasus default. Pertimbangkan untuk mengganti enum. Sakelar Anda menentukan wadah untuk semua nilai yang mungkin. Sekarang menambahkan nilai ke enum akan menghasilkan menambahkan kasus di saklar itu. Jika Anda tidak melakukannya, ini mungkin kesalahan, karena Anda ingin melakukan sesuatu untuk nilai enum baru ini, tetapi kode Anda tidak. Compiler Anda dapat memperingatkan Anda (saya pikir; tidak yakin tentang Java) tentang itu, tetapi hanya jika Anda tidak meletakkan case default. Atau, Anda dapat mencetak peringatan dalam kasus default ketika Anda yakin kode tidak pernah mencapainya.
Tema
6
Saya dan teman-teman saya menyebut ini kasus "Pengecualian Pengembang" - ketika sesuatu dalam kode terjadi yang Anda tahu seharusnya tidak pernah terjadi (karena alasan logis / kode), maka kami menambahkan "Pengecualian Pengembang" yang dilemparkan. Dengan begitu, jika ini pernah terjadi, Pengecualian Pengembang dilemparkan dan setidaknya kita tahu di mana segala sesuatunya salah.
Marco

Jawaban:

31

Tampaknya ada tiga kasus ketika defaultpernyataan tidak diperlukan:

  1. tidak ada case lain yang tersisa, karena ada sejumlah nilai yang masuk switch case. Tapi ini mungkin berubah seiring waktu (sengaja atau tidak sengaja), dan akan lebih baik default casejika ada perubahan apa pun _ Anda bisa mencatat atau memperingatkan pengguna tentang nilai yang salah.

  2. Anda tahu bagaimana dan di mana switch caseakan digunakan dan nilai apa yang akan memasukinya. Sekali lagi, ini mungkin berubah dan pemrosesan ekstra mungkin diperlukan.

  3. kasus lain tidak memerlukan pemrosesan khusus. Jika ini masalahnya, saya pikir Anda diminta untuk menambahkan default case, karena ini adalah gaya pengkodean yang diterima, dan itu membuat kode Anda lebih mudah dibaca.

Dua kasus pertama didasarkan pada asumsi. Jadi (dengan asumsi Anda bekerja di tim yang tidak terlalu kecil karena Anda memiliki ulasan kode reguler), Anda tidak mampu membuat asumsi tersebut. Anda tidak tahu siapa yang akan bekerja dengan kode Anda atau membuat panggilan ke fungsi / memanggil metode dalam kode Anda. Demikian pula, Anda mungkin perlu bekerja dengan kode orang lain. Memiliki gaya pengkodean yang sama akan memudahkan untuk berurusan dengan kode seseorang (termasuk Anda).

superM
sumber
14
Dalam kasus 1 dan 2, kasus default harus menjadi kesalahan. Jika gaya pengkodean Anda selalu menggunakan default, maka lakukan itu, tetapi buat itu memancarkan kesalahan dalam 1 dan 2. Apakah mungkin, itu harus memancarkannya pada waktu kompilasi, tetapi itu mungkin tidak selalu mungkin, jika pernah di java. Saya setidaknya pikir sangat penting bagi pengguna untuk mendapatkan pesan bahwa "Anda menembak diri sendiri di kaki dengan melewati nilai ini"
martiert
11
Kasing default selalu merupakan ide yang bagus, karena, misalnya dalam kasing, jika seseorang menambahkan entri baru ke kasing, kasing default Anda harus melakukan sesuatu yang mirip dengan throw new IllegalStateException("Unrecognised case "+myEnum)yang menunjukkan kepada Anda di mana dan apa kesalahannya.
Rich
Apakah ini berarti Anda harus selalu memiliki elseklausa setelah setiap if/else ifbahkan jika Anda tahu itu tidak boleh terjadi? Sepertinya bukan ide yang baik bagi saya ...
jadkik94
2
Jika saya dapat menambahkan anekdot dari pekerjaan saya: Saya memiliki metode pabrik yang menggunakan enum untuk membuat instance beberapa kelas. Saya telah meninggalkan instruksi bahwa setiap kali Anda menambahkan kelas baru ke proyek itu, Anda harus menambahkan nilai ke enum dan case o switch. Tentu saja, seminggu setelah saya menutup kode itu berhenti berfungsi, dengan salah satu pengecualian yang tidak boleh diajukan. Saya pergi ke programmer dan bertanya kepadanya: "Apakah Anda menambahkan kasing ke sakelar?" dan tentu saja, dia tidak melakukannya. Pada hari itu saya mengubah pengecualian dengan mengatakan "jika Anda menerima pesan ini, salahkan pengembang terakhir yang menyentuh kode".
Ziv
28

Apakah ini tindakan yang tepat untuk dilakukan? Apa tujuannya?

Bukan tidak biasa bagi standar pengkodean perusahaan untuk meminta kasing standar untuk semua switchpernyataan. Salah satu alasannya adalah karena itu memudahkan pembaca untuk menemukan bagian akhir switch. Alasan lain yang mungkin lebih baik adalah membuat Anda berpikir sejenak tentang apa yang harus dilakukan kode Anda ketika kondisinya tidak sesuai dengan harapan Anda. Apa pun alasannya, jika itu merupakan standar perusahaan, Anda harus mengikutinya kecuali ada alasan kedap udara untuk tidak melakukannya.

Jika Anda yakin bahwa Anda switchmenyertakan case untuk setiap kondisi yang memungkinkan, maka hal yang baik untuk dilakukan adalah memasukkan assertpernyataan dalam case default. Dengan begitu, ketika seseorang mengubah kode dan secara tidak sengaja menambahkan kondisi yang switchtidak Anda liput, mereka akan menekan assertdan menyadari bahwa mereka perlu mengatasi bagian kode itu.

Jika Anda switchhanya mencakup beberapa kondisi yang mungkin, tetapi tidak ada yang istimewa yang harus dilakukan untuk yang lain, Anda dapat membiarkan case default kosong. Adalah ide yang baik untuk menambahkan komentar dalam kasus itu untuk menunjukkan bahwa kasus default sengaja dikosongkan karena kondisi yang menabraknya tidak memerlukan pekerjaan apa pun untuk dilakukan.

Caleb
sumber
1
apa itu assert?
FLY
1
@ FLY Ini adalah kata kunci di Jawa dan biasanya makro di C, C ++, dll. Either way, pernyataan digunakan untuk menguji bahwa beberapa asumsi tetap benar dan melempar dan pengecualian atau sebaliknya menyebabkan kesalahan jika tidak.
Caleb
Saya telah mengedit komentar saya sebelumnya dengan tautan ke wikipedia
FLY
Anda seharusnya tidak meninggalkan kasing kosong. Jika sakelar Anda tidak mencakup semua kondisi yang memungkinkan, Anda harus menegaskan kondisi lain dalam kasing default Anda untuk alasan yang sama dengan yang Anda sarankan untuk menambahkan penegasan pada kasing default pada paragraf kedua Anda.
rold2007
12

Jika Anda "beralih" pada tipe enumerasi murni, berbahaya memiliki fallback default. Saat nanti Anda menambahkan nilai ke tipe enumerasi, kompiler akan menyoroti sakelar dengan nilai baru yang tidak tercakup. Jika Anda memiliki klausa default di sana, kompiler akan tetap diam, dan Anda mungkin melewatkannya.

Artur
sumber
1
+1 untuk menangkap masalah pada waktu kompilasi dan bukan pada saat dijalankan.
SylvainD
Saya bertanya-tanya bagaimana jawaban yang sepenuhnya menyesatkan dipilih dan diterima. Googling cepat menunjukkan bahwa kompiler java memiliki semacam peringatan. Kenapa Anda menunggu kesalahan saat runtime, kawan?
Artur
Saya tidak tahu tentang perilaku ini. Saya kode ideone sampel ideone.com/WvytWq menunjukkan sebaliknya. Dengan asumsi Anda mengatakan itu benar, apa yang terjadi jika seseorang menambahkan nilai ke tipe enumerasi, tetapi Anda tidak mengkompilasi ulang kode Anda?
emory
1
Jelas, nilai-nilai baru tidak ditangani oleh pernyataan switch tanpa case default. Tetapi jika Anda tidak mengkompilasi ulang implementasi Anda ketika antarmuka berubah, sistem build Anda benar-benar rusak.
Artur
9

Dalam banyak hal, pertanyaan ini adalah sama dengan sering bertanya Apakah saya perlu sebuah elseklausul pada akhir sebuah if/ else iftangga yang mencakup setiap pilihan .

Jawabannya adalah, secara sintaksis, tidak Anda tidak. Namun ada ...

Sebuah defaultklausul bisa berada di sana untuk (setidaknya) dua alasan:

  1. Sebagai penangan kesalahan - tentu, Seharusnya tidak pernah sampai di sini! adalah klaim yang dapat dibuat, tetapi Bagaimana jika itu terjadi? Korupsi data, atau bahkan lebih buruk, tidak ada validasi data adalah rute menuju kegagalan program jika tidak terjebak dengan benar. Dalam hal ini, seharusnya bukan klausa kosong!
  2. Desain / Cakupan Kode - bahkan dalam bentuk yang paling sederhana dari diagram alur, ada dua rute dari pernyataan-if, dan selalu otherwisedari case. Tidak ada alasan apapun untuk tidak memasukkan ini dalam kode sumber.

Filosofi saya selalu cukup sederhana - menilai skenario kasus terburuk dari dua opsi, dan mencari yang paling aman. Dalam hal klausa kosong elseatau default, pilihan kasus terburuk adalah:

  • Sertakan mereka: Tiga atau empat baris kode "berlebihan" tambahan.
  • Jangan Sertakan Mereka: Data jahat atau kondisi yang tidak terduga tidak terjebak, berpotensi menyebabkan kegagalan program.

Overdramatic? Mungkin ... tetapi kemudian perangkat lunak saya memiliki potensi membunuh orang jika terjadi kesalahan. Saya lebih suka tidak mengambil risiko itu.


Sebagai tambahan, pedoman MISRA-C {lihat profil untuk afiliasi} merekomendasikan defaultklausa untuk setiapswitch

Andrew
sumber
Bukan hanya di ujung tangga. Pertanyaannya adalah: apakah saya perlu elsesetelah if. Tetapi seperti yang Anda katakan, tidak, tidak.
ott--
Sebagai penangan kesalahan, saya sarankan formulir yang sedikit dimodifikasi yang menghindari default kosong. Sedangkan untuk membunuh orang, saya tidak berpikir itu benar-benar penting - orang-orang akan sama mati apakah Anda memiliki klausa standar atau tidak, tetapi akan membuatnya lebih mudah untuk mencari tahu mengapa mereka mati.
emory
Poin bagus, @emory - itu tidak terlalu jelas, apakah itu ... diedit :)
Andrew
6

Java tidak memaksa Anda untuk memiliki pernyataan 'default' tetapi itu adalah praktik yang baik untuk memiliki satu sepanjang waktu, bahkan jika kodenya mungkin tidak pernah tercapai (sekarang). Berikut beberapa alasan:

Dengan memiliki klausa default yang tidak terjangkau Anda menunjukkan pembaca kode Anda bahwa Anda mempertimbangkan nilai-nilai dan tahu apa yang Anda lakukan. Anda juga mengizinkan untuk perubahan di masa mendatang, misalnya, misalnya: nilai enum baru ditambahkan, sakelar seharusnya tidak mengabaikan nilai baru secara diam-diam; Anda bisa melempar Pengecualian ke sana atau melakukan sesuatu yang lain.

Untuk menangkap nilai tak terduga (jika Anda tidak mengaktifkan enum) yang diteruskan - mungkin lebih besar atau kurang dari apa yang Anda harapkan, misalnya.

Untuk menangani tindakan 'default' - di mana switch untuk perilaku khusus. Sebagai contoh, sebuah variabel dapat dideklarasikan di luar switch tetapi tidak diinisialisasi dan setiap kasus menginisialisasi ke sesuatu yang berbeda. Default dalam hal ini dapat menginisialisasi ke nilai default sehingga kode segera setelah switch tidak kesalahan / melempar pengecualian.

Bahkan jika Anda memutuskan untuk tidak memasukkan apa pun dalam default (tidak ada pengecualian, logging, dll.) Maka bahkan komentar yang mengatakan bahwa Anda telah mempertimbangkan fakta bahwa default tidak akan pernah terjadi dapat membantu keterbacaan kode Anda; tapi itu turun ke preferensi pribadi.

Deco
sumber
2

Saya juga akan menambahkan bahwa itu tergantung pada filosofi bahasa yang Anda gunakan. Di Erlang misalnya, di mana itu merupakan pendekatan umum untuk 'membiarkannya crash', Anda tidak akan mendefinisikan kasus default tetapi membiarkan casepernyataan Anda menimbulkan kesalahan jika terjadi situasi yang tidak dipenuhi.

Rodrigue
sumber
0

Anda harus selalu memiliki default kecuali Anda telah membuktikan dan secara permanen menutupi semua kasus. Tidak ada biaya apapun, dan itu merupakan jaminan terhadap kegagalan mempertahankan pernyataan peralihan Anda dalam program yang terus berkembang.

Jika Anda benar-benar yakin tidak peduli dengan kasus lain, default: break; // tidak peduli tapi default defaultnya harus seperti default: throw new Error ("value tak terduga");

Demikian juga, Anda tidak boleh "menerobos" konstruksi kasus nontrivial tanpa menambahkan komentar pada efek yang ingin Anda lewatkan. Java salah dalam tahap desain.

ddyer
sumber
-2

Mempertimbangkan

enum Gender
{
       MALE ,
       FEMALE ;
}

dan

void run ( Gender g )
{
      switch ( g )
      {
           case MALE :
                 // code related to males
                 break ;
           default :
                 assert Gender . FEMALE . equals ( g ) ;
                 // code related to females
                 break ;
      }
}

Saya berpendapat bahwa ini lebih unggul daripada memiliki kasus MALE, kasus FEMALE, dan kasus default yang melempar pengecualian.

Selama fase pengujian Anda, komputer akan memeriksa apakah g adalah PEREMPUAN. Selama produksi, cek akan dihilangkan. (Ya optimasi mikro!)

Lebih penting lagi, Anda akan mempertahankan tujuan Anda dari cakupan kode 100%. Jika Anda menulis case default yang melempar Exception, bagaimana Anda akan mengujinya?

emory
sumber
1
1. Tidak perlu optimasi mikro - eliminasi kode mati digunakan dalam kompiler selama 30 tahun terakhir dan itu akan dihilangkan oleh JIT. 2. Cakupan kode 100% biasanya tidak dianggap penting (di satu sisi cakupan 100% mungkin tidak menangkap semua kasus tepi, di lain tidak ada tes akan menangkap garis assert_not_reached pada program yang benar). Dalam hal ini tidak meninggalkan case default akan menyebabkan kesalahan kompiler. Di sisi lain - bagaimana Anda memeriksa apakah pernyataan itu berfungsi (Anda menggeser masalah dan menyembunyikannya dengan cakupan 100% alih-alih memiliki garis yang sama 'itu tidak akan terjadi, saya janji').
Maciej Piechotka
1
3. Kapan Gender . FEMALE . equals ( FEMALE ) ;evaluasi dilakukan false? Maksud Anda, Gender.FEMALE.equals (g)tetapi karena Anda dapat bergantung pada referensi untuk enum menjadi stabil, Anda cukup menulis g == Gender.FEMALE. 4. (Pendapat pribadi) kode seperti itu jauh lebih sulit dibaca dan akan menghasilkan kesalahan yang sedikit membingungkan.
Maciej Piechotka
@MaciejPiechotka tangkapan bagus tentang g. Ya, optimasi mikro adalah tidak bermanfaat, tetapi juga bukan kelemahannya. Cakupan kode 100% adalah manfaat jika itu salah satu tujuan Anda dan alat cakupan kode Anda tidak memeriksa pernyataan (yang seharusnya tidak).
emory
Lalu mengapa itu menjadi salah satu tujuan saya? Bagian yang 'menarik' harus diuji untuk semua kasus tepi (terlepas dari apakah mereka memetakan ke baris kode) dan bagian 'membosankan' dapat dengan mudah dilewati untuk menghemat waktu pengujian. Cakupan kode IMHO adalah metrik tes yang buruk.
Maciej Piechotka