Saya membaca pertanyaan ini di SO yang membahas beberapa perilaku umum yang tidak terdefinisi dalam C ++, dan saya bertanya-tanya: apakah Java juga memiliki perilaku yang tidak terdefinisi?
Jika itu masalahnya, lalu apa penyebab umum dari perilaku tidak terdefinisi di Jawa?
Jika tidak, maka fitur Java mana yang membuatnya bebas dari perilaku seperti itu dan mengapa versi C dan C ++ terbaru belum diimplementasikan dengan properti ini?
java
c++
c
undefined-behavior
Delapan
sumber
sumber
Jawaban:
Di Java, Anda dapat mempertimbangkan perilaku program yang disinkronkan secara salah, tidak terdefinisi.
Java 7 JLS menggunakan kata "tidak terdefinisi" sekali, dalam 17.4.8. Eksekusi dan Persyaratan Kausalitas :
Dokumentasi Java API menetapkan beberapa kasus saat hasil tidak ditentukan - misalnya, dalam Tanggal konstruktor (tidak digunakan) (tahun int, bulan int, hari int) :
Javadocs untuk ExecutorService.invokeAll (Koleksi) menyatakan:
Jenis perilaku "tidak terdefinisi" yang kurang formal dapat ditemukan misalnya di ConcurrentModificationException , di mana dokumen API menggunakan istilah "upaya terbaik":
Lampiran
Salah satu komentar pertanyaan merujuk pada sebuah artikel oleh Eric Lippert yang memberikan pengantar yang bermanfaat ke dalam hal-hal topik: Perilaku yang ditentukan implementasi .
Saya merekomendasikan artikel ini untuk alasan bahasa-agnostik, meskipun perlu diingat bahwa penulis menargetkan C #, bukan Java.
Di atas hanya liputan yang sangat singkat; artikel lengkap berisi penjelasan dan contoh untuk poin-poin yang disebutkan dalam kutipan ini; itu sangat berharga untuk dibaca. Misalnya, perincian yang diberikan untuk "faktor keenam" dapat memberikan satu wawasan tentang motivasi untuk banyak pernyataan dalam Java Memory Model ( JSR 133 ), membantu untuk memahami mengapa beberapa optimasi diizinkan, mengarah pada perilaku yang tidak ditentukan sementara yang lain dilarang, yang mengarah ke keterbatasan seperti yang terjadi sebelum dan persyaratan kausalitas .
sumber
Dari atas kepala saya, saya tidak berpikir ada perilaku yang tidak terdefinisi di Jawa, setidaknya tidak dalam arti yang sama seperti di C ++.
Alasan untuk ini adalah bahwa ada filosofi yang berbeda di belakang Jawa daripada di belakang C ++. Tujuan utama desain Java adalah untuk memungkinkan program berjalan tidak berubah di seluruh platform, demikian juga spesifikasi mendefinisikan semuanya dengan sangat eksplisit.
Sebaliknya, tujuan desain inti dari C dan C ++ adalah efisiensi: seharusnya tidak ada fitur (termasuk kemandirian platform) yang memerlukan biaya kinerja bahkan jika Anda tidak membutuhkannya. Untuk tujuan ini, spesifikasi sengaja tidak mendefinisikan beberapa perilaku karena mendefinisikan mereka akan menyebabkan kerja ekstra pada beberapa platform dan dengan demikian mengurangi kinerja bahkan untuk orang-orang yang menulis program khusus untuk satu platform dan menyadari semua keanehannya.
Bahkan ada contoh di mana Java dipaksa untuk secara surut memperkenalkan bentuk terbatas dari perilaku tidak terdefinisi untuk alasan itu: kata kunci tightfp diperkenalkan di Java 1.2 untuk memungkinkan perhitungan floating point untuk menyimpang dari mengikuti persis standar IEEE 754 seperti yang sebelumnya diminta oleh spec , karena melakukan itu memerlukan kerja ekstra dan membuat semua perhitungan floating-point lebih lambat pada beberapa CPU umum, sementara sebenarnya menghasilkan hasil yang lebih buruk dalam beberapa kasus.
sumber
int x=-1; foo(); x<<=1;
filsafat hiper-modern akan mendukung menulis ulangfoo
sehingga setiap jalan yang tidak keluar harus terjangkau. Ini, jikafoo
adalahif (should_launch_missiles) { launch_missiles(); exit(1); }
kompilator bisa (dan menurut beberapa orang harus) menyederhanakan yang untuk hanyalaunch_missiles(); exit(1);
. UB tradisional adalah eksekusi kode acak, tetapi dulu terikat oleh hukum waktu dan hubungan sebab akibat. UB yang lebih baik tidak terikat oleh keduanya.Java berusaha cukup keras untuk memusnahkan perilaku yang tidak terdefinisi, justru karena pelajaran dari bahasa sebelumnya. Sebagai contoh, variabel tingkat kelas diinisialisasi secara otomatis; variabel lokal tidak diinisialisasi otomatis karena alasan kinerja, tetapi ada analisis aliran data yang canggih untuk mencegah siapa pun menulis program yang dapat mendeteksi hal ini. Referensi bukan petunjuk, jadi referensi yang tidak valid tidak ada, dan dereferencing
null
menyebabkan pengecualian khusus.Tentu saja masih ada beberapa perilaku yang tidak sepenuhnya ditentukan, dan Anda dapat menulis program yang tidak dapat diandalkan jika Anda berasumsi demikian. Misalnya, jika Anda beralih ke yang normal (tidak diurutkan)
Set
, bahasa menjamin bahwa Anda akan melihat setiap elemen tepat satu kali, tetapi tidak dalam urutan yang Anda akan melihatnya. Urutan mungkin sama pada proses yang berurutan, atau mungkin berubah; atau mungkin tetap sama selama tidak ada alokasi lain yang terjadi, atau selama Anda tidak memperbarui JDK Anda, dll. Hampir tidak mungkin untuk menghilangkan semua efek seperti itu; misalnya, Anda harus secara eksplisit memesan atau mengacak semua operasi Koleksi, dan itu sama sekali tidak sebanding dengan tambahan kecil un-undefined-ness.sumber
Anda harus memahami "Perilaku Tidak Terdefinisi" dan asalnya.
Perilaku Tidak Terdefinisi berarti perilaku yang tidak didefinisikan oleh standar. C / C ++ memiliki terlalu banyak implementasi kompiler yang berbeda dan fitur tambahan. Fitur tambahan ini mengikat kode ke kompiler. Ini karena tidak ada pengembangan bahasa yang terpusat. Jadi beberapa fitur canggih dari beberapa kompiler menjadi "perilaku tidak terdefinisi".
Sedangkan di Jawa spesifikasi bahasa dikendalikan oleh Sun-Oracle dan tidak ada orang lain yang mencoba membuat spesifikasi dan dengan demikian tidak ada perilaku yang tidak terdefinisi.
Diedit Khusus menjawab Pertanyaan
sumber
Java pada dasarnya menghilangkan semua perilaku tidak terdefinisi yang ditemukan di C / C ++. (Sebagai contoh: Signed overflow integer, pembagian dengan nol, variabel tidak diinisialisasi, null pointer dereference, menggeser lebih dari lebar bit, bebas ganda, bahkan "tidak ada baris baru di akhir kode sumber".) Tetapi Java memiliki beberapa perilaku tidak jelas yang tidak jelas yang jarang ditemui oleh programmer.
Java Native Interface (JNI), suatu cara bagi Java untuk memanggil kode C atau C ++. Ada banyak cara untuk mengacaukan JNI, seperti membuat tanda tangan fungsi salah, membuat panggilan tidak sah ke layanan JVM, merusak memori, mengalokasikan / membebaskan barang secara tidak benar, dan banyak lagi. Saya telah membuat kesalahan ini sebelumnya, dan umumnya seluruh JVM crash ketika ada satu thread yang mengeksekusi kode JNI melakukan kesalahan.
Thread.stop()
, yang sudah usang. Mengutip:https://docs.oracle.com/javase/8/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html
sumber