Использование .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 на какое-то ваше исключение.