2016-09-01 17 views
4

Java SE 8ストリームよりも、最も速い方法と複雑な方法でunion/exclude/intersection操作を実行しようとしています。私はこれをやっているJavaストリーム間の操作

Stream<String> fruitStream = Stream.of("apple", "banana", "pear", "kiwi", "orange"); 
Stream<String> fruitStream2 = Stream.of("orange", "kiwi", "melon", "apple", "watermelon"); 

//Trying to create exclude operation 
fruitStream.filter(
    item -> !fruitStream2.anyMatch(item2 -> item2.equals(item))) 
.forEach(System.out::println); 
// Expected result: fruitStream - fruitStream2: ["banana","pear"] 

私は、次の例外を取得:

はjava.lang.IllegalStateException:ストリームがすでに時に操作したり、私がした場合

を閉じられているがこの操作を行うことができた、私は自分自身を開発することができたすべての残り、組合、交差点など...

2点は次のとおりです。

1)この例外を取得するにはどうしたらよいですか?

2)2つのストリーム間で操作を行う方法がそれほど複雑ではありませんか?

私はそれらについて学ぶためにストリームを使用します。配列やリストに変換したくないですか?

+0

「配列やリストに変換したくないのですが」そうしたくないかもしれませんが、コレクションにストリームを格納することを伴わない別の解決策はありません。 –

+0

varargsが暗黙のうちに配列を作成することを理解しています。 – shmosel

+0

'Stream.of'がシーンの背後で配列の作成を行うという事実を無視したいなら、' fruitStream.filter( item - >!Stream.of( "orange"、 "kiwi" anyMatch(item2 - > item2.equals(item)))... ... 'もちろん、' HashSet'ベースのソリューションがより効率的です。 – Holger

答えて

6

初めてitem -> !fruitStream2.anyMatch(item2 -> item2.equals(item))実行し、それがfruitStream2を消費します。 fruitStream2を再度使用して、fruitStream1の2番目の項目をフィルタリングすることはできません。

第2ストリームを使用するのではなく、Setを作成してcontainsを使用してください。

Set<String> otherFruits = new HashSet<>(); // Add the fruits. 
fruitStream.filter(f -> !otherFruits.contains(f)).forEach(System.out::println); 
+1

または ' otherFruits = Stream.of(" orange "、" kiwi "、" melon "、" apple "、" watermelon ")を設定します(collectors.toSet());'質問のコードに近づける。 – Holger

4

例外を取得するにはどうしたらよいですか?

あなたは何回か同じStreamを消費することはできませんし、ここにあなたがfruitStream

の要素を持っているとして、あなたはfruitStream2な回数を消費する2つのストリーム間の操作を実行するために、あまり複雑な方法はありますか?

あなたは二StreamSetとして変換することができます:

Stream<String> fruitStream = Stream.of("apple", "banana", "pear", "kiwi", "orange"); 
Set<String> fruitSet = Stream.of("orange", "kiwi", "melon", "apple", "watermelon") 
    .collect(Collectors.toSet()); 

fruitStream.filter(item -> !fruitSet.contains(item)).forEach(System.out::println); 

出力:

banana 
pear 
1

ストリームは、1回だけ実行される内部反復/処理です。それは非常に限られたエリアです。

Supplier<Stream<String>> fruitStream2S =() -> 
     Stream.of("orange", "kiwi", "melon", "apple", "watermelon"); 

fruitStream.filter(item -> !fruitStream2s.get().anyMatch(item2 -> item2.equals(item))) 
    .forEach(System.out::println); 

これは効率的ではありません。

0

これは一種の愚かであり、それはあなたに素晴らしいパフォーマンスを与えることはありませんが、それはない(explicitly)のご要件を満たすない配列またはリストを作成する:

public static void main(String[] args) { 
    new Object() { 
     Stream<String> fruitStream = Stream.of("apple", "banana", "pear", "kiwi", "orange"); 
     Stream<String> fruitStream2 = Stream.of("orange", "kiwi", "melon", "apple", "watermelon"); 
     { 
      fruitStream2.forEach(f -> fruitStream = fruitStream.filter(Predicate.isEqual(f).negate())); 
      fruitStream.forEach(System.out::println); 
     } 
    }; 
} 

出力:

banana 
pear 

編集(少し)より簡単なアプローチ:

public static void main(String[] args) { 
    Stream<String> fruitStream = Stream.of("apple", "banana", "pear", "kiwi", "orange"); 
    Stream.of("orange", "kiwi", "melon", "apple", "watermelon") 
      .map(Predicate::isEqual) 
      .reduce(Predicate::or) 
      .map(Predicate::negate) 
      .map(fruitStream::filter) 
      .orElse(fruitStream) 
      .forEach(System.out::println); 
} 
関連する問題