中断或从Java 8流返回?

时间:2022-06-26 19:45:17

When using external iteration over an Iterable we use break or return from enhanced for-each loop as:

在迭代中使用外部迭代时,我们使用break或从enhanced for-each循环返回如下:

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

How can we break or return using the internal iteration in a Java 8 lambda expression like:

如何使用Java 8 lambda表达式中的内部迭代来中断或返回:

someObjects.forEach(obj -> {
   //what to do here?
})

11 个解决方案

#1


229  

If you need this, you shouldn't use forEach, but one of the other methods available on streams; which one, depends on what your goal is.

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

For example, if the goal of this loop is to find the first element which matches some predicate:

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

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

(Note: This will not iterate the whole collection, because streams are lazily evaluated - it will stop at the first object that matches the condition).

(注意:这不会迭代整个集合,因为流是延迟计算的——它将在第一个匹配条件的对象处停止)。

If you just want to know if there's an element in the collection for which the condition is true, you could use anyMatch:

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

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

#2


37  

This is possible for forEach(). The solution is not nice, but it is possible.

这对forEach()是可能的。解决办法并不好,但却是可能的。

WARNING: You should not use it for controlling business logic, but purely for handling an exceptional situation which occurs during the execution of the forEach(). Such as a resource suddenly stops being accessible, one of the processed objects is violating a contract (e.g. contract says that all the elements in the stream must not be null but suddenly and unexpectedly one of them is null) etc.

警告:不应该将它用于控制业务逻辑,而应该纯粹用于处理forEach()执行过程中发生的异常情况。例如,一个资源突然停止可访问,一个被处理的对象违反了一个契约(例如,契约说流中的所有元素必须不是null,而是突然而意外地其中一个元素是null)等等。

According to the documentation for Iterable.forEach():

根据Iterable.forEach()的文档:

Performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception... Exceptions thrown by the action are relayed to the caller.

为可迭代的每个元素执行给定的操作,直到所有元素都被处理或操作抛出异常……由动作抛出的异常被转发给调用者。

So you throw an exception which will immediately break the internal loop.

因此,您抛出一个异常,它将立即中断内部循环。

The code will be something like this - I cannot say I like it but it works. You create your own class BreakException which extends RuntimeException.

代码会是这样的——我不能说我喜欢它,但它确实有效。您可以创建自己的类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
}

Notice that the try...catch is not around the lambda expression, but rather around the whole forEach() method. To make it more visible, see the following transcription of the code which shows it more clearly:

注意,试一试……catch不是围绕lambda表达式,而是围绕整个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
}

#3


20  

Below you find the solution I used in a project. Instead forEach just use allMatch:

下面是我在一个项目中使用的解决方案。取而代之的是使用allMatch:

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

#4


16  

A return in a lambda equals a continue in a for-each, but there is no equivalent to a break. You can just do a return to continue:

一个lambda中的一个返回值等于一个for-each中的一个continue,但是并不等于一个break。你可以返回继续:

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

#5


10  

Either you need to use a method which uses a predicate indicating whether to keep going (so it has the break instead) or you need to throw an exception - which is a very ugly approach, of course.

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

So you could write a forEachConditional method like this:

所以你可以写成这样的foreachcondition方法

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

Rather than Predicate<T>, you might want to define your own functional interface with the same general method (something taking a T and returning a bool) but with names that indicate the expectation more clearly - Predicate<T> isn't ideal here.

与谓词 不同,您可能希望使用相同的通用方法(使用T并返回bool)定义自己的函数接口,但是使用更明确的名称——谓词 在这里并不理想。

#6


7  

You can use java8 + rxjava.

您可以使用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));

#7


3  

For maximal performance in parallel operations use findAny() which is similar to findFirst().

对于并行操作中的最大性能,使用类似于findFirst()的findAny()。

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

However If a stable result is desired, use findFirst() instead.

但是,如果需要稳定的结果,可以使用findFirst()代替。

Also note that matching patterns (anyMatch()/allMatch) will return only boolean, you will not get matched object.

还要注意,匹配模式(anyMatch()/allMatch)只返回布尔值,不会得到匹配对象。

#8


3  

I have achieved by something like this

我是通过这样的方式获得的

  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;
    }

#9


2  

You can achieve that using a mix of peek(..) and anyMatch(..).

您可以使用peek(..)和anyMatch(..)的混合来实现。

Using your example:

用你的例子:

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

Or just write a generic util method:

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

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

And then use it, like this:

然后使用它,像这样:

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

#10


2  

It's not easy to do that by the APIs provided in JDK. But we can do it by AbacusUtil. Here is sample code:

用JDK提供的api来实现这一点并不容易。但是我们可以用AbacusUtil来做。下面是示例代码:

Stream.of("a", "b", "c", "d", "e").peek(N::println) //
        .forEach("", (r, e) -> r + e, (e, r) -> e.equals("c"));
// print: a b c

Disclosure: I'm the developer of AbacusUtil.

披露:我AbacusUtil的开发者。

#11


0  

What about this one:

这一个:

final BooleanWrapper condition = new BooleanWrapper();

最终的BooleanWrapper条件=新的BooleanWrapper();

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

Where BooleanWrapper is a class you must implement to control the flow.

在BooleanWrapper是一个类的地方,你必须实现它来控制流。

#1


229  

If you need this, you shouldn't use forEach, but one of the other methods available on streams; which one, depends on what your goal is.

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

For example, if the goal of this loop is to find the first element which matches some predicate:

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

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

(Note: This will not iterate the whole collection, because streams are lazily evaluated - it will stop at the first object that matches the condition).

(注意:这不会迭代整个集合,因为流是延迟计算的——它将在第一个匹配条件的对象处停止)。

If you just want to know if there's an element in the collection for which the condition is true, you could use anyMatch:

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

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

#2


37  

This is possible for forEach(). The solution is not nice, but it is possible.

这对forEach()是可能的。解决办法并不好,但却是可能的。

WARNING: You should not use it for controlling business logic, but purely for handling an exceptional situation which occurs during the execution of the forEach(). Such as a resource suddenly stops being accessible, one of the processed objects is violating a contract (e.g. contract says that all the elements in the stream must not be null but suddenly and unexpectedly one of them is null) etc.

警告:不应该将它用于控制业务逻辑,而应该纯粹用于处理forEach()执行过程中发生的异常情况。例如,一个资源突然停止可访问,一个被处理的对象违反了一个契约(例如,契约说流中的所有元素必须不是null,而是突然而意外地其中一个元素是null)等等。

According to the documentation for Iterable.forEach():

根据Iterable.forEach()的文档:

Performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception... Exceptions thrown by the action are relayed to the caller.

为可迭代的每个元素执行给定的操作,直到所有元素都被处理或操作抛出异常……由动作抛出的异常被转发给调用者。

So you throw an exception which will immediately break the internal loop.

因此,您抛出一个异常,它将立即中断内部循环。

The code will be something like this - I cannot say I like it but it works. You create your own class BreakException which extends RuntimeException.

代码会是这样的——我不能说我喜欢它,但它确实有效。您可以创建自己的类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
}

Notice that the try...catch is not around the lambda expression, but rather around the whole forEach() method. To make it more visible, see the following transcription of the code which shows it more clearly:

注意,试一试……catch不是围绕lambda表达式,而是围绕整个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
}

#3


20  

Below you find the solution I used in a project. Instead forEach just use allMatch:

下面是我在一个项目中使用的解决方案。取而代之的是使用allMatch:

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

#4


16  

A return in a lambda equals a continue in a for-each, but there is no equivalent to a break. You can just do a return to continue:

一个lambda中的一个返回值等于一个for-each中的一个continue,但是并不等于一个break。你可以返回继续:

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

#5


10  

Either you need to use a method which uses a predicate indicating whether to keep going (so it has the break instead) or you need to throw an exception - which is a very ugly approach, of course.

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

So you could write a forEachConditional method like this:

所以你可以写成这样的foreachcondition方法

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

Rather than Predicate<T>, you might want to define your own functional interface with the same general method (something taking a T and returning a bool) but with names that indicate the expectation more clearly - Predicate<T> isn't ideal here.

与谓词 不同,您可能希望使用相同的通用方法(使用T并返回bool)定义自己的函数接口,但是使用更明确的名称——谓词 在这里并不理想。

#6


7  

You can use java8 + rxjava.

您可以使用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));

#7


3  

For maximal performance in parallel operations use findAny() which is similar to findFirst().

对于并行操作中的最大性能,使用类似于findFirst()的findAny()。

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

However If a stable result is desired, use findFirst() instead.

但是,如果需要稳定的结果,可以使用findFirst()代替。

Also note that matching patterns (anyMatch()/allMatch) will return only boolean, you will not get matched object.

还要注意,匹配模式(anyMatch()/allMatch)只返回布尔值,不会得到匹配对象。

#8


3  

I have achieved by something like this

我是通过这样的方式获得的

  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;
    }

#9


2  

You can achieve that using a mix of peek(..) and anyMatch(..).

您可以使用peek(..)和anyMatch(..)的混合来实现。

Using your example:

用你的例子:

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

Or just write a generic util method:

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

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

And then use it, like this:

然后使用它,像这样:

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

#10


2  

It's not easy to do that by the APIs provided in JDK. But we can do it by AbacusUtil. Here is sample code:

用JDK提供的api来实现这一点并不容易。但是我们可以用AbacusUtil来做。下面是示例代码:

Stream.of("a", "b", "c", "d", "e").peek(N::println) //
        .forEach("", (r, e) -> r + e, (e, r) -> e.equals("c"));
// print: a b c

Disclosure: I'm the developer of AbacusUtil.

披露:我AbacusUtil的开发者。

#11


0  

What about this one:

这一个:

final BooleanWrapper condition = new BooleanWrapper();

最终的BooleanWrapper条件=新的BooleanWrapper();

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

Where BooleanWrapper is a class you must implement to control the flow.

在BooleanWrapper是一个类的地方,你必须实现它来控制流。