Apa gunanya kelas Opsional Guava

89

Saya baru-baru ini membaca tentang ini dan melihat orang-orang menggunakan kelas ini, tetapi dalam hampir semua kasus, penggunaan nullakan berhasil juga - jika tidak lebih intuitif. Dapatkah seseorang memberikan contoh konkret di mana Optionalakan mencapai sesuatu yang nulltidak bisa atau dengan cara yang jauh lebih bersih? Satu-satunya hal yang dapat saya pikirkan adalah menggunakannya dengan Mapstidak menerima nullkunci, tetapi bahkan itu dapat dilakukan dengan sisi "pemetaan" dari nilai null. Adakah yang bisa memberi saya argumen yang lebih meyakinkan? Terima kasih.

SINAR
sumber
12
kata-kata kasar acak: saya benci jika orang terlalu sering menggunakan "pola" dan membuat kode terlihat sangat jelek untuk beberapa manfaat teoretis yang tidak ada ...
RAY
Untuk Java8, saya tidak akan menggunakan kelas Guava ini lagi karena kurang kuat dari JDK. Lihat stackoverflow.com/a/10756992/82609
Sebastien Lorber

Jawaban:

155

Anggota tim jambu di sini.

Mungkin satu-satunya kelemahan terbesar nulladalah tidak jelas apa artinya dalam konteks tertentu: tidak memiliki nama ilustrasi. Itu tidak selalu jelas yang nullberarti "tidak ada nilai untuk parameter ini" - heck, sebagai nilai yang dikembalikan, terkadang itu berarti "kesalahan", atau bahkan "berhasil" (!!), atau hanya "jawaban yang benar adalah tidak ada". Optionalsering kali merupakan konsep yang sebenarnya Anda maksud saat membuat variabel menjadi nullable, tetapi tidak selalu. Jika tidak, kami menyarankan Anda untuk menulis kelas Anda sendiri, mirip dengan Optionaltetapi dengan skema penamaan yang berbeda, untuk memperjelas apa yang sebenarnya Anda maksud.

Tetapi saya akan mengatakan keuntungan terbesar Optionaltidak dalam keterbacaan: keuntungannya adalah bukti-kebodohannya. Ini memaksa Anda untuk secara aktif memikirkan kasus absen jika Anda ingin program Anda untuk dikompilasi sama sekali, karena Anda harus secara aktif membuka bungkus Optionaldan menangani kasus itu. Null membuatnya sangat mudah untuk melupakan sesuatu, dan meskipun FindBugs membantu, saya rasa itu tidak mengatasi masalah dengan baik. Ini sangat relevan ketika Anda mengembalikan nilai yang mungkin "ada" atau tidak. Anda (dan lain-lain) jauh lebih mungkin untuk melupakan bahwa other.method(a, b)bisa mengembalikan nullnilai dari Anda mungkin lupa bahwa abisa nullketika Anda menerapkan other.method. KembaliOptional membuat penelepon tidak mungkin melupakan kasus itu, karena mereka harus membuka sendiri objeknya.

Untuk alasan ini, kami merekomendasikan agar Anda menggunakan Optionalsebagai tipe kembalian untuk metode Anda, tetapi tidak harus dalam argumen metode Anda.

(Omong-omong, ini benar-benar disebutkan dari diskusi di sini .)

Louis Wasserman
sumber
3
1 untuk penjelasan yang bagus. Saya tidak tahu apakah ini adalah inspirasi, tetapi saya akan menambahkan penunjuk ke jenis opsi di SML, OCaml, dan F #, yang memiliki banyak semantik yang sama.
Adam Mihalcin
2
Selalu senang mendapatkan jawaban dari seseorang yang terlibat langsung. Saya akan memberi +1 hanya untuk itu. Akan memberi +1 lagi untuk jawaban yang bagus. (tetapi saya tidak bisa.) Saya pikir poin tentang menjadikannya sebagai nilai balik untuk memaksa konsumen dari metode yang tidak biasa untuk berusaha mengakui bahwa "tidak ada" yang dapat dikembalikan adalah satu alasan yang kuat. Saya tidak suka bagaimana hal itu digunakan secara berlebihan (atau bahkan disalahgunakan). misalnya, saya merasa sangat tidak nyaman saat melihat orang menempatkan Opsional sebagai nilai ke dalam Maps. Map returing null untuk kunci yang tidak ada / tidak dipetakan adalah paradigma yang mapan ... Tidak perlu membuatnya lebih rumit ...
RAY
9
Sudah mapan bahwa Mapmengembalikan nulljika kunci tidak dipetakan, tetapi ingat bahwa jika Anda melakukannya map.put(key, null), maka map.containsKey(key)akan kembali truetetapi map.get(key)akan kembali null. Optionaldapat berguna dalam membersihkan perbedaan antara kasus "yang dipetakan secara eksplisit ke null" dan kasus "tidak ada di peta". Saya akan mengabulkan bahwa itu Optionaldapat disalahgunakan, tetapi saya belum yakin bahwa kasus yang Anda gambarkan adalah pelecehan.
Louis Wasserman
8
Untuk menggunakan analogi kuno, dulu ada benda raksasa yang disebut "buku telepon" :-) dan jika saya meminta Anda untuk mencari nomor seseorang dan Anda berkata "tidak ada nomor untuk orang itu" Saya akan mengatakan "apa yang Anda maksudnya, mereka ada di sana dengan nomor yang tidak terdaftar atau Anda sama sekali tidak bisa menemukan entri untuk mereka? " Kedua kemungkinan tanggapan tersebut masing-masing dipetakan dengan baik ke Opsional.absent () dan null. Opsional.absent () adalah "negatif positif" yang definitif.
Kevin Bourrillion
3
@RAY: Di satu sisi, Optional<T> apakah itu nilai "ditemukan, tetapi tidak valid". Atau lebih tepatnya, Optional<T>adalah cara untuk menghias jenis apa pun Tdengan nilai ekstra "ditemukan, tetapi tidak valid" - membuat jenis baru dengan menggabungkan dua jenis yang ada. Jika Anda memiliki seratus kelas, akan berantakan jika Anda harus membuat nilai "ditemukan, tetapi tidak valid" untuk masing-masing kelas, tetapi Optional<T>dapat dengan mudah berfungsi untuk semuanya.
Daniel Pryden
9

Ini benar-benar terlihat seperti Maybepola Monad dari Haskell.

Anda harus membaca berikut ini, Wikipedia Monad (pemrograman fungsional) :

Dan baca Dari Opsional ke Monad dengan Jambu Biji di Blog Kerflyn, yang membahas tentang Pilihan Jambu Biji yang digunakan sebagai Monad:


Sunting: Dengan Java8, ada Opsional bawaan yang memiliki operator monadik seperti flatMap. Ini telah menjadi topik yang kontroversial tetapi akhirnya diterapkan.

Lihat http://www.nurkiewicz.com/2013/08/optional-in-java-8-cheat-sheet.html

public Optional<String> tryFindSimilar(String s)  //...

Optional<Optional<String>> bad = opt.map(this::tryFindSimilar);
Optional<String> similar =       opt.flatMap(this::tryFindSimilar);

The flatMapoperator adalah penting untuk memungkinkan operasi monadik, dan izin untuk dengan mudah rantai panggilan yang semua kembali Opsional hasil.

Pikirkan tentang itu, jika Anda menggunakan mapoperator 5 kali Anda akan berakhir dengan Optional<Optional<Optional<Optional<Optional<String>>>>>, sedangkan menggunakan flatMapakan memberi AndaOptional<String>

Sejak Java8 saya lebih suka tidak menggunakan Guava's Opsional yang kurang bertenaga.

Sebastien Lorber
sumber
6

Salah satu alasan bagus untuk menggunakannya adalah karena itu membuat null Anda sangat berarti. Alih-alih mengembalikan null yang bisa berarti banyak hal (seperti kesalahan, atau kegagalan, atau kosong, dll), Anda dapat memasukkan 'nama' ke null Anda. Lihat contoh ini:

mari kita tentukan POJO dasar:

class PersonDetails {

String person;
String comments;

public PersonDetails(String person, String comments) {
    this.person = person;
    this.comments = comments;
}

public String getPerson() {
    return person;
}


public String getComments() {
    return comments;
}

}

Sekarang mari kita gunakan POJO sederhana ini:

public Optional<PersonDetails> getPersonDetailstWithOptional () {

  PersonDetails details = null; /*details of the person are empty but to the caller this is meaningless,
  lets make the return value more meaningful*/


    if (details == null) {
      //return an absent here, caller can check for absent to signify details are not present
        return Optional.absent();
    } else {
      //else return the details wrapped in a guava 'optional'
        return Optional.of(details);   
    }
}

Sekarang mari kita hindari penggunaan null dan lakukan pemeriksaan dengan Opsional sehingga berarti

public void checkUsingOptional () {

    Optional<PersonDetails> details = getPersonDetailstWithOptional();

    /*below condition checks if persons details are present (notice we dont check if person details are null,
    we use something more meaningful. Guava optional forces this with the implementation)*/
    if (details.isPresent()) {

      PersonDetails details = details.get();

        // proceed with further processing
        logger.info(details);

    } else {
        // do nothing
        logger.info("object was null"); 
    }

    assertFalse(details.isPresent());
}

jadi pada akhirnya ini adalah cara untuk membuat nulls bermakna, & mengurangi ambiguitas.

j2emanue
sumber
4

Keuntungan terpenting dari Opsional adalah ia menambahkan lebih banyak detail pada kontrak antara pelaksana dan pemanggil suatu fungsi. Untuk alasan ini berguna untuk parameter dan tipe kembalian.

Jika Anda membuat konvensi untuk selalu memiliki Optionalkemungkinan objek null, Anda menambahkan lebih banyak klarifikasi untuk kasus seperti:

  1. Optional<Integer> maxPrime(Optional<Integer> from, Optional<Integer> to)

    Kontrak di sini dengan jelas menetapkan bahwa ada kemungkinan bahwa hasil tidak dikembalikan tetapi juga menunjukkan bahwa hasil tersebut akan berfungsi dengan fromdan tosebagai tidak ada.

  2. Optional<Integer> maxPrime(Optional<Integer> from, Integer to)

    Kontrak menetapkan bahwa from adalah opsional sehingga nilai yang tidak ada mungkin memiliki arti khusus seperti mulai dari 2. Saya dapat mengharapkan bahwa nilai null untuk toparameter akan memunculkan pengecualian.

Jadi bagian yang baik dari menggunakan Opsional adalah bahwa kontrak menjadi deskriptif (mirip dengan @NotNullanotasi) tetapi juga formal karena Anda harus menulis kode .get()untuk mengatasinya Optional.

kismis
sumber
Mengapa menggunakan <List> Opsional jika List yang kosong akan lebih bersih?
RAY
Saya memilih contoh yang salah saat kembali. Dengan koleksi, Anda dapat membuat konvensi untuk selalu mengembalikan koleksi kosong, bukan nilai null. Jika konvensi ini digunakan, Anda tidak perlu opsional untuk koleksi. Opsional dapat dianggap sebagai kumpulan dengan nol atau satu elemen sehingga tidak perlu diletakkan di sekitar koleksi lain.
kismis
2
bergantung pada konteksnya, mungkin ada perbedaan yang berarti antara daftar dengan 0 item dan daftar yang tidak ada.
plasma147