Java 8'in İsteğe Bağlı neden bağımsız değişkenlerde kullanılmamalıdır?


392

Birçok Web sitesinde okudum İsteğe bağlı bir dönüş türü olarak kullanılmalı ve yöntem bağımsız değişkenlerinde kullanılmamalıdır. Bunun mantıklı bir nedenini bulmak için uğraşıyorum. Örneğin, 2 isteğe bağlı parametreye sahip bir mantık parçam var. Bu nedenle yöntem imzamı bu şekilde yazmanın mantıklı olacağını düşünüyorum (çözüm 1):

public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {
    // my logic
}

Birçok web sayfası, isteğe bağlı olarak belirtilen yöntem bağımsız değişkenleri olarak kullanılmamalıdır. Bunu göz önünde bulundurarak, aşağıdaki yöntem imzasını kullanabilir ve argümanların boş olabileceğini belirtmek için açık bir Javadoc yorumu ekleyebilirim, gelecekteki koruyucular Javadoc'u okuyacak ve bu nedenle argümanları kullanmadan önce her zaman boş denetimler gerçekleştireceğini umarak :

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}

Alternatif olarak, daha güzel bir arayüz sağlamak ve daha belirgin p1 ve p2'nin isteğe bağlı olmasını sağlamak için yöntemimi dört genel yöntemle değiştirebilirim (çözüm 3):

public int calculateSomething() {
    calculateSomething(null, null);
}

public int calculateSomething(String p1) {
    calculateSomething(p1, null);
}

public int calculateSomething(BigDecimal p2) {
    calculateSomething(null, p2);
}

public int calculateSomething(String p1, BigDecimal p2) {
    // my logic
}

Şimdi her yaklaşım için bu mantık parçasını çağıran sınıfın kodunu yazmaya çalışıyorum. Önce iki giriş parametresini Optionals döndüren başka bir nesneden alıyorum ve sonra çağırıyorum calculateSomething. Bu nedenle, çözüm 1 kullanılırsa, çağrı kodu şöyle görünecektir:

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1, p2);

çözüm 2 kullanılırsa, çağıran kod şöyle görünür:

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));

çözüm 3 uygulanırsa, yukarıdaki kodu kullanabilir veya aşağıdakileri kullanabilirim (ancak önemli ölçüde daha fazla kod):

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result;
if (p1.isPresent()) {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p1, p2);
    } else {
        result = myObject.calculateSomething(p1);
    }
} else {
    if (p2.isPresent()) {
        result = myObject.calculateSomething(p2);
    } else {
        result = myObject.calculateSomething();
    }
}

Öyleyse sorum: Optionals'yi yöntem argümanları olarak kullanmak neden kötü uygulama olarak değerlendiriliyor (bkz. Çözüm 1)? Benim için en okunabilir çözüm gibi görünüyor ve parametrelerin gelecekteki koruyucular için boş / boş olabileceğini en açık hale getiriyor. (Tasarımcıların Optionalyalnızca bir dönüş türü olarak kullanılması amaçlandığını biliyorum, ancak bu senaryoda kullanmamak için mantıklı nedenler bulamıyorum).


16
Optionals kullandıysanız, parametre olarak geçirilen isteğe bağlı olup olmadığını kontrol etmeniz gerekmez nullmi?
biziclop

17
Evet, ancak gelecekte kodun boş / boş olabileceğini iddia eden bir başkası için açık olacaktır, bu nedenle gelecekte boş bir işaretçi istisnasından kaçınılabilir
Neil Stevens

1
Vay. Bir yönteme boş değerler mi aktarılıyor? Bu çok Visual Basic. Hangi prensibi ihlal ediyor? SRP (belki). Ayrıca adı beni terkeden başka bir ilkeyi de ihlal ediyor.
Aydınlık

20
Teorik olarak null olması gereken her şey kütüphanedeki System.exit (0) olarak adlandırılan her yöntem gibidir. Bunu kontrol edemezsiniz ve buna karşı kontrol etmemelisiniz. Her zaman yapmak zorunda olduğunuz her şey (neredeyse) asla yapmamalı. Tüm parametreleri nihai yapmak gibi. Araçlarınızın, kodunuzu bin finalde ve birçok boş kontrolle okunamaz hale getirmek yerine parametre değerlerini değiştirmenizi veya alanları başlatmayı unutmanızı önlemenize yardımcı olun.
yeoman

6
Aslında sadece Boş / Boş olmayan ek açıklamaları kullanın, bu durumda aradığınız şey budur, isteğe bağlı değil.
Bill K

Yanıtlar:


202

Oh, bu kodlama stilleri biraz tuzla alınmalı.

  1. (+) İsteğe bağlı bir sonucun herhangi bir anlamsal analiz yapılmadan başka bir yönteme geçirilmesi; bunu yönteme bırakmak oldukça iyidir.
  2. (-) Yöntemlerin içinde koşullu mantığa neden olan isteğe bağlı parametrelerin kullanılması, kelimenin tam anlamıyla kontra-üretkentir.
  3. (-) İsteğe bağlı bir argümanı paketlemenin gerekmesi derleyici için yetersizdir ve gereksiz bir kaydırma yapar.
  4. (-) Sıfırlanabilir parametrelerle karşılaştırıldığında İsteğe bağlı daha pahalıdır.

Genel olarak: İsteğe bağlı, çözülmesi gereken iki durumu birleştirir. Bu nedenle, veri akışının karmaşıklığı için girişten, sonuçtan daha uygundur.


38
Aslında, bir girişe sahip Optionalbir: parametre üç durumdan birini temsil nullİsteğe bağlı olmayan bir boş Optionalolan isPresent() == falseve olmayan bir boş Optionalbir gerçek değer sarma.
biziclop

16
@biziclop evet, kaçınılmaz bir nokta zaten eleştirildi. Ancak amaç yalnızca boş olmayan ifadeler kullanmaktır. Uzun sürmemesi, kaçınılması tavsiyesini duymak İsteğe bağlı olarak bazı durumlarda oldukça ironiktir. Bir @NotNull Optional.
Joop Eggen

80
@biziclop Hiç kullanmıyorsanız Optional, durum 1'in ( nullİsteğe bağlı) genellikle bir programlama hatası gösterdiğine dikkat edin, bu yüzden de halledemeyebilirsiniz (sadece NullPointerException
atayın

50
"derleyici için en düşük", "Null olabilecek parametrelerle karşılaştırıldığında İsteğe bağlı daha pahalıdır" - bu bağımsız değişkenler C dili için geçerli olabilir, Java dili için geçerli olmayabilir. Java programcıları temiz kod, taşınabilirlik, test edilebilirlik, iyi mimari, modülerlik vb. Üzerine odaklanmalı ve "İsteğe bağlı boş referanstan daha pahalıya" odaklanmamalıdır. Mikro optimizasyonlara odaklanmanız gerektiğini düşünüyorsanız, Nesneleri, Listeleri, Jenerikleri atlamanız ve dizilere ve ilkellere geçmeniz daha iyi olur (burada saldırgan olmak istemiyorum, sadece fikrimi paylaşıyorum) .
Kacper86

15
"derleyici için yetersiz": Erken optimizasyon tüm kötülüğün köküdür ... Eğer performans kritik kodu yazmıyorsanız (temiz bir arayüz belirtmeye çalışırken genellikle durum budur), bu bir endişe olmamalıdır.
Mohan

165

Bu konuda gördüğüm en iyi gönderi Daniel Olszewski tarafından yazılmıştır :

Zorunlu olmayan yöntem parametreleri için isteğe bağlı olarak düşünmek cazip gelse de, böyle bir çözüm diğer olası alternatiflerle karşılaştırıldığında soluklaşır. Sorunu göstermek için aşağıdaki yapıcı bildirimini inceleyin:

public SystemMessage(String title, String content, Optional<Attachment> attachment) {
    // assigning field values
}

İlk bakışta doğru bir tasarım kararı gibi görünebilir. Sonuçta, attachment parametresini açıkça isteğe bağlı olarak işaretledik. Ancak, yapıcı çağrıldığında, istemci kodu biraz sakar hale gelebilir.

SystemMessage withoutAttachment = new SystemMessage("title", "content", Optional.empty());
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", Optional.ofNullable(attachment));

Netlik sağlamak yerine, İsteğe bağlı sınıfın fabrika yöntemleri yalnızca okuyucuyu dağıtır. Sadece bir isteğe bağlı parametre olduğunu unutmayın, ancak iki veya üç tane olduğunu düşünün. Bob Amca kesinlikle böyle bir kodla gurur duymazdı 😉

Bir yöntem isteğe bağlı parametreleri kabul edebildiğinde, kanıtlanmış yaklaşımı benimsemek ve yöntem aşırı yüklemesi kullanarak böyle bir durumu tasarlamak tercih edilir. SystemMessage sınıfı örneğinde, iki ayrı kurucunun bildirilmesi, İsteğe bağlı kullanımından daha üstündür.

public SystemMessage(String title, String content) {
    this(title, content, null);
}

public SystemMessage(String title, String content, Attachment attachment) {
    // assigning field values
}

Bu değişiklik, istemci kodunu daha basit ve okunmasını kolaylaştırır.

SystemMessage withoutAttachment = new SystemMessage("title", "content");
Attachment attachment = new Attachment();
SystemMessage withAttachment = new SystemMessage("title", "content", attachment);

10
Bu, yalnızca bir veya iki paragraf alakalı olduğunda çok sayıda kopyala + yapıştır işlemidir.
Garret Wilson

47
Ne yazık ki bu açıklama, arayanın örneğin bazı bilgileri ayrıştırması konusunda endişe duymaz, isteğe bağlı olabilir. Yöntemin aşırı yüklenmesi ile (yukarıda önerildiği gibi), arama kodu "X mevcut mu? Varsa aşırı yüklenmiş yöntem A'yı arayacağım. Y mevcut mu? Aşırı yüklenmiş B yöntemini çağırmalıyım. X ve Y mevcut, aşırı yüklenmiş C yöntemini çağırmam gerekecek. " Ve bunun gibi. Bunun iyi bir cevabı olabilir, ama "neden" in bu açıklaması bunu kapsamıyor.
Garret Wilson

9
Ayrıca, koleksiyonlar söz konusu olduğunda, boş bir koleksiyon ile koleksiyon yok arasında belirgin bir fark vardır. Örneğin, bir önbellek. Önbellek kaçtı mı? boş isteğe bağlı / null. Boş bir koleksiyon olan bir önbellek vuruşu oldu mu? tam isteğe bağlı / toplama.
Ajax

1
@Ajax Sanırım makaleyi yanlış anlıyorsunuz. Etkili Java kitabı tarafından savunulan bir noktaya değiniyorlar ; bu, bir yöntem döndürme türü bir Koleksiyon olduğunda (önbellek olarak rastgele bir nesne değil), nullveya yerine boş bir koleksiyon döndürmeyi tercih etmeniz gerektiğini söyler Optional.
Gili

4
Elbette, bunu tercih etmelisiniz , ancak her zaman bazı kodlar üzerinde kontrole sahip değilsiniz ve çok gerçek anlamda, "bir değer var ve boş bir koleksiyon" yerine "hayır" arasında ayrım yapmak isteyebilirsiniz. msgstr "henüz tanımlanmamış değer". "Sihirli boş" aynı zamanda cesareti kırılmış bir uygulama olduğundan, en az kötü seçeneği seçmek size, geliştiriciye bağlıdır. Ben gerçek önbelleğe değeri olabilir, çünkü boş bir koleksiyon yerine bir önbellek temsil etmek boş Seçimlik tercih olmak boş bir koleksiyon.
Ajax

86

OptionalParametre olarak kullanmamanın neredeyse hiçbir nedeni yoktur . Buna karşı olan argümanlar otoriteden gelen argümanlara dayanır (bkz. Brian Goetz - argümanı boş olmayan opsiyonları uygulayamamamızdır) ya da Optionalargümanların boş olabileceğidir (aslında aynı argüman). Elbette, Java'daki herhangi bir referans boş olabilir, programcıların belleğini değil (sorunlu ve ölçeksiz) kuralları derleyici tarafından uygulanmasını teşvik etmeliyiz.

Fonksiyonel programlama dilleri Optionalparametreleri teşvik eder . Bunu kullanmanın en iyi yollarından biri, birden fazla isteğe bağlı parametreye sahip olmak liftM2ve parametrelerin boş olmadığını ve isteğe bağlı olarak dönen bir işlevi kullanmaktır (bkz. Http://www.functionaljava.org/javadoc/4.4/functionaljava/fj/ data / Option.html # liftM2-fj.F- ). Java 8, maalesef isteğe bağlı destekleyen çok sınırlı bir kütüphane uygulamıştır.

Java programcıları olarak yalnızca eski kitaplıklarla etkileşim kurmak için null kullanmalıyız.


3
Nasıl kullanma hakkında @Nonnullve @Nullableyerine javax.annotation gelen? Onları geliştirdiğim bir kütüphanede yaygın olarak kullanıyorum ve IDE (IntelliJ) tarafından sağlanan destek çok iyi.
Rogério

1
Bu iyi, ancak bu ek açıklamayı her yerde kullanmanız gerekiyor ve harita, flatMap / bind, liftM2, sıra vb. Gibi yöntemleri desteklemek için bir kütüphaneye ihtiyacınız var
Mark Perry

14
Fonksiyonel programlama dilleri Opsiyonel parametreleri teşvik eder. Kaynak belirtilmeli. Çoğu işlev isteğe bağlı olmamalıdır; bunun yerine, bir değerin varlığı ya da yokluğu ile ilgilenme (uygun yüksek dereceli fonksiyonları kullanarak) söz konusu fonksiyonun arayanıdır.
jub0bs

5
Bu. Gerçekten de, cevapların hiçbiri yeteri kadar inandırıcı olup, bunların hiçbiri bu özel sorunun cevabının "ile yöntem parametreleri annotating ederken kötü bir uygulama olarak kabul edilir neden yöntem parametreleri olarak isteğe bağlı öğeleri kullanarak @NonNulltamamen iyi farklı şekillerde aynı amaca hizmet eğer mi?" Benim için, en azından bir anlam ifade eden tek bir argüman var: "Net bir dönüş türüne sahip daha iyi API'ler sağlamak için isteğe bağlı kullanılmalıdır. Ancak yöntem bağımsız değişkenleri için aşırı yüklenmiş işlevler kullanılabilir." - yine de, bunun yeterince güçlü bir argüman olduğunu düşünmüyorum.
Utku Özdemir

1
Tabii ki, null için tercih edilebilir, ancak daha da tercih edilen şey, ilk etapta çok fazla isteğe bağlı değere ihtiyaç duymamaktır, çünkü iyi tasarım: D
yeoman

12

Bu tavsiye, "girdiler hakkında olabildiğince belirsiz ve çıktılar hakkında mümkün olduğunca spesifik" kuralının bir çeşitidir.

Genellikle düz null olmayan bir değer alan bir yönteminiz varsa, üzerinde eşleştirebilirsiniz Optional, böylece düz sürüm girdilerle ilgili olarak daha spesifik değildir. Bununla birlikte, Optionalyine de bir tartışmaya ihtiyaç duymanızın bir takım olası nedenleri vardır :

  • işlevinizin bir döndüren başka bir API ile birlikte kullanılmasını istiyorsanız Optional
  • OptionalVerilen değer boşsa işleviniz boş dışında bir şey döndürmelidir
  • OptionalAPI'nızı kullanan her şey hakkında bilgi edinmek için o kadar harika olduğunu düşünüyorsunuz ;-)

10

İle desen geri dönmekOptional için biri içindir . Bir yönteme geçmek hala mükemmel bir şekilde mümkündür . nullnull

Bunlar henüz resmi olmasa da, işleve değerleri kabul edip etmediğinizi belirtmek için JSR-308 stil ek açıklamalarını kullanabilirsiniz null. Bunu gerçekten tanımlamak için doğru araçlara sahip olmanız gerektiğini ve uygulanabilir bir çalışma zamanı politikasından daha statik bir kontrol sağlayacağını unutmayın, ancak bu yardımcı olacaktır.

public int calculateSomething(@NotNull final String p1, @NotNull final String p2) {}

Buradaki problem, @NotNull'un varsayılan durum olmadığı ve açık bir şekilde açıklanması gerektiğidir - bu nedenle kaynatma plakası ve insanların tembellik nedeniyle yapmayacağı şeyler.
2016

1
@ dwegener Evet, ancak Optionalsorunu da çözmüyor, bu nedenle ek açıklamalar için önerim.
Makoto

2
Yoksaymak çok daha zor Opsiyonel olarak sadece dokümanlar / kaynak okunduğunda veya takımınız onu yakalayabildiğinde fark edeceğiniz bir notu görmezden gelmekten daha zordur (statik analiz her zaman nullabiliteyi doğru bir şekilde belirleyemez).
Ajax

@Nullable öğesinin null değerini geçerli bir değer olarak "kabul ettiğiniz" anlamına gelmeyebileceğini, yani herhangi bir istisna atmayabileceğinizi unutmayın. Bu sadece bu davaya karşı korunduğunuz anlamına gelebilir, ancak yine de bir istisna atacaktır (Bu Findbugs anlambilimidir). Böylece netlik yerine bu tür ek açıklamalarla belirsizlik sağlayabilirsiniz.
tkruse

@ User2986984'in hangi belirsizliğinden emin değilim. "Null değerinin ele alınmaması" yalnızca gerçekçi olarak bir istisna atıldığı anlamına gelebilir.
Makoto

7

Bu benim için biraz aptalca görünüyor, ama düşünebilmemin tek nedeni, yöntem parametrelerindeki nesne argümanlarının zaten bir şekilde isteğe bağlı olması - boş olabilirler. Bu nedenle, birini mevcut bir nesneyi alıp isteğe bağlı olarak sarmaya zorlamak anlamsızdır.

Bununla birlikte, alma / iade opsiyonellerini bir araya getirme yöntemlerinin birlikte yapılması makul bir şeydir, örneğin Belki monad.


7
Değerler ve alanlar da boş olamaz mı? Yani Optionaltamamen anlamsızdır?
Samuel Edwin Ward


4

Benim almam, İsteğe bağlı bir Monad olmalı ve bunlar Java'da düşünülemez.

Fonksiyonel programlamada, argümanlarını yalnızca "işletme alanı türlerine" göre alan ve oluşturan saf ve daha üst düzey işlevlerle ilgilenirsiniz. Gerçek dünyayı (yan etkiler olarak adlandırılan) beslenen veya hesaplanması gereken işlevler oluşturmak için, dış dünyayı temsil eden monad'lardan değerleri otomatik olarak açmaya özen gösteren işlevlerin uygulanması gerekir (Devlet, Yapılandırma, Futures, Belki, Ya Yazar, vb ...); buna kaldırma denir. Bunu bir tür endişelerin ayrılması olarak düşünebilirsiniz.

Bu iki soyutlama düzeyini karıştırmak okunabilirliği kolaylaştırmaz, böylece bundan kaçınmanız daha iyi olur.


3

Bir Optionalas parametresini geçirirken dikkatli olmanın bir başka nedeni , bir yöntemin bir şey yapması gerektiğidir ... Bir Optionalparam geçirirseniz, birden fazla şey yapmayı tercih edebilirsiniz, boolean bir param geçirmeye benzer.

public void method(Optional<MyClass> param) {
     if(param.isPresent()) {
         //do something
     } else {
         //do some other
     }
 }

Bence bu iyi bir sebep değil. İsteğe bağlı kullanılmadığında parametrenin boş olup olmadığını kontrol etmek için aynı mantık uygulanabilir. Aslında, if(param.isPresent())isteğe bağlı kullanmak için en iyi yaklaşım değildir, bunun yerine şunları kullanabilirsiniz:param.forEach(() -> {...})
hdkrus

Sıfırlanabilir paramları geçirme fikrini de sevmiyorum. Her neyse, tercih edebileceğinizi söyledim, elbette kullanabileceğiniz istisnalar var, size kalmış, sadece dikkatli kullanın, hepsi bu. Tüm senaryolar için geçerli bir kural yoktur.
Pau

2

İsteğe bağlı olarak parametre olarak kabul etmek, arayan düzeyinde gereksiz sarmaya neden olur.

Örneğin:

public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {}

İki boş olmayan dizeniz olduğunu varsayalım (başka bir yöntemden döndürülen):

String p1 = "p1"; 
String p2 = "p2";

Boş olmadıklarını bilseniz bile onları İsteğe Bağlı olarak sarmak zorundasınız.

Diğer "eşlenebilir" yapılarla, yani. Eithers :

Either<Error, String> value = compute().right().map((s) -> calculateSomething(
< here you have to wrap the parameter in a Optional even if you know it's a 
  string >));

ref:

yöntemler parametre olarak seçenek beklememelidir, bu neredeyse her zaman arayandan arayan kişiye kontrol akışının sızıntısını gösteren bir kod kokusudur, bir opsiyonun içeriğini kontrol etmek arayanın sorumluluğunda olmalıdır.

ref. https://github.com/teamdigitale/digital-citizenship-functions/pull/148#discussion_r170862749


1

Ben genellikle verileri işlemek için Fonksiyonlarınızı yazmak ve sonra onu kaldırın çünkü olduğunu düşünüyorum Optionalkullanarak mapve benzeri fonksiyonlar. Bu, varsayılan Optionaldavranışı ekler . Tabii ki, üzerinde çalışan kendi yardımcı fonksiyonunuzu yazmanız gerektiğinde durumlar olabilir Optional.


1

Varlığın yankısı ilk önce İsteğe bağlı null olup olmadığını kontrol etmek ve sonra sardığı değeri değerlendirmek zorunda olduğuna inanıyorum. Çok fazla gereksiz doğrulama var.


2
Bir boş iletme İsteğe bağlı başvuru bir programlama hatası olarak kabul edilebilir (İsteğe bağlı, "boş" bir değer iletmenin açık bir yolunu sağladığı için ), her durumda istisna atmaktan kaçınmak istemiyorsanız, kontrol etmeye değmez.
pvgoran

1

Brian Goetz tarafından güzel açıklandığı gibi opsiyoneller bu amaç için tasarlanmamıştır .

Bir yöntem bağımsız değişkeninin boş olabileceğini göstermek için her zaman @Nullable öğesini kullanabilirsiniz . İsteğe bağlı bir yöntem kullanmak, yöntem mantığınızı daha düzgün yazmanıza olanak tanımaz.


5
Üzgünüm, ama "tasarlanmadı" ya da "birileri buna karşı tavsiye ediyor" iddiasını kabul edemiyorum. Bir mühendis, spesifik olmalıyız. İsteğe bağlı, API açısından çok daha ayrıntılı olduğundan @Nullable kullanımı İsteğe bağlı kullanımı çok daha kötüdür. Optionals'ı argüman olarak kullanmaya karşı iyi bir neden görmüyorum (yöntem aşırı yüklemeyi kullanmak istemiyorsanız)
Kacper86

0

Bir yaklaşım daha, yapabileceğiniz şey

// get your optionals first
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();

// bind values to a function
Supplier<Integer> calculatedValueSupplier = () -> { // your logic here using both optional as state}

Bir işlev (bu durumda tedarikçi) oluşturduktan sonra, bunu başka bir değişken olarak aktarabilir ve kullanarak bu işlevi çağırabilirsiniz.

calculatedValueSupplier.apply();

Buradaki fikir, isteğe bağlı değere sahip olup olmamanız, işlevinizin dahili detayı olacak ve parametrede olmayacaktır. İsteğe bağlı olarak parametre olarak düşünürken düşünme işlevleri aslında bulduğum çok kullanışlı bir tekniktir.

Sorunuzla ilgili olarak gerçekten yapmanız gerekip gerekmemesi tercihinize bağlıdır, ancak diğerlerinin söylediği gibi API'nızı en az söylemek çirkin hale getirir.


0

İlk başta, Optionals'ı parametre olarak iletmeyi tercih ettim, ancak API-Designer perspektifinden API-User perspektifine geçerseniz, dezavantajları görürsünüz.

Her parametrenin isteğe bağlı olduğu örneğin, hesaplama yöntemini aşağıdaki gibi kendi sınıfına değiştirmenizi öneririm:

Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();

MyCalculator mc = new MyCalculator();
p1.map(mc::setP1);
p2.map(mc::setP2);
int result = mc.calculate();

0

Bu sorunun zor gerçeklerden ziyade fikirle ilgili olduğunu biliyorum. Ancak son zamanlarda bir .net geliştiricisi olmaktan çıkarak bir java geliştiricisine geçtim. Ayrıca, bunu bir yorum olarak belirtmeyi tercih ederim, ancak puan seviyem yorum yapmama izin vermediğinden, bunun yerine bir cevap olarak koymak zorunda kalıyorum.

Yaptığım şey, bana bir kural olarak iyi hizmet etti. Dönüş türleri için Optionals kullanmak ve parametreler olarak Optionals kullanmak, isteğe bağlı hem de hava durumu gerekir veya isteğe bağlı değil isteğe bağlı yöntem içinde bir değer vardı.

Ben sadece değer umurumda, ben yöntemi çağırmadan önce isPresent kontrol, eğer değer varsa bağlıdır yöntemi içinde günlük veya farklı bir mantık varsa, o zaman ben mutlu Opsiyonel geçer.


0

Bunun nedeni, bir API kullanıcısı ve bir API geliştiricisi için farklı gereksinimlerimiz olmasıdır.

Bir geliştirici kesin bir şartname ve doğru bir uygulama sağlamaktan sorumludur. Bu nedenle, geliştirici bir argümanın isteğe bağlı olduğunu zaten biliyorsa, uygulama null veya İsteğe bağlı olsun, bununla doğru bir şekilde ilgilenmelidir. API kullanıcı için olabildiğince basit olmalıdır ve null en basitidir.

Öte yandan, sonuç API geliştiricisinden kullanıcıya geçirilir. Şartname eksiksiz ve ayrıntılı olsa da, kullanıcının hala farkında olmadığından veya onunla başa çıkmak için tembel olma ihtimali vardır. Bu durumda, İsteğe bağlı sonuç kullanıcıyı olası boş bir sonuçla başa çıkmak için ekstra kod yazmaya zorlar.


0

Her şeyden önce, yöntem 3'ü kullanıyorsanız, son 14 kod satırını bununla değiştirebilirsiniz:

int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));

Yazdığınız dört varyasyon kolaylık yöntemleridir. Bunları yalnızca daha uygun olduklarında kullanmalısınız. Bu da en iyi yaklaşım. Bu şekilde, API hangi üyelerin gerekli ve hangilerinin gerekli olmadığı çok açıktır. Dört yöntem yazmak istemiyorsanız, parametrelerinize nasıl ad verdiğinizi açıklığa kavuşturabilirsiniz:

public int calculateSomething(String p1OrNull, BigDecimal p2OrNull)

Bu şekilde, null değerlere izin verildiği açıktır.

Kullanımınız, p1.orElse(null)İsteğe Bağlı kullanırken kodumuzun ne kadar ayrıntılı olduğunu gösterir, bu da neden kaçındığımın bir parçasıdır. Fonksiyonel programlama için opsiyonel yazılmıştır. Akışların buna ihtiyacı var. Fonksiyonel programlamada kullanmanız gerekmedikçe yöntemleriniz muhtemelen asla İsteğe Bağlı döndürmemelidir. Optional.flatMap()İsteğe bağlı döndüren bir işleve başvuru gerektiren yöntem gibi yöntemler vardır . İşte imzası:

public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)

Bu nedenle, genellikle İsteğe Bağlı döndüren bir yöntem yazmanın tek iyi nedeni budur. Ama orada bile, önlenebilir. İsteğe bağlı olmayan bir alıcıyı flatMap () gibi bir yönteme, işlevi doğru türe dönüştüren başka bir yöntemle sararak iletebilirsiniz. Sarma yöntemi şuna benzer:

public static <T, U> Function<? super T, Optional<U>> optFun(Function<T, U> function) {
    return t -> Optional.ofNullable(function.apply(t));
}

Diyelim ki böyle bir alıcıya sahipsin: String getName()

Bunun gibi flatMap'e geçiremezsiniz:

opt.flatMap(Widget::getName) // Won't work!

Ancak şu şekilde iletebilirsiniz:

opt.flatMap(optFun(Widget::getName)) // Works great!

Fonksiyonel programlama dışında Seçeneklerden kaçınılmalıdır.

Brian Goetz bunu söylediğinde en iyisini söyledi:

İsteğe Bağlı Java'nın eklenmesinin nedeni şudur:

return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
    .stream()
    .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
    .filter(m ->  Arrays.equals(m.getParameterTypes(), parameterClasses))
    .filter(m -> Objects.equals(m.getReturnType(), returnType))
    .findFirst()
    .getOrThrow(() -> new InternalError(...));

bundan daha temiz:

Method matching =
    Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
    .stream()
    .filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
    .filter(m ->  Arrays.equals(m.getParameterTypes(), parameterClasses))
    .filter(m -> Objects.equals(m.getReturnType(), returnType))
    .getFirst();
if (matching == null)
  throw new InternalError("Enclosing method not found");
return matching;

1
Java'ya eklenmesinin sebeplerinden biri budur. Çok daha fazlası var. Veri yapısına geçen iç içe 'if' ifadelerinin uzun zincirlerini, Optional.map zincirleme çağrılarının tek bir sırası ile değiştirmek kişisel favorimdir. Fonksiyonel Diller programlama dünyası, isteğe bağlı olarak bunun gibi null kontrolleri değiştirmenin yanı sıra birçok ilginç kullanım alanına sahiptir.
Bazı
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.