Optional.ifPresent()の適切な使用法


94

Java 8のAPI のifPresent()メソッドを理解しようとしていOptionalます。

私は単純なロジックを持っています:

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

しかし、これによりコンパイルエラーが発生します。

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

もちろん、私はこのようなことをすることができます:

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

しかし、これは雑然としたnull小切手とまったく同じです。

コードをこれに変更すると:

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

コードが汚れてきているので、以前のnullチェックに戻ることを考えさせられます。

何か案は?

回答:


154

Optional<User>.ifPresent()かかるConsumer<? super User>引数として。型がvoidの式を渡しています。したがって、コンパイルされません。

コンシューマーはラムダ式として実装することを目的としています。

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

または、メソッド参照を使用してさらに簡単にします。

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

これは基本的に同じです

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

この考え方は、doSomethingWithUser()メソッド呼び出しはユーザーが存在する場合にのみ実行されるというものです。コードはメソッド呼び出しを直接実行し、そのvoid結果をに渡そうとしますifPresent()


2
そのコードは乱雑になっています... nullチェックははるかにクリーンになります。
doSomethingWithUser

4
どのコード?使用する必要があるのは、インスタンス(つまり、非静的)メソッドdoSomethingWithUser()を呼び出す2番目のメソッドです。雑然としているのがわかりません。最後のコードは、ラムダ前の世界のラムダに相当するものを説明するためにあります。使用しないでください。
JBニゼット2014年

2
はい。ただし、匿名クラスに慣れていて、同等の匿名クラスを見てラムダが何をするのかを理解しているかもしれません。それがポイントです。
JBニゼット2014年

1
変更するものはありません。そのままそれを残し、そして第二の例を使用する:user.ifPresent(this::doSomethingWithUser);
JB Nizet

10
@rayman返す関数Optional<User>がある場合、ローカル変数に格納する必要はありません。ただ、メソッド呼び出しをチェーン:funcThatMightReturnUser().ifPresent(this::doSomethingWithUser);
スチュアート・マークス

19

@ JBNizetの答えに加えて、私のための一般的なユースケースがifPresent結合することである.isPresent().get()

古い方法:

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

新しい方法:

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

これは、私には、より直感的です。


7

flatMapを使用します。値が存在する場合、flatMapはその値のみを含む順次Streamを返し、それ以外の場合は空のStreamを返します。したがって、を使用する必要はありませんifPresent()。例:

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

3
オプション::ストリームにはjava9が必要
avmohan

7

単純にすることができるのに、なぜ複雑なコードを書くのですか?

実際、Optionalクラスを絶対に使用する場合、最も単純なコードは、すでに記述したものです...

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

このコードには、

  1. 読みやすい
  2. デバッグが簡単(ブレークポイント)
  3. トリッキーではない

OracleがOptionalJava 8でクラスを追加したからといって、このクラスをすべての状況で使用する必要があるとは限りません。


1
ifPresentを使用する主な利点は、get()を手動で呼び出す必要がなくなることです。最初にisPresentを確認することを忘れがちなので、get()を手動で呼び出すとエラーが発生しやすくなりますが、ifPresentを使用する場合は忘れることはできません
dustinroepsch

1
では、「user」オブジェクトを使用するたびに、.ifPresent()を呼び出す必要があります。.ifPresent()を読みすぎるとコードがすぐに判読できなくなります。
schlebe

2
上のスペルミスを修正するために、あなたのプロフィールページVB.NetNetbeansののSQLServerPostgreSQLのMySQLは、とLINQのは、あなたが使用することができます私のサービスをもあります。対応するワードリストは
ピーター・モーテンセン

7

次のようなメソッド参照を使用できます。

user.ifPresent(ClassNameWhereMethodIs::doSomethingWithUser);

メソッドifPresent()Consumerオブジェクトをパラメーターとして取得し、(JavaDocから):「値が存在する場合は、その値で指定されたコンシューマーを呼び出します。」値それはあなたの変数ですuser

または、このメソッドdoSomethingWithUserUserクラス内にあり、そうでない場合はstatic、次のようにメソッド参照を使用できます。

user.ifPresent(this::doSomethingWithUser);

1
しかし、doSomethingWithUserは静的メソッドでもクラスでもありません。
レイマン2014年

@rayman [OK]を、そうでない場合は、静的なあなたは次のように行うことができます:user.ifPresent(new ClassNameWhereMethodIs()::doSomethingWithUser);
アレクサンドルPodkutin

7
あなたは、このように、彼が使用する必要があり、それはから呼び出されていた方法は、同じクラスであるように聞こえるOPから、ただ一つの方法を実行するために、クラスの新しいインスタンスを作成するべきではありません@AleksandrPodkutinuser.ifPresent(this::doSomethingWithUser);
マーヴ

@Marv同じクラスにあることの確認フォームOPが表示されません。しかし、あなたがそのような気持ちを持っているなら、私は彼が使用しなければならないことに同意しますuser.ifPresent(this::doSomethingWithUser);。回答に追加します。
Aleksandr Podkutin
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.