Guava'nın İsteğe Bağlı sınıfının amacı nedir


89

Son zamanlarda bunu okudum ve bu sınıfı kullanan insanlar gördüm, ancak hemen hemen her durumda, kullanmak nullda işe yarardı - daha sezgisel olmasa bile. Birisi başaramayan veya çok daha temiz bir şekilde bir Optionalşeyi nerede başaracağına dair somut bir örnek nullverebilir mi? Aklıma gelen tek şey, onu anahtarları Mapskabul etmeyen bir şekilde kullanmaktır null, ama bu bile boş değerin bir yan "eşlemesi" ile yapılabilir. Biri bana daha ikna edici bir argüman sunabilir mi? Teşekkür ederim.


12
rastgele rant: İnsanların bir "kalıbı" aşırı kullanmasından ve var olmayan bazı teorik yararlar için kodu çok çirkin göstermesinden nefret ediyorum ...
RAY

Java8 itibariyle, bu Guava sınıfını artık kullanmayacağım çünkü JDK sınıfından daha az güçlü. Bkz stackoverflow.com/a/10756992/82609
Sebastien Lorber

Yanıtlar:


155

Guava ekip üyesi burada.

Muhtemelen en büyük dezavantajı, nullherhangi bir bağlamda ne anlama gelmesi gerektiğinin açık olmamasıdır: açıklayıcı bir adı yoktur. null"Bu parametre için değer yok" anlamına geldiği her zaman açık değildir - heck, bir dönüş değeri olarak, bazen "hata" veya hatta "başarı" (!!) veya kısaca "doğru cevap hiçbir şeydir" anlamına gelir. Optionalgenellikle bir değişkeni null yapılabilir yaptığınızda kastettiğiniz kavramdır, ancak her zaman değil. OptionalDeğilse, gerçekte ne demek istediğinizi netleştirmek için kendi sınıfınızı benzer ancak farklı bir adlandırma şemasıyla yazmanızı öneririz.

Ama en büyük avantajının Optionalokunabilirlikte olmadığını söyleyebilirim : Avantaj, aptalca kanıtlanmamış olmasıdır. Programınızın derlenmesini istiyorsanız, mevcut olmayan durumu aktif olarak düşünmeye zorlar, çünkü bu durumu aktif olarak açmanız Optionalve ele almanız gerekir . Null, bir şeyleri basitçe unutmayı rahatsız edici derecede kolaylaştırır ve FindBugs yardımcı olsa da, sorunu neredeyse aynı şekilde ele aldığını düşünmüyorum. Bu, özellikle "mevcut" olabilecek veya olmayabilecek değerler döndürürken önemlidir. Sen (ve diğerleri) unutmak çok daha muhtemeldir other.method(a, b)bir geri dönebilirler nullEğer unutmak olasıdır daha değer aolabilir nullsiz uygularken yaparken other.method. Geri dönenOptional Nesneyi kendilerinin açması gerektiğinden arayanların bu durumu unutmasını imkansız kılar.

Bu nedenlerden dolayı, Optionalyöntemleriniz için bir dönüş türü kullanmanızı öneririz, ancak yöntem bağımsız değişkenlerinizde olması gerekmez.

(Bu tamamen tartışmadan, bu arada, cribbed edilir burada .)


3
Harika bir açıklama için +1. Bunun ilham kaynağı olup olmadığını bilmiyorum, ancak SML, OCaml ve F #'daki seçenek türlerine bir işaretçi eklerdim, bunlar aynı anlamsallıkların çoğuna sahiptir.
Adam Mihalcin

2
Doğrudan dahil olan birinden yanıt almak her zaman harikadır. Sadece bunun için + 1'ledim. Harika bir yanıt için +1 daha alırsınız. (ama yapamam.) Bence, tüketicileri alışılmadık bir yöntemin tüketicilerini bir "hiçbir şeyin" iade edilebileceğini kabul etmeye zorlamak için bir geri dönüş değeri olarak sunmanın önemli bir nedeni olduğunu düşünüyorum. Nasıl aşırı kullanıldığını (hatta istismar edildiğini) sevmiyorum. Örneğin, insanların Haritalar'a Opsiyonel değerleri değer olarak koyduğunu görünce gerçekten huzursuz oluyorum. Varolmayan / eşlenmemiş bir anahtar için boş döndüren harita, iyi oluşturulmuş bir paradigmadır ... Daha karmaşık hale getirmeye gerek yok ...
RAY

9
Bir anahtar eşlenmemişse Mapgeri döndüğü iyi nullbilinmektedir, ancak bunu yaparsanız map.put(key, null), map.containsKey(key)geri döneceğini trueancak map.get(key)geri döneceğini hatırlayın null. Optional"Açıkça boş olarak eşleştirilmiş" durumu ile "haritada mevcut değil" durumu arasındaki ayrımı temizlemek için kullanışlı olabilir. Bunun Optionalistismar edilebileceğini kabul edeceğim , ancak tarif ettiğiniz vakanın kötüye kullanım olduğuna henüz ikna olmadım.
Louis Wasserman

8
Eski bir benzetme kullanacak olursak, "telefon rehberi" denen devasa şeyler vardı :-) ve senden birinin numarasına bakmanı isteseydim ve sen "o kişiye numara yok" dedim, ne yaparsın Yani orada listelenmemiş bir numarayla oradalar mı yoksa onlar için hiç giriş bulamadınız mı? " Bu iki olası yanıt, sırasıyla Optional.absent () ve null ile güzel bir şekilde eşleşir. Optional.absent () kesin "pozitif negatif" tir.
Kevin Bourrillion

3
@RAY: Bir bakıma, Optional<T> bir "bulduk ama geçerli değil" diye değer. Ya da daha doğrusu, Optional<T>bir yoludur süslemeleri her türlü Tmevcut iki tip birleştirerek yeni bir tür oluşturmak - Bir ekstralarla "buldular ancak bu geçerli" değer. Yüz tane sınıfınız varsa, her biri için ayrı bir "bulundu, ancak geçerli olmayan" değer oluşturmak Optional<T>zor olabilir , ancak hepsi için kolayca çalışabilir.
Daniel Pryden

9

Gerçekten MaybeHaskell'deki Monad modeline benziyor .

Aşağıdakini okumalısınız, Wikipedia Monad (işlevsel programlama) :

Ve Monad olarak kullanılan Guava'nın İsteğe Bağlı'sını tartışan Kerflyn'in Blog'unda Guava ile İsteğe Bağlı'dan Monad'a bölümünü okuyun :


Düzenleme: Java8 ile, gibi monadik operatörlere sahip yerleşik bir İsteğe Bağlı vardır flatMap. Bu tartışmalı bir konu oldu ama sonunda uygulandı.

Bkz. 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);

flatMapOperatör kolayca zincir aramaları hepsi dönüş Opsiyonel sonuçları için monadic işlemleri ve izinleri izin esastır.

Bir düşünün, mapoperatörü 5 kez Optional<Optional<Optional<Optional<Optional<String>>>>>kullanırsanız bir ile sonuçlanırken , kullanmak flatMapsize verirOptional<String>

Java8'den beri daha az güçlü olan Guava'nın İsteğe Bağlı'sını kullanmak istemiyorum.


6

Kullanmanın iyi bir nedeni, boş değerlerinizi çok anlamlı hale getirmesidir. Birçok şey ifade edebilecek bir boş değer döndürmek yerine (hata, başarısızlık veya boş gibi) boş değerinize bir 'ad' koyabilirsiniz. Şu örneğe bakın:

temel bir POJO tanımlayalım:

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;
}

}

Şimdi bu basit POJO'dan yararlanalım:

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);   
    }
}

Şimdi boş kullanmaktan kaçınalım ve kontrollerimizi İsteğe Bağlı ile yapalım, böylece anlamlı olsun

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());
}

böylece sonunda boşları anlamlı ve daha az belirsiz hale getirmenin bir yolu.


4

İsteğe bağlı özelliğin en önemli avantajı, uygulayıcı ile bir işlevi arayan arasındaki sözleşmeye daha fazla ayrıntı eklemesidir. Bu nedenle hem parametreler hem de dönüş türü için kullanışlıdır.

Kuralı her zaman Optionalolası boş nesnelere sahip olacak şekilde yaparsanız, aşağıdaki gibi durumlara daha fazla açıklama eklersiniz:

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

    Buradaki sözleşme, bir sonucun iade edilememe ihtimalinin olduğunu açıkça belirtmekle birlikte, bununla fromve toyok olarak çalışacağını da gösterir .

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

    Sözleşme, from öğesinin isteğe bağlı olduğunu belirtir, bu nedenle eksik bir değerin 2'den başlama gibi özel bir anlamı olabilir. toParametre için boş bir değerin bir istisna oluşturmasını bekleyebilirim .

Dolayısıyla, İsteğe Bağlı'yı kullanmanın iyi yanı, sözleşmenin hem açıklayıcı ( @NotNullek açıklamaya benzer ) hem de .get()başa çıkmanız için kod yazmanız gerektiğinden resmi hale gelmesidir Optional.


Boş bir Liste daha temiz olacakken neden bir İsteğe Bağlı <List> kullanılsın?
RAY

Dönüşte yanlış örneği seçtim. Koleksiyonlarla, kuralı her zaman boş bir değer yerine boş bir koleksiyon döndürecek şekilde yapabilirsiniz. Bu kural kullanılırsa, koleksiyonlar için isteğe bağlı olmanız gerekmez. Opsiyonel, sıfır veya bir element içeren bir koleksiyon olarak algılanabilir, bu nedenle başka bir koleksiyonun etrafına koymaya gerek yoktur.
rainercostin

2
bağlama bağlı olarak, 0 öğeli bir liste ile eksik bir liste arasında anlamlı bir fark olabilir.
plasma147
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.