2017-06-20 12 views
4

Optionalが空であるか、その両方が存在するかどうかわかりません。アイデアは、この時点で私に警告している、私の実際のコードでなぜIdeaは `orElseGet`の` isPresent() `チェックがないのを警告しますか?

final Optional<String> a = Optional.of("1"); 
final Optional<String> b = Optional.empty(); 
if (a.isPresent() || b.isPresent()) { 
    // prefer a over b 
    Integer result = a 
     .map(s -> s + "0") 
     .map(Integer::parseInt) 
     .orElseGet(() -> Integer.parseInt(b.get())); // <-- warning for b.get() 
    System.out.println(result); 
} 

'Optional.get()' isPresent」せずに後者のケースでは、私はいつもbaを好むしたいです() 'チェック。

なぜですか? aまたはbが存在するかどうかを事前に確認しています。また、このコードは期待通りに機能し、出力は10です。 b = Optional.of("2")を入力した場合、出力は10です。これはaが好ましいからです。 a = Optional.empty()と入力すると、出力は期待どおり2になります。

私は何か間違っているのですか、またはアイデアの間違っていますか?

+3

これは 'a.isPresent()||によって混乱します。 b.isPresent() '条件があり、この状況下では' b'が存在しなければならないことがわかりません。 –

+1

@LouisWasserman、実際には条件はうまく処理されます。 IDEAは '!a.isPresent()'は '!a.map(anything).isPresent()'(これは今は分かっていません)を意味するだけです。また、lambda/methodrefを調べ、 'null'を返さないことを理解していなければなりません(そうでなければ、警告は正しい)。それはあまりにも多くの分析ですが、おそらく将来それを行うでしょう。 –

答えて

3

ここで混同されている考えは、isPresentと同じオプションチェーンのチェックを想定しています。

これは明らかにOptionalの外側にあり、(a.isPresent() || b.isPresent())のためにチェックされます。それはあなたがa.isPresent()とでb.isPresent()や状態を確認している...ので、これらのチェックの空のオプションborElseGetを呼び出すための方法がないことを

+0

私はリンターをよりスマートにして、この「OR」を検出できると思っていたでしょう。 'b.isPresent()'しかチェックしないと、警告が消えます。しかし、よく、確認していただきありがとうございます! – Blacklight

+2

@Blacklight正しいことは、このためのバグを記入し、それらのポイントを参照することです。開発者は*通常*非常に反応があります。あなたはこの方法でツールを改善するかもしれません。 – Eugene

+0

私の思考を最初に確認したいだけです。 – Blacklight

0

を教えてくれない可能性ができます。条件の最初の部分が真の "a.isPresent()"であるが、b.isPresent()は偽であることが判明したため警告が表示されています。しかし、||ブロック内のコードが実行を開始します。この場合、b.getは "NoSuchElementException"で失敗します。

あなたのロジックによれば、bが存在しないか空であれば、b.get()に到達できませんが、bを超えることが望ましいからです。しかし、IDEは分析して、すべてのことが間違っているか、あなたのコードで何が悪いことかを積極的に伝えます。

は次のように何かをするようにしてください:それは毛羽立ちのアイデアのように見える

if(a.isPresent()){ 
//logic if a is there 
} 
else if(b.isPresent){ 
//logic if a not there and b is there 
} 
else{ 
logic if both are not there 
} 
+0

私は確かにリンター警告を避けるためにそれをしている可能性がありますが、それは本当にポイントではありません。問題は、if節と端末操作の両方がわかっているときにIdeaが警告する理由をより指摘しました。 – Blacklight

+0

私は、IDEAが現在の変数の値だけでなく、間違って何が起こる可能性があるかを知っていることを警告していることを何度も見てきました。ここでは、b.get()が到達可能ではないが、bが空であることを知っているのでエラーを表示していることを知っているので、両方の組み合わせです。 –

4

この場合には間違っているが、それはそれはb.isPresent()a.orElseGet(...)フォールバックで保証されているかどうかの決定の複雑さをどうするだと考えられます。

は、一般的に私はIDEは何かについても警告している場合、それは通常は良いアイデア次の開発者がコードを見に来るようにも背後にある意図を解読するために苦労しそうだ、それを修正するために(しゃれがが意図した)ことがわかりますコード。

既にOptionalを使用しているので、私はisPresentメソッドを使用しないで、あなたのためにこのAPIを使用することを検討します。この警告を満たすはずの2つのオプション(punが)を見ることができます。

の両方が存在しない場合は、適切な代替を提供することができます:

final Optional<String> a = Optional.of("1"); 
final Optional<String> b = Optional.empty(); 

// prefer a over b 
Integer result = a 
    .map(s -> s + "0") 
    .map(Integer::parseInt) 
    .orElseGet(() -> b.map(Integer::parseInt).orElse(0)); 

System.out.println(result); 

を使用すると、両方が空であることを期待することはありません場合は、あなたの代わりにフォールバックのIllegalStateExceptionを投げることができます。

final Optional<String> a = Optional.of("1"); 
final Optional<String> b = Optional.empty(); 

// prefer a over b 
Integer result = a 
    .map(s -> s + "0") 
    .map(Integer::parseInt) 
    .orElseGet(() -> b.map(Integer::parseInt).orElseThrow(IllegalStateException::new)); 

System.out.println(result); 
+0

私はあなたの提案を、ありがとう。彼らは実際に警告を取り除く。私は実際に私の最初のコードはあまりにも複雑ではないと考えました..コード全体にif節を付ける代わりに、結果がnullかどうかをチェックするif節が必要です(整数は例のためだけです)。 try/catchブロック。そして、私は、コードをより明確に理解したり、より分かりやすいコードを見つけることはできません。それでも、良い選択肢、ありがとう。 – Blacklight

2

ロングストーリーショート:IDEA 2017.3で修正されました(IDEA-174759参照)。

はい、bは、b.get()ポイントに存在することが保証されています。そしてはい、IDEAの警告は間違っています。その理由は、現在のバージョンでのIDEA分析は、オプションのチェーン内で何が起こっているのかを理解するのに十分なほど洗練されていないからです。結果は、Integer::parseIntメソッド参照が決してnullを生成しないという事実にも依存することに注意してください。そうでない場合は、aが存在する場合でもOptional.mapは空のオプションを生成する可能性があります。 a非数値列を含む場合b警告が所望さを有するので、ここでは、存在しないかもしれない。この場合

private static Integer myParseInt(String s) { 
    try { 
     return Integer.parseInt(s); 
    } catch (NumberFormatException e) { 
     return null; 
    } 
} 

... 

if (a.isPresent() || b.isPresent()) { 
    // prefer a over b 
    Integer result = a.map(s -> s + "0").map(MyClass::myParseInt) 
         .orElseGet(() -> Integer.parseInt(b.get())); 
    System.out.println(result); 
} 

:、例えば、以下のコードを検討します。

IDEA静的解析を常に改善します。あなたは今、元のコードで表示されていない警告を見ることができるように

IDEA 2017.3

を、しかし、NULL値可能myParseIntについて表示:2017.3では、これらの構造を理解します。

IDEA 2017.3はまだ利用できません。ただし、この機能はIDEA Communityの一部であるため、masterブランチのGitHub sourcesを使用して自分で構築することができます。

免責事項:私はIntelliJ IDEA開発者であり、この問題を解決するために取り組んでいます。

+1

ありがとう、Tagir、非常に感謝し、非常に高速な反応。このような状況になる人がどれくらいいるか分かりませんが、私は間違いなく、Ideaが開発者のフィードバックに基づいて常に改善していることを知ってうれしいです。 – Blacklight

関連する問題