Использование .peek() в java 8 потоках
Я использую .peek() в своем потоке, но на него нахмурился, к сожалению, я не могу найти решение.
Упрощенная версия:
static boolean fooAddTester(int size) {
Foo foo = new foo(); //data structure
return IntStream.range(0, size).
.peek(i -> synchronized(r){foo.add(i)})
.allMatch(e -> foo.isLegal());
}
что мне нужно сделать, это перебрать IntStream и проверить после каждой вставки, если структура данных foo является законной.
Это логически эквивалентно:
static boolean fooAddTester(int size) {
Foo foo = new foo(); //data structure
for(int i=0; i<size; i++){
foo.add(i);
if(!foo.isLegal())
return false;
return true;
}
Однако это сложнее, и я пытаюсь использовать потоки для упрощения и изучения.
Способ сделать то же самое без использования .peek()
заключается в следующем: что работает, но я просто "переместил" проблему на .allMatch()
:
return IntStream.range(0, size).
.allMatch(i -> {
synchronized(r){foo.add(i)};
foo.isLegal();
)};
Моя проблема очень похожа на на этот вопрос, разница в том, что я проверяю каждый раз, чтобы решения не работали.
Итак, мои вопросы:
- Действительно ли
.peek()
только для отладки или я могу использовать его таким образом?
- Есть ли лучшее решение?
- Должен ли я использовать свое второе решение?
Я ищу правильное решение, а не рабочее решение, все эти коды уже работают.
Ответы
Ответ 1
документация Stream#peek
упомянута ниже и в основном не абсолютно:
Этот метод существует главным образом для поддержки отладки, где вы хотите видеть элементы при прохождении мимо определенной точки в конвейере
@Holger ответил на этот вопрос абсолютно:
полезная вещь , которую вы можете сделать с peek
, - это узнать, был ли обработан элемент потока.
и некоторые побочные эффекты, о которых он также указал в своем ответе, операция peek
зависит от того, какая операция терминала была вызвана. поэтому при использовании peek
внутренне вы должны быть осторожны.
так что правильный способ просто использует цикл for-each
, так как Stream#collect
не поддерживает операцию короткого замыкания.
необязательный способ использует peek
, потому что вы можете управлять потоком самостоятельно. и вам нужно удалить блок synchornized
, здесь это необязательно.
return IntStream.range(0, size).peek(foo::add).allMatch(__ -> Foo.isLegal(foo));
Ответ 2
Я могу думать только об одном способе сделать это, если вы действительно хотите использовать другие потоковые операции перед своей логикой, но я не очень большой поклонник этого...
boolean result = true;
try {
IntStream.range(0, 10)
.forEachOrdered(x -> {
foo.add(x);
if (!Foo.isLegal(foo)) {
throw new RuntimeException("just because");
}
});
} catch (RuntimeException re) {
result = false;
}
System.out.println(result);
Очевидно, вам нужно заменить RuntimeException
на какое-то ваше исключение.