2016-07-02 2 views
3

У меня есть Stack<Object> и следующий кусок кода:Как реализовать стек итерацию с использованием Java 8 Поток

while(!stack.isEmpty()){ 
    Object object = stack.pop(); 
    // do some operation on object 
} 

Как это итерация может быть реализована с использованием Java 8 поток так, чтобы он петлями, пока стек не пуст, и в каждая итерация стека должна быть уменьшена, выбирая один элемент сверху?

+3

Потоки должны использоваться для получения новых данных из заданного набора данных. Но вы также пытаетесь изменить стек. Использование потоков - это не очень хорошая идея. Если вы не в порядке с вызовом '' 'clear''' в конце. –

+2

'stack.stream(). Map (...) ...' 'stack.clear()' Я бы не стал манипулировать структурой данных, используя поток поверх нее. Большинство программистов будут удивлены этим побочным эффектом, когда они прочтут такой код. В случае, если вы ищете более «элегантный» синтаксис, рассмотрите возможность переноса операции в итераторе. –

+3

Следует также упомянуть, что '' 'Deque''' предпочтительнее' '' Stack''' –

ответ

7

В Java 9, будет представлять собой 3-Arg версии Stream.iterate (как for цикла - начальное значение лямбды для определение конца входного текста, лямбда для определения следующего входа), которые могли бы сделать это, хотя бы немного напряженными:

if (!stack.isEmpty()) { 
    Stream.iterate(stack.pop(), 
        e -> !stack.isEmpty(), 
        e -> stack.pop()) 
      ... 
} 
+0

Это не работает, потому что 'isEmpty' проверяется после' pop', что означает, что последний элемент всегда отсутствует в потоке. То же самое верно, если 'iterate' используется для итераторов или перечислений (что, по общему признанию, не имеет смысла). Я знаю, что это согласуется как с 'for' (если' pop' помещается в часть _increment_) и 'takeWhile', но все еще запутанно. Достаточно, чтобы даже привлечь экспертов, создающих его. ;) – Nicolai

-1

Невозможно использовать поток стека, поскольку сначала он будет первым в первом порядке, а второй, поскольку он основан на итераторе, выкинет ConcurrentModificationException. Тем не менее возможно, но, конечно, не рекомендуется, если по сравнению с простым циклом:

IntStream.range(0, s.size()).forEach(i -> stack.pop()); 
+0

Эти коды не учитывают изменение стека внутри потребителя. – pisaruk

1

в случае, если вы не хотите ждать the Java 9 solution, вот поток завода, который работает под Java 8.

public static <T> Stream<T> pop(Stack<T> stack) { 
    return StreamSupport.stream(new Spliterators.AbstractSpliterator<T>(
     stack.size(), Spliterator.ORDERED|Spliterator.SIZED) { 
      public boolean tryAdvance(Consumer<? super T> action) { 
       if(stack.isEmpty()) return false; 
       action.accept(stack.pop()); 
       return true; 
      } 
    }, false); 
} 

Обратите внимание, что это указывает начальный размер стека, принимая его как должное, что подразумевает, что вы не должны менять промежуточный стек (модификация источника потока в промежутке - это плохая идея в любом случае). С другой стороны, это сделает некоторые операции Stream более эффективными, чем вариант итерации.

Теперь общее предупреждение, которое применяется к обоим вариантам. Источники потока, которые были изменены из-за текущей операции Stream, например, выбирая элементы, которые потребляет Stream, могут оставить источник в непредсказуемом состоянии. Операции короткого замыкания могут не потреблять все элементы и в сочетании с параллельными потоками, они все равно могут потреблять больше элементов, чем это необходимо для работы терминала.

Так аналогично BufferedReader.lines()

После выполнения операции терминала потока нет никаких гарантий того, что читатель будет в определенном положении, из которого читать следующий символ или строку.

Вы не должны делать какие-либо предположения относительно содержимого Stack после потребления элементов таким образом.

Смежные вопросы