Menu

Optional Java: Menghindari null dan NullPointerException

Apa itu java.util.Optional, cara membuatnya, dan cara membaca nilainya dengan aman lewat map, filter, orElse, dan ifPresent sebagai pengganti pengecekan null.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Masalah yang Diselesaikan Optional

Di Java, method yang mungkin tidak punya jawaban selalu menghadapi pilihan yang canggung: mengembalikan null dan berharap pemanggil ingat untuk mengeceknya. Biasanya pemanggil lupa, dan hasilnya adalah NullPointerException yang muncul jauh dari method yang mengembalikan null itu.

Optional<T> adalah kotak kecil yang berisi sebuah nilai atau secara eksplisit kosong. Dengan mengembalikan Optional<User> alih-alih User, method memberi tahu pemanggil "ini mungkin tidak menemukan apa-apa" langsung di signature-nya, dan compiler mengarahkan pemanggil untuk menangani kasus itu.

Membuat Optional

Ada tiga factory method, dan memilih yang tepat itu penting:

  • Optional.of(value): nilainya harus tidak null, kalau tidak, langsung melempar NullPointerException saat itu juga.
  • Optional.ofNullable(value): kosong kalau nilainya null, berisi kalau tidak. Pakai ini untuk membungkus sesuatu yang mungkin null.
  • Optional.empty(): optional yang kosong.

Kesalahan yang umum adalah memakai Optional.of(x) untuk nilai yang bisa saja null. Itu menggagalkan tujuannya dan justru melempar exception yang ingin kamu hindari. Kalau ragu, pakai ofNullable.

Membaca Nilainya dengan Aman

Begitu kamu punya optional, tujuannya adalah mengeluarkan nilainya tanpa menganggap nilai itu pasti ada. Alat yang kasar adalah get(), dan hampir tidak pernah sebaiknya kamu pakai:

Optional<String> name = Optional.empty();
String value = name.get();   // throws NoSuchElementException - just NPE in disguise

Sebagai gantinya, berikan nilai cadangan atau tanggapi keberadaan nilainya. orElse mengembalikan nilai default kalau kosong; ifPresent menjalankan kode hanya kalau nilainya ada:

Pakai orElseGet(supplier) alih-alih orElse kalau nilai default-nya mahal untuk dibuat: supplier hanya dijalankan kalau optional-nya memang kosong. Argumen orElse selalu dievaluasi, bahkan saat tidak dibutuhkan.

orElseThrow untuk "ini seharusnya ada"

Kadang kosong memang sebuah error, misalnya nilai konfigurasi yang wajib ada, atau user yang seharusnya ada di database. orElseThrow mengubah optional kosong menjadi exception yang jelas sesuai pilihanmu:

Kode ini jauh lebih enak dibaca daripada blok if (opt.isPresent()) dan membuat kegagalannya tertulis jelas tepat di tempat terjadinya.

Mengubah Nilai dengan map dan filter

Keuntungan sebenarnya ada di chaining. map menerapkan fungsi pada nilainya hanya kalau nilainya ada dan membiarkan optional kosong tetap kosong, jadi kamu bisa mengubah nilai tanpa pernah menyentuh null. filter membuang nilainya kalau tidak lolos pengujian.

Kalau fungsi mapping-mu sendiri mengembalikan Optional, pakai flatMap alih-alih map supaya tidak menghasilkan Optional<Optional<T>> yang canggung. Ini sama dengan perbedaan map/flatMap yang kamu lihat di stream: Optional berperilaku mirip stream dengan nol atau satu elemen.

Tempat yang Cocok untuk Optional (dan yang Tidak)

Optional dirancang sebagai tipe kembalian untuk method yang wajar saja kalau tidak menghasilkan apa-apa. Contoh klasiknya adalah Stream.findFirst(), pencarian ala Map, dan parsing. Pakai di sana, dan API-mu akan menjelaskan sendiri celah-celahnya.

Optional tidak dimaksudkan untuk:

  • Field. Optional tidak bisa diserialisasi dan menambah satu objek per field. Pakai referensi biasa dan validasi di constructor.
  • Parameter method. Pemanggil jadi harus membungkus argumen dengan Optional.of(...), yang lebih ribet daripada overload atau parameter yang boleh null.
  • Collection. Kembalikan List kosong, bukan Optional<List>. Collection kosong sudah berarti "tidak ada apa-apa".

Kalau diperlakukan sebagai tipe kembalian, Optional mengubah bug null yang diam-diam menjadi pengingat saat kompilasi untuk menangani kasus yang hilang.

Berikutnya: Exception

Optional menangani kasus sehari-hari "mungkin tidak ada nilai" dengan rapi, tetapi sebagian kegagalan memang luar biasa: file yang tidak bisa dibuka, jaringan yang terputus, input yang tidak bisa di-parse. Java memodelkannya dengan exception, dan itulah topik halaman berikutnya.

Pertanyaan yang sering diajukan

Apa itu Optional di Java dan kenapa dipakai?

Optional<T> adalah wadah yang berisi sebuah nilai atau kosong. Tujuannya membuat kemungkinan "tidak ada nilai" tertulis jelas di tipe kembalian method, sehingga pemanggil terdorong menangani kasus kosong daripada lupa mengecek null lalu terkena NullPointerException saat runtime. Pakai terutama sebagai tipe kembalian untuk method yang mungkin tidak menghasilkan apa-apa, misalnya pencarian yang tidak menemukan hasil.

Apa perbedaan Optional.of dan Optional.ofNullable?

Optional.of(x) langsung melempar NullPointerException kalau x bernilai null, jadi pakai saat kamu tahu nilainya tidak null. Optional.ofNullable(x) mengembalikan Optional kosong kalau x null dan optional yang berisi nilai kalau tidak, jadi pakai saat nilainya mungkin null. Optional.empty() langsung memberimu optional yang kosong.

Apakah saya perlu memanggil Optional.get() untuk membaca nilainya?

Hindari get() mentah-mentah: method ini melempar NoSuchElementException kalau optional-nya kosong, yang pada dasarnya NullPointerException dengan nama lain. Utamakan orElse, orElseGet, orElseThrow, ifPresent, atau map supaya kasus kosong selalu tertangani. Kalau memang harus mengecek dulu, lindungi dengan isPresent(), tetapi method fungsionalnya lebih rapi.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai