Optional.ifPresent () öğesinin doğru kullanımı


99

Java 8'de API'nin ifPresent()yöntemini anlamaya çalışıyorum Optional.

Basit mantığım var:

Optional<User> user=...
user.ifPresent(doSomethingWithUser(user.get()));

Ancak bu, bir derleme hatasıyla sonuçlanır:

ifPresent(java.util.functionError:(186, 74) java: 'void' type not allowed here)

Tabii ki bunun gibi bir şey yapabilirim:

if(user.isPresent())
{
  doSomethingWithUser(user.get());
}

Ancak bu tam olarak dağınık bir nullçek gibi .

Kodu şununla değiştirirsem:

 user.ifPresent(new Consumer<User>() {
            @Override public void accept(User user) {
                doSomethingWithUser(user.get());
            }
        });

Kod gittikçe kirleniyor ve bu da bana eski nullçeke dönmeyi düşündürüyor .

Herhangi bir fikir?

Yanıtlar:


160

Optional<User>.ifPresent()Consumer<? super User>argüman olarak alır . Ona türü geçersiz bir ifade geçiriyorsunuz. Böylece bu derlemez.

Bir Tüketici, lambda ifadesi olarak uygulanmak üzere tasarlanmıştır:

Optional<User> user = ...
user.ifPresent(theUser -> doSomethingWithUser(theUser));

Veya bir yöntem referansı kullanarak daha da basit:

Optional<User> user = ...
user.ifPresent(this::doSomethingWithUser);

Bu temelde aynı şey

Optional<User> user = ...
user.ifPresent(new Consumer<User>() {
    @Override
    public void accept(User theUser) {
        doSomethingWithUser(theUser);
    }
});

Buradaki fikir, doSomethingWithUser()yöntem çağrısının yalnızca kullanıcı mevcutsa yürütüleceğidir. Kodunuz yöntem çağrısını doğrudan yürütür ve void sonucunu öğesine iletmeye çalışır ifPresent().


2
Bu kod dağınık hale geliyor .. sıfır kontrolü çok daha temiz olacak. özellikle bunu yapanSomethingWithUser'ın statik bir yöntem olmadığını düşünmüyor musunuz?
rayman

4
Hangi kod? Kullanmanız gereken, doSomethingWithUser () örneğini (yani statik olmayan) yöntemini çağıran ikincisidir. Nasıl darmadağın olduğunu anlamıyorum. Son kod, size lambda öncesi bir dünyadaki lambda eşdeğerini açıklamak içindir. Onu kullanma.
JB Nizet

2
Evet, ancak anonim sınıflara alışmış olabilirsiniz ve bu nedenle anonim bir sınıf eşdeğerini görerek lambda'nın ne yaptığını anlayabilirsiniz. Konu bu.
JB Nizet

1
Değiştirecek hiçbir şeyin yok. user.ifPresent(this::doSomethingWithUser);
Olduğu

11
@rayman Dönen bir işleviniz Optional<User>varsa, onu yerel bir değişkende saklamanıza genellikle gerek yoktur. Sadece yöntem çağrılarını zincirleyin:funcThatMightReturnUser().ifPresent(this::doSomethingWithUser);
Stuart Marks

21

@ JBNizet'in cevabına ek olarak, genel kullanım durumum ifPresentbirleştirmek .isPresent()ve .get():

Eski yol:

Optional opt = getIntOptional();
if(opt.isPresent()) {
    Integer value = opt.get();
    // do something with value
}

Yeni yol:

Optional opt = getIntOptional();
opt.ifPresent(value -> {
    // do something with value
})

Bu benim için daha sezgisel.


9

Basitleştirebilecekken neden karmaşık kod yazasınız?

Nitekim Optionaldersi kesinlikle kullanacaksanız , en basit kod zaten yazmış olduğunuz koddur ...

if (user.isPresent())
{
    doSomethingWithUser(user.get());
}

Bu kodun olmanın avantajları vardır

  1. okunabilir
  2. hata ayıklaması kolay (kesme noktası)
  3. zor değil

Sırf Oracle'ın Optionalsınıfı Java 8'e eklemiş olması, bu sınıfın her durumda kullanılması gerektiği anlamına gelmez.


1
İfPresent kullanmanın en büyük yararı, get () öğesini manuel olarak çağırma ihtiyacını ortadan kaldırmasıdır. Önce isPresent'i kontrol etmeyi unutmak kolay olduğu için get () 'i manuel olarak çağırmak hataya meyillidir, ancak ifPresent kullanırsanız unutmanız imkansızdır
dustinroepsch

1
Tamam ve 'user' nesnesini her kullanacağınız zaman .ifPresent () 'i çağırmalısınız. Çok fazla zaman .ifPresent () okuyacağınız için kod hızla okunamaz hale gelecektir!
schlebe

2
Profil sayfanızdaki ( VB.Net , Netbeans , SqlServer , PostGresql , MySql ve Linq) yazım hatalarını düzeltmek için hizmetimi kullanabilirsiniz . Buna karşılık gelen bir kelime listesi de var .
Peter Mortensen

7

FlatMap'i kullanın. Bir değer varsa, flatMap yalnızca bu değeri içeren sıralı bir Akış döndürür, aksi takdirde boş bir Akış döndürür. Yani kullanmaya gerek yok ifPresent(). Misal:

list.stream().map(data -> data.getSomeValue).map(this::getOptinalValue).flatMap(Optional::stream).collect(Collectors.toList());

3
Optional :: stream java9 gerektiriyor
avmohan

7

Yöntem referansını şu şekilde kullanabilirsiniz:

user.ifPresent(ClassNameWhereMethodIs::doSomethingWithUser);

Yöntem ifPresent()get Consumerobject as a paremeter and (from JavaDoc ): "Bir değer varsa, belirtilen tüketiciyi değerle çağırın." Değer sizin değişkeninizdir user.

Bu yöntem Ya doSomethingWithUseriçindedir Usersınıf ve değil staticböyle bir yöntem başvuru kullanabilirsiniz:

user.ifPresent(this::doSomethingWithUser);

1
Ancak doSomethingWithUser statik bir yöntem veya sınıfı değildir.
rayman

@rayman Tamam, statik değilse şunu yapabilirsin:user.ifPresent(new ClassNameWhereMethodIs()::doSomethingWithUser);
Aleksandr Podkutin

7
Sınıfın yeni bir örneğini oluşturmak gerekir @AleksandrPodkutin sadece böylece o kullanmalıdır, bu çağrılan ediliyor olarak yöntem aynı sınıfta olduğu gibi geliyor OP, bir yöntemini çalıştırmak içinuser.ifPresent(this::doSomethingWithUser);
Marv

@Marv Aynı sınıfta olduğuna dair herhangi bir onay formu OP göremiyorum. Ama böyle duyguların varsa, kullanmak zorunda olduğuna katılıyorum user.ifPresent(this::doSomethingWithUser);. Cevabıma ekleyeceğim.
Aleksandr Podkutin
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.