2016-09-01 4 views
4

Я пытаюсь найти самый быстрый способ и менее сложный способ выполнить некоторые операции union/exclude/intersection над потоками Java SE 8.Операции между потоками 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) Существует ли менее сложный способ выполнения операций между двумя потоками?

Примечание

Я хочу использовать потоки, чтобы узнать о них. Не хотите преобразовывать их в массивы или списки

+0

«Не хотите превращать их в массивы или списки» Возможно, вам этого не захочется, но другого решения не будет, кроме хранения одного потока в коллекции. –

+0

Вы понимаете, что varargs неявно создает массив для вас, не так ли? – shmosel

+0

Если вы хотите игнорировать тот факт, что 'Stream.of' создает массив за кулисами, вы * можете * просто использовать' fruitStream.filter ( элемент ->! Stream.of («orange», «kiwi», «melon», «apple», «арбуз»). anyMatch (item2 -> item2.equals (item))) ... ', но, конечно, решение на основе HashSet более эффективно. – Holger

ответ

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

Или 'Set otherFruits = Stream.of (« orange »,« kiwi »,« melon »,« apple »,« арбуз »). Collect (Collectors.toSet());' ближе к коду вопроса. – Holger

4

Что я делаю неправильно в этом решении, чтобы получить это Исключение?

Вы не можете потребляющие в несколько раз то же самое Stream и здесь вы потребляете fruitStream2 столько раз, сколько у вас есть элементы в fruitStream

Есть менее сложный способ выполнения операций между 2 потока?

Вы можете преобразовать второй 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 
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); 
} 
Смежные вопросы