2017-11-28 5 views
2

以下のコードは、要約すると、2番目のパラメータにあるエンティティの最初のパラメータをフィルタリングすることを意味します。また、第2パラメータで「変更」が指定された場合は、より狭い結果をフィルタリングする必要があります。

これを実行すると、「IllegalStateException:ストリームが既に操作されているか、閉じています」というエラーが表示されます。

同じストリームを再利用できる方法はありますか?
私はサプライヤー>のようなものを実装している人を見てきましたが、このケースではうまくいかないと思います。または、サプライヤをどのように使用することができるかを理解するためには、それに慣れていません。

追加のフィルタリングが必要なときにストリームを再利用する - Java

/** 
    * Filters through DocumentAuditEntityListing to find existence of the entities 
    * ActionEnum, ActionContextEnum, LevelEnum, & StatusEnum. 
    * 
    * @param audits A list of audits to search 
    * @param toFind The audit entities to find 
    * @return If entities found, return DocumentAudit, else null 
    */ 
    public DocumentAudit verifyAudit(DocumentAuditEntityListing audits, DocumentAudit toFind) { 
     //Filter for proper entities 
     Stream stream = audits.getEntities().stream().filter(doc -> (
       doc.getAction().equals(toFind.getAction())) && 
       doc.getActionContext().equals(toFind.getActionContext()) && 
       doc.getLevel().equals(toFind.getLevel()) && 
       doc.getStatus().equals(toFind.getStatus())); 

     //If changes were specified, filter further. 
     if (toFind.getChanges() != null){ 
      stream.filter(change -> (toFind.getChanges().contains(change))); 
     } 

     return (DocumentAudit) stream.findFirst().orElse(null); 
    } 
+0

ストリームには、端末方式と非終端方式があります。 mapやfilterのような非終端メソッドは遅延メソッドです。つまり、端末メソッドが呼び出されるまで実際に何もしません。これは、@ Kayamanの説明に従ってフィルタを追加するだけでストリームに「追加」する必要があることを意味しますが、ストリームを「再利用」していないのは、 'findFirst( )。orElse(null) ' – Novaterata

+1

良い質問ですが、実際にエラーメッセージから理解するのは簡単ではありません。本質的にあなたのストリームは一度しか消費されません*しかし、それはエラーメッセージが言っているものではありません... https://stackoverflow.com/a/47548077/1059372 – Eugene

答えて

7

あなたはstream = stream.filter(change -> ...)と結果のストリームを割り当てる必要があります。

また、ストリームをタイプセーフにします(つまり、Stream<DocumentAudit>)。 GenericsはJava 5以降で使用されていますので、生の型を使用する言い訳はありません。

 Stream<DocumentAudio> stream = audits.getEntities().stream() 
      .filter(doc -> 
       doc.getAction().equals(toFind.getAction())) && 
       doc.getActionContext().equals(toFind.getActionContext()) && 
       doc.getLevel().equals(toFind.getLevel()) && 
       doc.getStatus().equals(toFind.getStatus()); 


     if (toFind.getChanges() != null){ 
      stream = stream.filter(change -> toFind.getChanges().contains(change)); 
     } 

     return stream.findFirst().orElse(null); 
2

Supplierトリックではなく、単に新しいストリームの作成を容易にするために使用されます。ルールは変わりません。ストリームを再利用することはできません。

Supplier<Stream<Something>> sup =() -> yourList.stream(); 

ですから、sup.get()あなたを呼び出すたびに新しいStreamを得ている:Supplierを使用する一般的なアプローチは、このようなものです。これには何の工夫もありません。

実際、あなたの質問は私がすでにこのように見たものとは少し異なります。

Stream<Some> s = ... 

s.filter 
s.filter 
s.forEach 

をそして私はstream has already been operated upon or closedが何を意味するのか、ここで誤解を招くようなビットは、単一の端末または中間操作は、単一のStreamに1回だけ適用することができ、実際にあるエラーメッセージを検索する:基本的にはやっています。これがエラーメッセージでより明確になったなら、それはより理にかなっています。

1

ストリームが再利用されていないため(1つの端末操作のみが呼び出されています(findFirst())、エラーメッセージが混乱します。しかし、他の者によって指摘されているように、filter操作によって返されたストリームは決して変数に代入されないので、ifブロック内のstream.filter(...)のアプリケーションは失われている。これがそのような混乱の原因です。

このすべてにもかかわらず、この要件に対処する別の方法をお示ししたいと思います。代わりに、条件付きで、余分なフィルタを適用した、あなたは、最初にして、一度準備述語に取り組むstream.filter(...)操作にそれを渡すことができます。

Predicate<DocumentAudit> pred = doc -> 
    doc.getAction().equals(toFind.getAction()) && 
    doc.getActionContext().equals(toFind.getActionContext()) && 
    doc.getLevel().equals(toFind.getLevel()) && 
    doc.getStatus().equals(toFind.getStatus()); 

// If changes were specified, filter further. 
if (toFind.getChanges() != null) { 
    pred = pred.and(change -> toFind.getChanges().contains(change)); 
} 

return audits.getEntities().stream() 
    .filter(pred) 
    .findFirst() 
    .orElse(null); 

いくつかのコメント...

私がPredicate.andを使用しました条件を構成する。

生ストリームと最後の行にキャストを使用していました。もうそれをやめてください。 ...

理想的には、見つかったオブジェクトまたはnullを返す代わりに、メソッドの戻り値としてOptionalを使用するのが理想的です。この方法では、メソッドのユーザーは、オブジェクトが見つかったかどうかを事前に知ることができます。そして、彼らはオブジェクトに対して条件付きでアクションを実行するためにOptionalの便利な操作を使用したり、属性のいくつかに条件付きでマップすることもできます。

関連する問題