Apakah Pilihan?
Parameter Pilihan digunakan untuk membawa objek dan membolehkan rujukan nol dikendalikan oleh pelbagai API. Mari lihat coretan kod:Coffee coffee = new Coffee();
Integer quantity = coffee.getSugar().getQuantity();
Kami mempunyai contoh Kopi di mana kami mendapat sedikit gula daripada contoh objek Gula . Jika kita menganggap bahawa nilai kuantiti tidak pernah ditetapkan dalam Coffee constructor , maka coffee.getSugar().getQuantity() akan mengembalikan NullPointerException . Sudah tentu, kita sentiasa boleh menggunakan semakan nol lama yang baik untuk menyelesaikan masalah.
Coffee coffee = new Coffee();
Integer quantity = 0;
if (coffee.getSugar() != null) {
quantity = coffee.getSugar().getQuantity();
}
Sekarang semuanya kelihatan baik-baik saja. Tetapi apabila menulis kod Java, lebih baik kita mengelak daripada melaksanakan semakan nol . Mari lihat bagaimana ini boleh dilakukan menggunakan Pilihan.
Bagaimana untuk membuat Pilihan
Terdapat tiga cara untuk mencipta objek Pilihan:-
of(T value) — instantiasi objek bukan nol Pilihan. Sedar bahawa menggunakan of() untuk merujuk kepada objek null akan membuang NullPointerException .
-
ofNullable(T value) - mencipta nilai Pilihan untuk objek yang boleh menjadi null.
-
empty() - Mencipta contoh Pilihan yang mewakili rujukan kepada null .
// пример использования Optional.of(T Value)
String name = "foo";
Optional<String> stringExample = Optional.of(name)
// пример использования Optional.ofNullable(T Value)
Integer age = null;
Optional<Integer> integerExample= Optional.ofNullable(age)
// пример использования Optional.empty()
Optional<Object> emptyExample = Optional.empty();
Jadi anda mempunyai objek Pilihan. Sekarang mari kita lihat dua kaedah utama untuk Pilihan:
-
isPresent() - Kaedah ini memberitahu anda sama ada objek Pilihan mengandungi nilai bukan nol.
-
get() - Mendapatkan nilai untuk Pilihan dengan nilai semasa. Harap maklum bahawa memanggil get() pada Optional kosong akan menghasilkan NullPointerException .
Memperbaik Pemeriksaan Null dengan Pilihan
Jadi bagaimana kita boleh menambah baik kod di atas? Dengan Pilihan kita boleh memahami kehadiran objek menggunakan isPresent() dan mendapatkannya menggunakan get() . Mari kita mulakan dengan membungkus hasil coffee.getSugar() dengan Pilihan dan menggunakan kaedah isPresent() . Ini akan membantu kami menentukan sama ada getSugar() mengembalikan null.Coffee coffee = new Coffee();
Optional<String> sugar = Optional.ofNullable(coffee.getSugar());
int quantity = 0;
if (sugar.isPresent()) {
Sugar sugar = sugar.get();
int quantity = sugar.getQuantity();
}
Melihat contoh ini, membungkus hasil coffee.getSugar() ke dalam Pilihan nampaknya tidak menambah apa-apa nilai, sebaliknya menambah kerumitan. Kami boleh menambah baik hasilnya dengan menggunakan apa yang saya anggap sebagai fungsi kegemaran saya daripada kelas Pilihan:
-
map(Function<? super T,? extends U> mapper) - Petakan nilai yang terkandung dalam Pilihan kepada fungsi yang disediakan. Jika parameter Pilihan kosong, maka map() akan mengembalikan Optional.empty() .
-
orElse(T other) ialah versi "istimewa" kaedah get() . Ia boleh mendapatkan nilai yang terkandung dalam Pilihan. Walau bagaimanapun, dalam kes Pilihan kosong, ini akan mengembalikan nilai yang dihantar kepada kaedah orElse() .
Coffee coffee = new Coffee();
Integer quantity = Optional.ofNullable(coffee.getSugar())
.map(it -> it.getQuantity())
.orElse(0);
Ini sangat keren - sekurang-kurangnya saya fikir begitu. Sekarang, jika dalam kes nilai kosong kita tidak mahu mengembalikan nilai lalai, maka kita perlu membuang beberapa jenis pengecualian. orElseThrow(Supplier<? extends X> exceptionSupplier) mengembalikan nilai yang terkandung dalam parameter Pilihan, atau membuang pengecualian jika Pilihan kosong.
Coffee coffee = new Coffee();
Integer quantity = Optional.ofNullable(coffee.getSugar())
.map(it -> it.getQuantity())
.orElseThrow(IllegalArgumentException::new);
Seperti yang anda lihat, Pilihan memberikan beberapa kelebihan:
- abstrak semakan nol
- menyediakan API untuk mengendalikan objek nol
- membolehkan pendekatan deklaratif untuk menyatakan apa yang dicapai
Bagaimana untuk menjadi berkesan dengan Pilihan
Dalam kerja saya, saya menggunakan Pilihan sebagai jenis pulangan apabila kaedah boleh mengembalikan keadaan "tiada hasil". Saya biasanya menggunakannya apabila menentukan jenis pulangan untuk kaedah.Optional<Coffee> findByName(String name) {
...
}
Kadang-kadang ini tidak perlu. Sebagai contoh, jika saya mempunyai kaedah yang mengembalikan int , seperti getQuantity() dalam kelas Sugar , maka kaedah itu mungkin mengembalikan 0 jika hasilnya nol untuk mewakili "tiada kuantiti". Sekarang, mengetahui perkara ini, kita boleh berfikir bahawa parameter Gula dalam kelas Kopi boleh diwakili sebagai Pilihan. Pada pandangan pertama, ini kelihatan seperti idea yang baik kerana, secara teori, gula tidak perlu ada dalam kopi. Walau bagaimanapun, di sinilah saya ingin menangani apabila tidak menggunakan Pilihan. Kita harus mengelak daripada menggunakan Pilihan dalam senario berikut:
-
Sebagai jenis parameter untuk POJO , seperti DTO . Pilihan tidak boleh bersiri, jadi menggunakannya dalam POJO menjadikan objek tidak boleh bersiri.
-
Sebagai hujah kaedah. Jika argumen kaedah boleh menjadi null , maka dari perspektif kod tulen, lulus null masih lebih baik daripada lulus Pilihan. Selain itu, anda boleh mencipta kaedah terlebih beban untuk mengendalikan ketiadaan hujah kaedah nol secara abstrak.
-
Untuk mewakili objek Koleksi yang tiada. Koleksi boleh kosong, jadi Koleksi kosong , seperti Set atau Senarai kosong , mesti digunakan untuk mewakili Koleksi tanpa nilai.
GO TO FULL VERSION