Tipe null-restricted dan nullable
(bugs.openjdk.org)- Java sedang menyiapkan fitur bahasa preview yang menambahkan penanda nullness pada tipe:
Foo!menolaknull, sedangkanFoo?sengaja mengizinkannya Footanpa penanda tetap memiliki nullness unspecified, sehingga kompatibel dengan kode lama; konversi antar tipe dengan nullness berbeda dapat disertai peringatan atau pemeriksaan runtime- Field dan array yang menolak
nulltidak dapat memakai nilai defaultnull, sehingga field instans harus mendapat definite assignment sebelum pemanggilansuper(...), dan array memerlukan nilai awal komponen - Jika
nulldipersempit menjadiFoo!, akan terjadiNullPointerException; pada jalur penyimpanan array dan field, kontaminasi dicegah dengan ArrayStoreException dan FieldStoreException - Ini menjadi dasar agar optimisasi seperti flattening value class Valhalla dapat memercayai eksklusi
null; penerapan ke pustaka standar atau reinterpretasi otomatis kode lama saat ini bukan tujuan
Fitur preview untuk menyatakan nullness pada tipe Java
- Menambahkan penanda nullness pada tipe Java untuk menyatakan apakah himpunan nilai tipe tersebut mencakup
null Foo!adalah tipe null-restricted, yang mengecualikannulldari himpunan nilainyaFoo?adalah tipe nullable, yang secara sengaja memasukkannullke dalam himpunan nilainyaFootanpa penanda memiliki nullness unspecified;nulldapat muncul, tetapi tidak diketahui apakah keberadaannya disengaja- Fitur ini adalah fitur preview yang diaktifkan dengan flag kompilasi dan runtime
--enable-preview
Tujuan dan non-tujuan
- Menyatakan apakah tipe referensi Java mengharapkan
null, serta menyediakan peringatan dan pemeriksaan untuk konversi antar tipe dengan perbedaan nullness - Tetap kompatibel dengan kode Java yang ada, dan harus dapat diperkenalkan secara bertahap tanpa menimbulkan inkompatibilitas source maupun binary
- Variabel bertipe yang menolak
nullharus diinisialisasi sebelum pertama kali dibaca, dan penolakannulldipaksakan saat runtime bahkan pada kelas yang dikompilasi terpisah - Menyediakan metadata dan jaminan integritas agar optimisasi runtime seperti flattening value class Valhalla dapat memercayai tipe null-restricted
- Hal-hal berikut saat ini bukan tujuan
- Tidak otomatis menafsirkan ulang kode lama
- Tidak menjadikan semua kemungkinan
nullsebagai error kompilasi - Tidak menambahkan bentuk nullable pada tipe primitif seperti
int - Tidak menerapkan ekstensi bahasa ke pustaka standar pada tahap saat ini
Mengapa diperlukan
- Variabel
Stringdi Java dapat berisi referensi ke objekStringataunull, tetapi tidak ada cara di tingkat bahasa untuk menyatakan mana yang dimaksud - Banyak program berasumsi tidak ada
null, tetapi perlu upaya tambahan untuk menegakkan hal ini secara konsisten dalam spesifikasi Javadoc dan kode implementasi - Jika ekspektasi ini dilanggar, nilai
nulldapat mengalir di dalam kode implementasi lalu memicu exception di titik yang jauh dari bug asalnya - Jika developer menyatakan niat bahwa
nullditolak atau diizinkan sebagai bagian dari tipe, feedback waktu kompilasi dan pemeriksaan runtime membantu menemukannulltak terduga lebih dini - Dalam Valhalla, variabel bertipe value class dapat dioptimalkan menjadi representasi flattened dari nilai, tetapi jika bit tambahan diperlukan untuk mengenkode
null, penggunaan memori dapat meningkat atau optimisasi penyimpanan tidak dapat dilakukan - Dalam Amber, nullness kandidat pattern matching dapat memengaruhi penilaian exhaustiveness pada
switch, dan nullness type pattern dapat memengaruhi apakahnullikut cocok
Sintaks penanda nullness dan struktur tipe
- Nullness diperlakukan sebagai bagian intrinsik dari tipe; karena
Foo?danFoomemiliki nullness berbeda, keduanya adalah tipe yang berbeda - Baik tipe array maupun tipe komponen array dapat memiliki penanda nullness
Foo?[]!adalah tipe array yang array-nya sendiri null-restricted, sedangkan komponennya adalahFoonullable- Pada array multidimensi, penanda dapat ditempatkan setelah setiap pasangan kurung siku, dan secara konvensi dibaca dari kiri ke kanan, dari bagian luar ke bagian dalam
- Tipe berparameter dan argumen tipe juga dapat memiliki penanda nullness
Predicate!<Foo?>adalahPredicatenull-restricted, dengan argumen tipeFoonullable
- Untuk menyatakan tipe null-restricted atau nullable,
!atau?harus muncul secara eksplisit di source - Di masa mendatang, dapat dipertimbangkan cara menafsirkan semua tipe dalam kelas atau unit kompilasi sebagai null-restricted secara default dan memakai
?hanya sebagai pengecualian, tetapi detailnya merupakan pekerjaan terpisah
Aturan inisialisasi field dan array
- Dalam Java yang ada, nilai default untuk field bertipe referensi dan komponen array adalah
null, tetapi ini tidak sesuai sebagai nilai awal untuk field atau komponen array null-restricted - Field dan array null-restricted harus selalu diinisialisasi oleh program sebelum dibaca
- Jika field instans null-restricted tidak memiliki initializer, field itu harus mendapat definite assignment sebelum pemanggilan
super(...)eksplisit atau implisit di setiap konstruktor- Flexible Constructor Bodies JEP memungkinkan penulisan kode inisialisasi yang diperlukan di bagian awal konstruktor
- Dalam early construction context ini, operasi yang berisiko mereferensikan
thisatau membaca field yang belum diinisialisasi tidak diizinkan
- Jika field instans null-restricted memiliki initializer, initializer itu dijalankan pada awal setiap konstruktor sebelum pemanggilan
super(...)- Konstruktor yang memanggil
this(...)adalah kasus khusus yang tidak menjalankan initializer, seperti aturan yang ada
- Konstruktor yang memanggil
- Field statis null-restricted harus mendapat definite assignment sebelum semua initializer statis dan blok inisialisasi kelas berakhir
- Jika kelas lain mencoba membaca field tersebut selama inisialisasi kelas, pemeriksaan runtime mendeteksi pembacaan dini dan melempar exception
- Array dengan tipe komponen null-restricted harus menyediakan nilai awal untuk setiap komponen dalam ekspresi pembuatan array
- Semua nilai dapat dicantumkan dengan array initializer
- Sintaks ringkas baru juga dimungkinkan, tetapi sintaksnya masih TBD
Nullness ekspresi dan konversi nullness
- Compiler Java menentukan nullness semua ekspresi selama proses type checking
- Nullness referensi variabel berasal dari deklarasi variabel, dan nullness pemanggilan metode berasal dari tipe return metode yang dirujuk
- Literal
nullbersifat nullable - Sebagian besar ekspresi bertipe referensi lainnya bersifat null-restricted
- Termasuk literal, konkatenasi string,
this, pembuatan instans kelas, pembuatan array, method reference, dan ekspresi lambda
- Termasuk literal, konkatenasi string,
- Konversi nullness diizinkan dalam konteks assignment, invocation, dan casting
- Widening nullness conversion mencakup berikut ini
Foo!→Foo?Foo!→FoounspecifiedFoo?→FoounspecifiedFoounspecified →Foo?
- Narrowing nullness conversion mencakup berikut ini
Foo?→Foo!Foounspecified →Foo!
- Narrowing nullness conversion dilakukan otomatis oleh compiler, mirip dengan unboxing conversion, tetapi saat runtime dilakukan pemeriksaan dinamis yang dapat menyebabkan
NullPointerException - Upaya mengonversi literal
nullsecara langsung ke tipe null-restricted adalah error waktu kompilasi
Pemeriksaan runtime dan exception
- Saat runtime, jika nilai
nullmengalami narrowing nullness conversion menjadi tipe null-restricted, NullPointerException terjadi - Narrowing nullness conversion yang tidak tampak eksplisit dalam source code juga dapat terjadi selama eksekusi runtime
- Array yang dialokasikan dengan tipe komponen null-restricted menolak nilai
nullmelalui pemeriksaan penyimpanan array biasa, meskipun di source code diperlakukan sebagai tipe yang kurang spesifik- Kegagalan konversi ini memicu ArrayStoreException
- Jika field yang saat kompilasi belum null-restricted kemudian menjadi null-restricted melalui kompilasi terpisah, field store check baru menolak penyimpanan
null- Kegagalan konversi ini memicu FieldStoreException
- Pada pemanggilan metode dalam relasi overriding, konversi ke tipe pemanggilan parameter metode super dapat diikuti oleh konversi ke tipe parameter metode overriding
- Nilai return metode juga dapat dikonversi ke tipe return metode yang dideklarasikan, lalu dikonversi ke tipe return yang diharapkan di titik pemanggilan
Generics, argumen tipe, dan overriding
- Penggunaan type variable juga dapat diberi penanda nullness;
T!adalah tipe null-restricted danT?adalah tipe nullable - Tipe type variable null-restricted dan nullable menegaskan nullness tertentu di dalam kode generik
- Tipe yang digunakan sebagai argumen tipe juga dapat menyatakan nullness, dan penanda nullness yang ditempelkan pada tipe type variable menimpa nullness yang ditegaskan pada argumen tipe
- Di dalam implementasi erased dari API generik, pembatasan null tidak dapat dipaksakan
- Namun cast implisit biasa yang terjadi pada batas API generik memaksakan argumen tipe null-restricted saat runtime
- Demi interoperabilitas, nullness di dalam argumen tipe tidak dipaksakan secara kuat
Predicate<String!>dapat dikonversi menjadiPredicate<String>atauPredicate<String?>- unchecked nullness conversion seperti ini dapat menimbulkan peringatan
- Perubahan nullness tipe komponen array juga diizinkan sebagai unchecked nullness conversion, dan dalam kondisi apa pemeriksaan runtime dilakukan masih TBD
- Dalam penentuan kesamaan signature metode, nullness diabaikan
- Sebuah metode dapat meng-override metode lain meskipun nullness parameter dan tipe return tidak cocok
- Ketidaksesuaian seperti ini bisa umum terjadi jika API yang berbeda memperkenalkan penanda nullness secara independen
- Nullness tidak memengaruhi applicability metode dan tidak dapat menyebabkan kegagalan inferensi argumen tipe, tetapi dapat memengaruhi nullness yang diinferensikan untuk tipe return metode generik
- Detail algoritme inferensi masih TBD
Peringatan dan error compiler
- Menjadikan suatu tipe null-restricted dapat menimbulkan error waktu kompilasi baru
- Jika field atau array bertipe tersebut belum diinisialisasi
- Jika ada upaya mengonversi literal
nullke tipe tersebut - Membandingkan literal
nulldengan ekspresi bertipe null-restricted juga dapat menjadi error waktu kompilasi
- Dalam situasi lain, analisis nullness bersifat pendukung dan tidak menimbulkan error waktu kompilasi
javacmenyediakan peringatan untuk menghindari error runtime, dan IDE serta alat analisis lain dianjurkan mengikuti arah yang sama- Kemungkinan penyebab peringatan meliputi
- Narrowing nullness conversion, termasuk yang berasal dari tipe
? - Penggunaan ekspresi bertipe
?untuk akses member atau operasi lain yang null-hostile - Nullness argumen tipe yang tidak konsisten dengan bound
- Nullness parameter metode atau return yang tidak cocok dengan metode yang di-override
- Unchecked conversion yang mengubah nullness tipe
- Narrowing nullness conversion, termasuk yang berasal dari tipe
File kelas, refleksi, dan perubahan pendukung
- Sebagian besar penggunaan penanda null dihapus dari file
class, dan konversi runtime pendamping direpresentasikan langsung dalam bytecode - Sintaks atribut
Signaturediperbarui agar mengizinkan!dan?di dalam tipe - Nullness tidak dienkode dalam descriptor metode dan field
- Untuk mencegah kontaminasi field, atribut baru
NullRestrictedmenandai bahwa field tidak mengizinkan nilainull- Field ini juga harus ditandai
ACC_STRICT, dan harus diinisialisasi secara ketat - Verifier memastikan semua field instans dengan strict initialization sudah di-assign saat konstruktor melakukan pemanggilan
super(...) - Setiap upaya menulis ke field memeriksa nilai
null, dan jika ditemukan akan melemparFieldStoreException
- Field ini juga harus ditandai
- Pembuatan array null-restricted tidak didukung oleh instruksi
anewarray, dan harus dilakukan melalui pemanggilan Reflection API - Tidak ada literal
Foo!.classatauFoo?.class, dan tidak ada instansjava.lang.Classterkait - RuntimeType API baru mendeskripsikan himpunan tipe yang dipaksakan saat runtime dalam pemeriksaan penyimpanan array dan field, termasuk varian null-restricted dari semua tipe class dan interface
- API
Fieldmendukung pengambilanRuntimeTypefield, dan nilai ini dapat berbeda dari hasilgetType - API
Arraymendukung variannewInstanceyang menyatakan tipe komponen denganRuntimeType- Varian ini juga mengizinkan pemberian nilai awal komponen array
- Upaya membuat array null-restricted tanpa nilai awal ditolak
- Deserialisasi tradisional tidak kompatibel dengan field dan array null-restricted, dan JEP terpisah akan menyediakan mekanisme serialisasi yang tidak mengekspos field dan array null-restricted yang belum diinisialisasi
- Dokumentasi yang dihasilkan
javadocmenyertakan penanda nullness - API
java.lang.reflect.Typedanjavax.lang.modelmengenkode nullness dalam representasi tipe
Alternatif dan dependensi
- Berbagai alat pengembangan di ekosistem Java telah mengimplementasikan pelacakan
nullwaktu kompilasi sendiri, tetapi karena tidak mengubah bahasa Java, sintaksnya terutama terbatas pada annotation dan perilaku yang dapat dipengaruhi juga terbatas pada pemeriksaan waktu kompilasi - Bahasa lain melacak nullness dalam sistem tipe, dan banyak bahasa secara default bersifat null-restricted serta menganggap assignment ke tipe null-restricted tanpa pemeriksaan
nulleksplisit sebagai error - Di Java, fitur ini harus opsional dan dapat digunakan bertahap tanpa migrasi besar-besaran sekaligus
- Pemaksaan nullness saat runtime juga dapat diimplementasikan dengan pemeriksaan eksplisit atau pemanggilan
Objects.requireNonNull- Namun penerapan yang konsisten merepotkan, membutuhkan dokumentasi tambahan, dan mengurangi keterbacaan program
- Tidak ada cara untuk menerapkannya langsung ke penyimpanan variabel seperti field dan array
- Prasyaratnya adalah Flexible Constructor Bodies (Second Preview)
- Konstruktor dapat menjalankan statement sebelum pemanggilan
super(...)dan melakukan assignment ke field instans, sehingga memungkinkan persyaratan inisialisasi field null-restricted
- Konstruktor dapat menjalankan statement sebelum pemanggilan
- Pekerjaan mendatang mencakup berikut ini
- Null-Restricted Value Class Types (Preview): optimisasi encoding untuk field dan array bertipe value class null-restricted
- JEP 402: Enhanced Primitive Boxing (Preview): pelacakan nullness saat bahasa memakai konversi boxing implisit secara lebih luas
- Spesialisasi kelas dan metode JVM (JEP 218 dan revisinya): mereifikasi dan memaksakan nullness sebagian argumen tipe
- Kemungkinan peningkatan mendatang tambahan mencakup penerapan penanda nullness pada sebagian API standar, representasi null check yang ringkas dalam bytecode, pemaksaan tingkat rendah yang lebih kuat untuk parameter metode null-restricted, dan mekanisme bahasa yang secara implisit menegaskan semua tipe dalam konteks tertentu sebagai null-restricted
1 komentar
Komentar Hacker News
Menarik melihat bagaimana pendekatan ini berbeda dari cara yang diperkenalkan C# beberapa tahun lalu. Di C#, jika nullability diaktifkan pada proyek, semua variabel secara default dideklarasikan sebagai non-null kecuali secara eksplisit ditandai nullable, sedangkan dalam proposal ini variabel yang sudah ada pada dasarnya menjadi salah satu dari nullable implisit, nullable eksplisit, atau non-nullable eksplisit
Kotlin juga bahasa JVM, tetapi seperti C# ia menganggap tipe sebagai non-null jika tidak dinyatakan sebaliknya, hanya saja Kotlin tidak punya beban kompatibilitas mundur. Kotlin juga menyediakan jalan keluar melalui
lateinit var, yang memungkinkan tipe non-nullable dibiarkan kosong sampai diinisialisasi dari metode lain, dan akan melempar pengecualian khusus jika diakses sebelum inisialisasiSaya penasaran kenapa harus ada tiga pilihan. Rasanya cukup mempertahankan variabel tanpa anotasi sebagai nullable, lalu hanya variabel yang diberi anotasi yang menjadi non-null eksplisit. Jika tanpa penanda apa pun sudah otomatis nullable, saya tidak melihat alasan mengapa orang masih ingin mendeklarasikan nullable secara eksplisit
Saya lebih suka pendekatan C#, tetapi pendekatan ini punya kelebihan karena bisa dipakai di codebase lama tanpa harus membereskan semua masalah nullability lebih dulu. Sebaliknya, C# langsung menampakkan masalah nullability, sedangkan proposal ini memungkinkan semuanya tetap tersembunyi seperti sekarang
Bagian yang mengatakan “satu metode tetap bisa menimpa metode lain meskipun nullability parameter dan nilai kembalian tidak cocok” juga terasa aneh. Saat meng-override/mengimplementasikan callback, ini terlihat seperti senjata makan tuan ketika metode aslinya menetapkan pengembalian non-null tetapi implementasinya malah mengembalikan null
Untuk sementara, karena keterbatasan waktu, kami memilih hanya mengaktifkan anotasi kecuali di beberapa titik penting, tetapi saya masih mempertahankan
NotNullAttributedanCanBeNullAttributedari JetBrains sebagai penanda agar keputusan yang dibuat secara sadar bisa langsung terlihat. Yang kedua sebenarnya bisa dihapus karena nullable sudah punya penanda eksplisit, tetapi yang pertama bentrok nama dengan fitur bawaan C#Dalam konteks itu, tiga pilihan justru cukup diinginkan. Kalau kodenya sudah ratusan ribu baris, migrasi cepat dan mudah memang tidak realistis
Di proyek internal lain, kami menaburkan
#nullable enabledi sekitar kode yang sedang disentuh agar cakupan nullability meluas secara bertahap. Kami juga mensyaratkan kode baru harus berada dalam konteks nullable. Ini juga cukup baik untuk menandai bagian yang sudah dianotasi, tetapi pendekatan seperti ini lebih mungkin dilakukan pada codebase dan tim yang jauh lebih kecilString!Istilah “platform types” dan simbol tanda seru itu memang agak membingungkan, tetapi selain itu pendekatan Kotlin bekerja cukup baik. Karena Kotlin sejak awal sudah punya nullability, programmer tidak bisa secara langsung menetapkan platform type, tetapi tetap membutuhkannya agar kompatibel dengan platform dasar seperti JVM atau JavaScript yang nullability-nya tidak jelas
Dalam pendekatan ini, nilai defaultnya tetap masuk akal. Secara default seharusnya selalu non-nullable, dan siapa pun yang berpikir sebaliknya berarti tidak belajar apa pun dari Tony Hoare. Pada saat yang sama, kompatibilitas mundur juga tetap terjaga. Kotlin punya jalan yang lebih mudah, sedangkan Java dan C# juga harus menjaga kompatibilitas dengan source code yang sudah ada
Baik pendekatan Java maupun C# sama-sama tidak ideal. Pendekatan C# mengubah perilaku kode secara besar bergantung pada compiler flag, sedangkan pendekatan Java menjadikan opsi terburuk sebagai default
Meski begitu, saya tetap lebih condong ke C#. Jika “mungkin nullable” dijadikan pilihan yang paling mudah, kebanyakan programmer akan memilih itu sebagai default. Ini terasa makin mungkin pada bahasa yang ramah perusahaan seperti Java. Linter dan peringatan compiler akan membantu dalam jangka panjang, tetapi sepertinya butuh bertahun-tahun sampai sebagian besar kode Java benar-benar dianotasi nullability dengan benar. Pengguna C# mungkin akan lebih menderita dalam jangka pendek, tetapi peluang mereka untuk jauh lebih cepat mencapai tujuan berupa nullability yang jelas juga lebih besar
https://kotlinlang.org/docs/java-interop.html#null-safety-an...
https://www.infoq.com/presentations/Null-References-The-Bill...
T?berarti nullable danT!berarti non-nullable, lalu untukTbiasa pada source yang baru dikompilasi, nilai defaultnya ditetapkan lewat deklarasi mirip pragma per file sumber, per filepackage-info, atau secara global lewat compiler switchSetelah itu, pada rilis Java LTS berikutnya, default globalnya bisa diubah. Dengan begitu transisi proyek jadi mudah, pragma bisa disisipkan/diperbarui secara otomatis, dan jika perlu default lama pun tetap bisa dipertahankan
Selain itu, kalau anotasi JSR-305
@Nonnullyang sudah ada dimanfaatkan di class file untuk menandai kemunculan tipe non-nullable, kompatibilitas dua arah dengan JDK lama juga sebenarnya bisa disediakan!secara eksplisit”Rasanya compiler flag atau semacam tag modul saja sudah cukup baik
Meski begitu, saya rasa nantinya akan ada compiler flag yang menganggap semua hal sebagai non-nullable secara otomatis kecuali dinyatakan lain
Kelihatannya bagus. Akhirnya ada cara untuk menghilangkan ribuan exception yang tidak perlu dan pemeriksaan null di tingkat bahasa. Namun, konversi otomatis yang mempersempit status null terasa kurang tepat
Dari contoh proposal
String? id(String! arg) { return arg; },String s = null;,Object! o1 = s; // NPE,Object o2 = id(s); // NPE,Object o3 = (String!) s; // NPE, rasanya setidaknya dua kasus pertama seharusnya menjadi error kompilasiYang terakhir memang ambigu karena eksplisit, tetapi lebih baik kalau di dalam
if (s != null)compiler mengetahui tipe validnya sebagaiString!dan mengizinkanString! ss = s;. Dengan begitu tidak ada kemungkinan errorSebenarnya, dibanding cast pada kasus terakhir, saya lebih suka memakai
Objects.requireNonNull(s)karena lebih eksplisit. Namun, akan bagus juga kalau ada sesuatu sepertiObjects.unsafeForceNonNull(s)yang melewati pemeriksaan eksplisit tetapi hanya dikecualikan untuk kasus yang terhalang optimisasi. Jika ada method unsafe, kita bisa mengimplementasikanrequireNonNullsendiri tanpa menambah analisis statis yang rumitSayangnya ini hanya akan terdeteksi saat runtime
Misalnya, library standar secara eksplisit menyatakan bahwa setidaknya untuk sementara waktu mereka tidak akan bermigrasi ke null type
Sepertinya sangat perlu ada cara untuk menandai semua variabel sebagai non-null secara default pada level package, atau setidaknya file. Kalau tidak, demi keamanan akan muncul dorongan untuk menulis sintaks
T!pada hampir semua variabel, dan itu hanya akan menambah banyak noise!secara eksplisit”@NullMasalah hanya muncul di batas kode yang berinteraksi dengan library. Sintaks baru ini sepertinya juga akan mirip begitu
Bagian “untuk saat ini bukan tujuan untuk menerapkan perbaikan bahasa ke library standar” cukup disayangkan
Dari pengalaman terpaksa memakai PHP, harus melepas atau memasang kembali properti yang sudah dijamin sebelumnya pada data setiap kali berinteraksi dengan library standar yang sangat besar itu merepotkan
Java juga perlu memasukkan ekspresivitas seperti ini lebih agresif ke library standar dan menjadikannya warga kelas satu
Optionalmenjadi beban bagi proposal nullable/non-nullable yang eksplisit. Rasanya tipe record juga seharusnya bisa dibuat default non-nullableSelain itu, membaginya menjadi dua tahap membuat fitur ini lebih mudah dirilis sebagai preview dan desainnya bisa dipastikan setelah menerima masukan. Kalau semua dipaksakan sekaligus, hampir tidak ada ruang untuk memperbaikinya secara iteratif di dunia nyata
Saya ingin fitur ini masuk ke Java. Opsi eksplisit di tingkat bahasa seperti
T?benar-benar meningkatkan kualitas hidup developer di Kotlin dan TypeScript. Java punya alat seperti NullAway, tetapi merepotkanDukungan di tingkat bahasa menurut saya jauh lebih baik daripada
Optional/Maybe. Karena itu membuat kita fokus pada logika yang sebenarnya, alih-alih menaruh kode di relmap/flatMaphttps://github.com/uber/NullAway
Bukankah lebih baik pakai bahasa JVM lain saja?
Situsnya sedang down sekarang, jadi saya taruh tautan arsipnya: https://web.archive.org/web/20240802081039/https://bugs.open...
“Tujuannya bukan menuntut program untuk secara eksplisit menangani semua kemungkinan nilai null yang dapat terjadi, dan nilai null yang tidak tertangani bisa menjadi peringatan saat kompilasi tetapi bukan error” adalah keputusan yang buruk.
Java pada dasarnya adalah bahasa bertipe statis, jadi saya tidak paham mengapa masih menambahkan perilaku dinamis lain seperti ini. Saya berharap ada cara mudah untuk menaikkan peringatan semacam ini menjadi error
Bahasa yang sistem tipenya memaksa penanganan null/nil di semua kasus memang jauh lebih baik. Tetapi Java saat ini bukan bahasa seperti itu. Meski begitu, ini tetap akan menjadi peningkatan besar
Sayang sekali pelajaran seperti ini dipelajari terlalu terlambat. Seharusnya secara default non-nullable, secara default immutable, dan secara default memakai cakupan tersempit.
Dalam desain baru, terlalu sering yang dipilih adalah kemudahan langsung daripada “membiarkannya jatuh ke jalur yang aman”. Default yang aman butuh desain dan pengalaman pengguna yang jauh lebih cermat, tetapi hasil akhirnya hampir semua bahasa, platform, dan teknologi dipenuhi footgun. Teknik sipil dan teknik elektro punya standar, sedangkan perangkat lunak terus mempelajari ulang pelajaran yang sama di bahasa dan teknologi baru setiap sekitar 30 tahun
Java seperti desa di dunia ketiga yang baru belajar bahwa air harus direbus untuk membunuh bakteri
Sebagian besar yang saya kerjakan di Facebook adalah memakai Hack. Status null adalah elemen inti dari sistem tipe Hack, dan itu benar-benar menyelesaikan banyak sekali error yang tidak perlu.
Tentu saja itu bukan berarti Anda sama sekali tidak akan pernah menerima null yang tak terduga. Fitur ini juga ditambahkan belakangan ke bahasa tersebut, jadi masih ada banyak tipe
mixedwarisan yang mencerminkan akar PHP-nya, yang pada dasarnya berarti apa saja bisa masuk.Pertama, saya penasaran bagaimana dengan array yang nullable. Contoh
String![]menunjukkan kasus ketika objeknya bisa null, tetapi bagaimana dengan array itu sendiri? Di Java,String labels[] = null;sepenuhnya legal. Jadi apakah harus dideklarasikan sepertiString![]! labels;?Di Hack,
vec $fooberarti foo maupun elemennya tidak null, dan?vec $fooberarti elemennya non-null tetapi foo sendiri bisa null. Sebenarnya hampir tidak ada alasan untuk memakai array null, jadi default-nya seharusnya tidak boleh null. Hanya saja, Java punya masalah bahwa semua kode warisan mengasumsikan kemungkinan null.Pada contoh proposal
Object! o1 = s,Object o2 = id(s),Object o3 = (String!) s, saya merasa bukankah nomor 2 dan 3 seharusnya menjadi error kompilasi?Terakhir, dibanding casting di Java, saya lebih suka operator pemaksaan
asdi Hack. Misalnya,foo($b)menghasilkan error kompilasi,$b as Amenghasilkan error runtime jika null, dan$a as ?Bakan meng-cast jika itu B, jika tidak maka mengembalikan null.Pada akhirnya, pertanyaannya adalah apakah ini bisa diterapkan ke Java SDK, dan seperti apa bentuknya di kode warisan.
https://docs.hhvm.com/hack/types/nullable-types
String![]? labels = null;Hal-hal bagus dari Kotlin tampaknya sekarang semuanya masuk ke Java.
Meski begitu, saya tetap ingin terus bekerja dengan Kotlin, di mana saya tidak perlu berurusan dengan hal-hal seperti Lombok. Record di Java memang bagus