java Streams之间的操作

时间:2016-09-01 14:22:49

标签: java java-8 java-stream

我正在尝试找到最快的方法,而不是通过Java SE 8 Streams进行联合/排除/交叉操作的复杂方法。

我这样做:

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:stream已经被操作或关闭

如果我能够做这个操作,我可以开发自己所有其余的,联合,交叉等......

所以,2点是:

1)我在这个解决方案中做错了什么?

2)是否有一种不太复杂的方法在两个流之间执行操作?

注意

我想用流来了解它们。不想将它们转换为数组或列表

4 个答案:

答案 0 :(得分:6)

第一次执行item -> !fruitStream2.anyMatch(item2 -> item2.equals(item))时,它会消耗fruitStream2。无法再次使用fruitStream2来过滤fruitStream1中的第二项。

为什么不创建Set并使用contains,而不是使用第二个流?

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

答案 1 :(得分:4)

  

我在这个解决方案中做错了什么?

您不能使用相同Stream的多次消费,并且在此消耗fruitStream2的次数与fruitStream

中的元素相同
  

是否有一种不太复杂的方法在两个流之间执行操作?

您可以将第二个Stream转换为Set

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

答案 2 :(得分:1)

Stream是仅执行一次的内部迭代/处理。这是一个非常有限的领域。

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);

效率不高。

答案 3 :(得分: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);
}