8 Pertanyaan: Mengapa Java memiliki kesalahan kompilator "pernyataan tidak terjangkau"?

pertanyaan dibuat di Sun, Jul 30, 2017 12:00 AM

Saya sering menemukan ketika debugging suatu program itu mudah, (walaupun praktiknya bisa dibilang buruk) untuk memasukkan pernyataan kembali ke dalam blok kode. Saya mungkin mencoba sesuatu seperti ini di Java ....

 
class Test {
        public static void main(String args[]) {
                System.out.println("hello world");
                return;
                System.out.println("i think this line might cause a problem");
        }
}

tentu saja, ini akan menghasilkan kesalahan kompiler.

  

Test.java:7: pernyataan yang tidak terjangkau

Saya bisa mengerti mengapa peringatan dapat dibenarkan karena memiliki kode yang tidak digunakan adalah praktik yang buruk. Tapi saya tidak mengerti mengapa ini perlu menghasilkan kesalahan.

Apakah ini hanya Java yang mencoba menjadi Nanny, atau adakah alasan yang bagus untuk membuat ini kesalahan kompiler?

    
79
  1. Java juga tidak sepenuhnya konsisten tentang ini. Untuk beberapa aliran kontrol yang menyebabkan kode mati, tetapi Java tidak mengeluh. Bagi orang lain, memang demikian. Menentukan kode apa yang mati adalah masalah yang tidak dapat dihitung. Saya tidak tahu mengapa Java memutuskan untuk memulai sesuatu yang tidak dapat diselesaikan.
    2013-03-21 20: 11: 59Z
8 Jawaban                              8                         

Karena kode yang tidak terjangkau tidak berarti bagi kompiler. Sementara membuat kode bermakna bagi orang-orang adalah yang terpenting dan lebih sulit daripada membuatnya bermakna bagi seorang kompiler, kompiler adalah konsumen penting kode. Perancang Jawa mengambil sudut pandang bahwa kode yang tidak berarti bagi kompiler adalah kesalahan. Sikap mereka adalah bahwa jika Anda memiliki beberapa kode yang tidak dapat dijangkau, Anda telah membuat kesalahan yang perlu diperbaiki.

Ada pertanyaan serupa di sini: Kode yang tidak dapat dijangkau: kesalahan atau peringatan? , di mana penulis mengatakan, "Secara pribadi saya sangat merasa itu harus menjadi kesalahan: jika programmer menulis sepotong kode, itu harus selalu dengan maksud untuk benar-benar menjalankannya dalam beberapa skenario." Jelas para perancang bahasa Jawa setuju.

Apakah kode yang tidak terjangkau harus mencegah kompilasi adalah pertanyaan yang tidak akan pernah ada konsensus. Tapi inilah mengapa desainer Java melakukannya.


Sejumlah orang di komentar menunjukkan bahwa ada banyak kelas kode yang tidak dapat diakses yang tidak dapat dikompilasi oleh Java. Jika saya memahami konsekuensi Gödel dengan benar, tidak ada kompiler yang dapat menangkap semua kelas kode yang tidak terjangkau.

Unit test tidak dapat menangkap setiap bug. Kami tidak menggunakan ini sebagai argumen terhadap nilai mereka. Demikian juga kompiler tidak dapat menangkap semua kode yang bermasalah, tetapi masih berharga untuk mencegah kompilasi kode buruk ketika itu bisa.

Perancang bahasa Jawa menganggap kode yang tidak dapat dijangkau sebagai kesalahan. Jadi mencegah kompilasi jika memungkinkan adalah masuk akal.


(Sebelum Anda downvote: pertanyaannya bukanlah apakah Java harus memiliki kesalahan kompilator pernyataan yang tidak dapat dijangkau. Pertanyaannya adalah mengapa Anda pikir Java membuat keputusan desain yang salah.)

    
61
2017-05-23 11: 54: 53Z
  1. Jelas para perancang bahasa Jawa setuju "Perancang bahasa Jawa" adalah manusia dan rentan terhadap kesalahan juga. Secara pribadi, saya merasa pihak lain dalam diskusi yang Anda referensikan memiliki argumen yang jauh lebih kuat.
    2010-09-25 21: 30: 17Z
  2. @ Gabe: Karena itu tidak berbahaya - hampir pasti merupakan kesalahan. Entah Anda telah meletakkan kode Anda di tempat yang salah, atau salah paham bahwa Anda telah menulis pernyataan Anda sedemikian rupa sehingga beberapa di antaranya tidak dapat dijangkau. Membuat ini sebagai kesalahan mencegah penulisan kode yang salah, dan jika Anda ingin sesuatu di tempat yang tidak terjangkau dalam kode Anda dibaca oleh pengembang lain (satu-satunya pemirsa untuk kode yang tidak terjangkau), gunakan komentar sebagai gantinya.
    2010-09-25 23: 27: 00Z
  3. SamStephens: Melihat bagaimana metode yang tidak dipanggil dan variabel yang tidak digunakan pada dasarnya semua bentuk kode yang tidak dapat dijangkau. Mengapaizinkan beberapa bentuk dan bukan yang lain? Khususnya, mengapa tidak mengizinkan mekanisme debugging yang bermanfaat?
    2010-09-26 01: 25: 30Z
  4. Bukankah komentar juga tidak dapat dijangkau? Dalam pikiran saya, kode yang tidak terjangkau sebenarnya adalah bentuk komentar (ini yang saya coba lakukan sebelumnya, dll). Tetapi mengingat komentar "asli" juga tidak "dapat dijangkau" ... mungkin mereka juga harus meningkatkan kesalahan ini;)
    2012-01-30 00: 50: 49Z
  5. Masalahnya adalah mereka (desainer bahasa java) tidak konsisten dengan ini. Jika ada analisis aliran aktual, itu sepele untuk menyadari bahwa return; System.out.println(); dan if(true){ return; } System.out.println(); keduanya dijamin memiliki perilaku yang sama, tetapi satu adalah kesalahan kompilasi, dan yang lainnya tidak. Jadi, ketika saya sedang debugging, dan saya menggunakan metode ini untuk "mengomentari" kode sementara, itulah cara saya melakukannya. Masalah dengan mengomentari kode adalah Anda harus menemukan tempat yang tepat untuk menghentikan komentar Anda, yang mungkin memerlukan waktu lebih lama daripada membuang return; cepat nyata.
    2012-09-19 21: 48: 10Z

Tidak ada alasan pasti mengapa pernyataan yang tidak terjangkau harus dilarang; bahasa lain memungkinkan mereka tanpa masalah. Untuk kebutuhan spesifik Anda, ini adalah trik yang biasa:

 
if (true) return;

Tampaknya tidak masuk akal, siapa pun yang membaca kode akan menebak bahwa itu pasti dilakukan dengan sengaja, bukan kesalahan ceroboh dengan membiarkan sisa pernyataan tidak dapat dijangkau.

Java memiliki sedikit dukungan untuk "kompilasi bersyarat"

http://java.sun.com/docs /books /jls /third_edition /html /statement.html # 14.21

 
if (false) { x=3; }
     

tidak menghasilkan waktu kompilasi   kesalahan. Kompilator pengoptimal mungkin   sadari bahwa pernyataan x = 3; akan   tidak pernah dieksekusi dan dapat memilih untuk   hilangkan kode untuk pernyataan itu dari   file kelas yang dihasilkan, tetapi file   pernyataan x = 3; tidak dianggap sebagai   "Tidak terjangkau" dalam arti teknis   ditentukan di sini.

     

Alasan untuk ini berbeda   perawatan adalah untuk memungkinkan programmer   tentukan "flag variabel" seperti:

 
static final boolean DEBUG = false;
     

dan kemudian tulis kode seperti:

 
if (DEBUG) { x=3; }
     

Idenya adalah itu harus mungkin   untuk mengubah nilai DEBUG dari   salah ke benar atau dari benar ke salah   dan kemudian kompilasi kodenya dengan benar   tanpa perubahan lain pada program   teks.

    
46
2016-01-04 15: 24: 50Z
  1. Masih tidak mengerti mengapa Anda repot-repot dengan trik yang Anda tampilkan. Kode yang tidak dapat dijangkau tidak berarti bagi kompiler. Jadi satu-satunya pemirsa untuk itu adalah pengembang. Gunakan komentar. Meskipun saya kira jika Anda menambahkan pengembalian sementara, menggunakan solusi Anda mungkin lebih cepat daripada hanya mengembalikan, dan mengomentari kode berikut.
    2010-09-26 03: 07: 29Z
  2. @ SamStephens Tetapi setiap kali Anda ingin berganti Anda harus mengingat semua tempat di mana Anda harus mengomentari kode dan di mana Anda harus melakukan yang sebaliknya. Anda harus membaca seluruh file, mengubah kode sumber, mungkin membuat beberapa kesalahan halus setiap saat dan bukannya hanya mengganti "benar" dengan "salah" di satu tempat. Saya pikir lebih baik untuk kode logika switching sekali dan tidak menyentuhnya kecuali diperlukan.
    2012-06-21 19: 02: 35Z
  3. "siapa pun yang membaca kode akan menebak bahwa itu pasti dilakukan dengan sengaja". Ini persis masalah menurut saya, orang tidak seharusnya menebak, mereka harus mengerti. Kode yang diingat adalah komunikasi dengan orang, bukan hanya instruksi untuk komputer. Jika itu selain sangat sementara, Anda harus menggunakan konfigurasi menurut saya. Melihat apa yang Anda perlihatkan di atas, if (true) return; tidak menunjukkan MENGAPA Anda melewatkan logika, sedangkan if (BEHAVIOURDISABLED) return; mengomunikasikan niat.
    2012-06-23 02: 47: 51Z
  4. IniTrik ini sangat berguna untuk debugging. Saya sering menambahkan jika (benar) kembali untuk menghilangkan "sisa" dari suatu metode yang mencoba mencari tahu di mana itu gagal. Ada beberapa cara lain, tetapi ini bersih dan cepat - tetapi ini bukan sesuatu yang harus Anda periksa.
    2014-01-16 17: 56: 12Z

Itu Nanny. Saya merasa. Net mendapatkan yang ini - itu memunculkan peringatan untuk kode yang tidak dapat dijangkau, tetapi bukan kesalahan. Adalah baik untuk diperingatkan tentang hal itu, tetapi saya melihat tidak ada alasan untuk mencegah kompilasi (terutama selama sesi debugging di mana itu bagus untuk melemparkan kembali untuk mem-bypass beberapa kode).

    
18
2010-09-25 21: 35: 52Z
  1. java dirancang lebih awal, setiap byte dihitung pada waktu itu, floppy disk masih berteknologi tinggi.
    2010-09-25 22: 58: 32Z
  2. Untuk debug awal lebih cepat, dibutuhkan lima detik lagi untuk mengomentari baris setelah pengembalian awal Anda. Harga kecil untuk bermain untuk bug dicegah dengan membuat kode yang tidak terjangkau menjadi kesalahan.
    2010-09-25 23: 31: 57Z
  3. juga mudah bagi kompiler untuk mengecualikan kode yang tidak terjangkau. tidak ada alasan untuk memaksa pengembang untuk melakukannya.
    2010-09-26 03: 42: 11Z
  4. @ SamStephens tidak jika Anda sudah memiliki komentar di sana, karena komentar tidak menumpuk, tidak perlu repot untuk menyelesaikan ini dengan komentar.
    2013-11-29 00: 21: 50Z
  5. @ SamStephens Kode yang dikomentari tidak memperbaiki dengan baik.
    2014-07-31 23: 03: 23Z

Saya baru saja memperhatikan pertanyaan ini, dan ingin menambahkan $.02 saya untuk ini.

Dalam kasus Java, ini sebenarnya bukan opsi. Kesalahan "kode tidak dapat dijangkau" tidak berasal dari fakta bahwa pengembang JVM berpikir untuk melindungi pengembang dari apa pun, atau menjadi lebih waspada, tetapi dari persyaratan spesifikasi JVM.

Baik kompiler Java, dan JVM, menggunakan apa yang disebut "tumpukan peta" - informasi yang pasti tentang semua item pada stack, sebagaimana dialokasikan untuk metode saat ini. Jenis masing-masing dan setiap slot tumpukan harus diketahui, sehingga instruksi JVM tidak salah memperlakukan item dari satu jenis untuk jenis lainnya. Ini sebagian besar penting untuk mencegah memiliki nilai numerik yang pernah digunakan sebagai pointer. Mungkin saja, menggunakan rakitan Java, untuk mencoba mendorong /menyimpan nomor, tetapi kemudian pop /memuat referensi objek. Namun, JVM akan menolak kode ini selama validasi kelas, - saat itulah tumpukan peta dibuat dan diuji untuk konsistensi.

Untuk memverifikasi peta tumpukan, VM harus berjalan melalui semua jalur kode yang ada dalam suatu metode, dan memastikan bahwa tidak peduli jalur kode mana yang akan dieksekusi, data tumpukan untuk setiap instruksi setuju dengan apa yang sebelumnya kode telah mendorong /disimpan di tumpukan. Jadi, dalam kasus sederhana:

 
Object a;
if (something) { a = new Object(); } else { a = new String(); }
System.out.println(a);

pada baris 3, JVM akan memeriksa bahwa kedua cabang 'jika' hanya disimpan ke dalam (yang hanya lokal var # 0) sesuatu yang kompatibel dengan Object (karena begitulah kode dari baris 3 dan seterusnya akan memperlakukan lokal var # 0).

Ketika kompiler mencapai kode yang tidak dapat dijangkau, ia tidak mengetahui status stack pada saat itu, sehingga tidak dapat memverifikasi statusnya. Itu tidak bisa mengkompilasi kode lagi pada saat itu, karena tidak bisa melacak variabel lokal juga, jadi alih-alih meninggalkan ambiguitas ini di file kelas, itu menghasilkan kesalahan fatal.

Tentu saja kondisi sederhana seperti if (1<2) akan membodohinya, tetapi itu tidak benar-benar membodohi - itu memberikan cabang potensial yang dapat mengarah ke kode, dan setidaknya kompilator dan VM dapat menentukan, bagaimana item tumpukan dapat mulai digunakan sejak saat itu.

P.S. Saya tidak tahu apa yang dilakukan .NET dalam hal ini, tetapi saya percaya itu akan gagal dikompilasi juga. Ini biasanya tidak akan menjadi masalah untuk kompiler kode mesin (C, C ++, Obj-C, dll.)

14
2013-08-01 21: 48: 37Z
  1. Seberapa agresif sistem peringatan kode mati Java? Bisakah itu dinyatakan sebagai bagian dari tata bahasa (mis. { [flowingstatement;]* } = > flowingstatement, { [flowingstatement;]* stoppingstatement; } = > stoppingstatement, return = > stoppingstatement, if (condition) stoppingstatement; else stoppingstatement = > stoppingstatement; dll?
    2013-08-05 23: 35: 55Z
  2. Saya tidak pandai tata bahasa, tapi saya yakin begitu, ya. Namun, "berhenti" bisa bersifat lokal, misalnya pernyataan "istirahat" di dalam satu lingkaran. Juga, akhir metode adalah pernyataan berhenti implisit untuk tingkat metode, jika metode tersebut batal. 'throw' juga akan menjadi pernyataan penghentian yang eksplisit.
    2013-08-06 22: 09: 13Z
  3. Apa yang akan dikatakan standar Java tentang sesuatu seperti void blah() { try {return;} catch (RuntimeError ex) { } DoSomethingElse(); } Apakah Java akan berkotek bahwa tidak mungkin blok try dapat benar-benar keluar melalui pengecualian, atau apakah akan menemukan jenis apa pun pengecualian tidak dicentang dapat terjadi dalam blok try apa pun?
    2013-08-06 22: 37: 27Z
  4. Cara terbaik untuk mengetahuinya adalah dengan mencoba dan mengompilasinya. Tetapi kompiler bahkan memungkinkan untuk mencoba /menangkap pernyataan kosong. Namun, setiap instruksi JVM secara teoritis dapat melempar pengecualian, jadi blok coba dapat keluar begitu. Tetapi saya tidak yakin bagaimana ini relevan dengan pertanyaan ini.
    2013-08-06 23: 49: 40Z
  5. Pada dasarnya, pertanyaannya adalah apakah satu-satunya pernyataan "tidak terjangkau" yang terlarang adalah yang dapat diidentifikasi sebagai tidak dapat dijangkau berdasarkan penguraian, tanpa harus benar-benar mengevaluasi ekspresi apa pun, atau apakah standar dapat melarang pernyataan yang tidak terjangkau seperti if (constantThatEqualsFive < 3) {doSomething;};.
    2013-08-06 23: 57: 34Z

Salah satu tujuan dari kompiler adalah untuk mengesampingkan kelas kesalahan. Beberapa kode yang tidak terjangkau ada di sana secara tidak sengaja, ada baiknya javac mengesampingkan kelas kesalahan tersebut pada waktu kompilasi.

Untuk setiap aturan yang menangkap kode yang salah, seseorang akan menginginkan kompiler untuk menerimanya karena mereka tahu apa yang mereka lakukan. Itulah penalti memeriksa kompiler, dan mendapatkan keseimbangan yang tepat adalah salah satu poin rumit dari desain bahasa. Bahkan dengan pemeriksaan ketat sekalipun, masih ada sejumlah program tak terbatas yang dapat ditulis, jadi segalanya tidak seburuk itu.

    
5
2010-09-25 22: 02: 16Z

Meskipun saya pikir kesalahan kompiler ini adalah hal yang baik, ada cara Anda bisa mengatasinya. Gunakan kondisi yang Anda tahu akan benar:

 
public void myMethod(){

    someCodeHere();

    if(1 < 2) return; // compiler isn't smart enough to complain about this

    moreCodeHere();

}

Kompiler tidak cukup pintar untuk mengeluh tentang itu.

    
5
2010-09-25 22: 28: 38Z
  1. Pertanyaannya di sini adalah mengapa? Kode yang tidak dapat dijangkau tidak berarti bagi kompiler. Jadi satu-satunya pemirsa untuk itu adalah pengembang. Gunakan komentar.
    2010-09-25 21: 43: 25Z
  2. Jadi saya mendapatkan downvotes karena saya setuju dengan cara orang-orang java merancang kompilasi mereka? Astaga ...
    2010-09-25 22: 14: 12Z
  3. Anda mendapat downvotes karena tidak menjawab pertanyaan yang sebenarnya. Lihat komentar SamStephens.
    2010-09-25 22: 37: 33Z
  4. javac pasti dapat menyimpulkan bahwa 1<2 benar, dan sisa metode ini tidak harus dimasukkan dalam kode byte. aturan "pernyataan yang tidak terjangkau" harus jelas, diperbaiki, dan terlepas dari kecerdasan kompiler.
    2010-09-25 22: 49: 13Z
  5. @ Sam dengan sikap itu, Anda harus menurunkan 50% jawaban terbaik dari situs ini (dan saya tidak mengatakan bahwa jawaban saya ada di antara mereka ). Bagian besar dari menjawab pertanyaan tentang SO, seperti dalam situasi konsultasi TI lainnya, adalah mengidentifikasi pertanyaan sebenarnya (atau pertanyaan sampingan yang relevan) dari pertanyaan yang diberikan.
    2010-09-26 12: 33: 11Z

Tentunya hal yang baik untuk mengeluh semakin ketat kompilernya adalah lebih baik, sejauh memungkinkan Anda untuk melakukan apa yang Anda butuhkan. Biasanya harga kecil untuk membayar adalah mengomentari kode, keuntungannya adalah ketika Anda mengkompilasi kode Anda berfungsi. Contoh umum adalah Haskell tentang orang-orang yang berteriak sampai mereka menyadari bahwa tes /debugging mereka adalah tes utama saja dan pendek. Saya pribadi di Jawa hampir tidak melakukan debug saat sedang (sebenarnya sengaja) tidak perhatian.

    
0
2010-09-25 22: 35: 14Z

Jika alasan untuk mengizinkan if (aBooleanVariable) return; someMoreCode; adalah untuk mengizinkan bendera, maka fakta bahwa if (true) return; someMoreCode; tidak menghasilkan kesalahan waktu kompilasi tampaknya seperti inkonsistensi dalam kebijakan menghasilkan pengecualian CodeNotReachable, karena kompiler 'tahu' bahwa true bukan bendera ( bukan variabel).

Dua cara lain yang mungkin menarik, tetapi tidak berlaku untuk mematikan bagian dari kode metode serta if (true) return:

Sekarang, alih-alih mengatakan if (true) return; Anda mungkin ingin mengatakan assert false dan menambahkan -ea OR -ea package OR -ea className ke argumen jvm. Poin yang baik adalah bahwa ini memungkinkan untuk beberapa rincian dan memerlukan menambahkan parameter tambahan untuk permintaan jvm sehingga tidak perlu menetapkan bendera DEBUG dalam kode, tetapi dengan menambahkan argumen saat runtime, yang berguna ketika target bukan mesin pengembang dan kompilasi ulang & mentransfer bytecode membutuhkan waktu.

Ada juga cara System.exit(0), tetapi ini mungkin berlebihan, jika Anda menaruhnya di Jawa dalam JSP maka itu akan menghentikan server.

Terlepas dari itu Java mendesain bahasa 'pengasuh', saya lebih suka menggunakan sesuatu yang asli seperti C /C ++ untuk kontrol lebih lanjut.

    
0
2012-06-08 21: 55: 55Z
  1. Mengubah sesuatu dari variabel static final yang diatur dalam blok inisialisasi statis menjadi variabel static final yang diatur dalam deklarasi tidak boleh merupakan perubahan besar. Sangat masuk akal bahwa ketika sebuah kelas pertama kali ditulis mungkin terkadang tidak dapat melakukan sesuatu (dan tidak diketahui sampai run-time apakah itu dapat melakukannya atau tidak), tetapi versi kelas yang lebih baru mungkin dapat melakukannya. lakukan tindakan itu selalu. Mengubah myClass.canFoo ke konstanta seharusnya membuat if (myClass.canFoo) myClass.Foo(); else doSomethingElse(); lebih efisien - jangan hancurkan.
    2013-12-30 19: 25: 41Z
sumber ditempatkan sini