从Java 8流中断或返回每个?

时间:2014-04-26 07:47:44

标签: java foreach lambda java-8

Iterable使用外部迭代时,我们使用breakreturn来自增强型for-each循环:

for (SomeObject obj : someObjects) {
   if (some_condition_met) {
      break; // or return obj
   }
}

我们如何{1}}或break在Java 8 lambda表达式中使用内部迭代,如:

return

13 个答案:

答案 0 :(得分:310)

如果你需要这个,你不应该使用forEach,而是使用流上可用的其他方法之一;哪一个,取决于你的目标是什么。

例如,如果此循环的目标是找到与某个谓词匹配的第一个元素:

Optional<SomeObject> result =
    someObjects.stream().filter(obj -> some_condition_met).findFirst();

(注意:这不会迭代整个集合,因为流被懒惰地评估 - 它将停在与条件匹配的第一个对象上。)

如果您只是想知道条件为真的集合中是否有元素,您可以使用anyMatch

boolean result = someObjects.stream().anyMatch(obj -> some_condition_met);

答案 1 :(得分:44)

Iterable.forEach()可以 (但Stream.forEach()不可靠)。解决方案并不好,但 可能。

警告:您不应该使用它来控制业务逻辑,而应该纯粹用于处理在执行forEach()期间发生的异常情况。例如资源突然停止被访问,其中一个已处理的对象违反了合同(例如,合同说流中的所有元素都不能是null,但突然而且意外地其中一个是null )等等。

根据Iterable.forEach()的文档:

  

Iterable 的每个元素执行给定操作,直到处理完所有元素或操作引发异常 ...异常抛出的异常动作转发给来电者。

所以你抛出一个会立即破坏内部循环的异常。

代码将是这样的 - 我不能说我喜欢它但是它有效。您可以创建自己的类BreakException,其范围为RuntimeException

try {
    someObjects.forEach(obj -> {
        // some useful code here
        if(some_exceptional_condition_met) {
            throw new BreakException();
       }
    }
}
catch (BreakException e) {
    // here you know that your condition has been met at least once
}

请注意,lambda表达式周围的try...catch 不是,而是围绕整个forEach()方法。为了使其更加明显,请参阅以下代码转录,以便更清楚地显示:

Consumer<? super SomeObject> action = obj -> {
    // some useful code here
    if(some_exceptional_condition_met) {
        throw new BreakException();
    }
});

try {
    someObjects.forEach(action);
}
catch (BreakException e) {
    // here you know that your condition has been met at least once
}

答案 2 :(得分:30)

lambda中的返回等于for-each中的continue,但没有相当于break。您可以返回继续:

someObjects.forEach(obj -> {
   if (some_condition_met) {
      return;
   }
})

答案 3 :(得分:20)

下面你会找到我在项目中使用的解决方案。相反,forEach只需使用allMatch

someObjects.allMatch(obj -> {
    return !some_condition_met;
});

答案 4 :(得分:11)

要么你需要使用一个方法,它使用一个谓词来指示是否继续(因此它有中断)你需要抛出异常 - 当然,这是一种非常丑陋的方法。

所以你可以这样写一个forEachConditional方法:

public static <T> void forEachConditional(Iterable<T> source,
                                          Predicate<T> action) {
    for (T item : source) {
        if (!action.test(item)) {
            break;
        }
    }
}

而不是Predicate<T>,您可能希望使用相同的通用方法(采用T并返回bool)来定义您自己的功能接口,但使用指示期望的名称更清楚 - Predicate<T>在这里并不理想。

答案 5 :(得分:8)

您可以使用java8 + rxjava

//import java.util.stream.IntStream;
//import rx.Observable;

    IntStream intStream  = IntStream.range(1,10000000);
    Observable.from(() -> intStream.iterator())
            .takeWhile(n -> n < 10)
            .forEach(n-> System.out.println(n));

答案 6 :(得分:5)

为了在并行操作中获得最大性能,使用findAny()类似于findFirst()。

Optional<SomeObject> result =
    someObjects.stream().filter(obj -> some_condition_met).findAny();

但是如果需要稳定的结果,请改用findFirst()。

另请注意,匹配模式(anyMatch()/ allMatch)将仅返回布尔值,您将无法获得匹配的对象。

答案 7 :(得分:3)

我已经通过类似的东西实现了

  private void doSomething() {
            List<Action> actions = actionRepository.findAll();
            boolean actionHasFormFields = actions.stream().anyMatch(actionHasMyFieldsPredicate());
            if (actionHasFormFields){
                context.addError(someError);
            }
        }
    }

    private Predicate<Action> actionHasMyFieldsPredicate(){
        return action -> action.getMyField1() != null;
    }

答案 8 :(得分:3)

你可以使用peek(..)和anyMatch(..)混合实现它。

使用您的示例:

someObjects.stream().peek(obj -> {
   <your code here>
}).anyMatch(obj -> !<some_condition_met>);

或者只写一个通用的util方法:

public static <T> void streamWhile(Stream<T> stream, Predicate<? super T> predicate, Consumer<? super T> consumer) {
    stream.peek(consumer).anyMatch(predicate.negate());
}

然后使用它,就像这样:

streamWhile(someObjects.stream(), obj -> <some_condition_met>, obj -> {
   <your code here>
});

答案 9 :(得分:1)

这个怎么样:

final BooleanWrapper condition = new BooleanWrapper();
someObjects.forEach(obj -> {
   if (condition.ok()) {
     // YOUR CODE to control
     condition.stop();
   }
});

BooleanWrapper是一个必须实现的类来控制流程。

答案 10 :(得分:0)

int valueToMatch = 7;
Stream.of(1,2,3,4,5,6,7,8).anyMatch(val->{
   boolean isMatch = val == valueToMatch;
   if(isMatch) {
      /*Do whatever you want...*/
       System.out.println(val);
   }
   return isMatch;
});

它将仅在找到匹配项时执行操作,找到匹配项后将停止迭代。

答案 11 :(得分:0)

我建议使用anyMatch。示例:-

return someObjects.stream().anyMatch(obj -> 
    some_condition_met;
);

您可以参考这篇文章以了解anyMatch:- https://beginnersbook.com/2017/11/java-8-stream-anymatch-example/

答案 12 :(得分:0)

public static void main(String[] args) {
    List<String> list = Arrays.asList("one", "two", "three", "seven", "nine");
    AtomicBoolean yes = new AtomicBoolean(true);
    list.stream().takeWhile(value -> yes.get()).forEach(value -> {
        System.out.println("prior cond" + value);
        if (value.equals("two")) {
            System.out.println(value);
            yes.set(false);
        }

    });
    //System.out.println("Hello World");
}