Tap*_*ose 275 java foreach lambda java-8
使用外部迭代时,Iterable
我们使用break
或return
来自增强型for-each循环:
for (SomeObject obj : someObjects) {
if (some_condition_met) {
break; // or return obj
}
}
Run Code Online (Sandbox Code Playgroud)
我们如何在Java 8 lambda表达式中使用break
或return
使用内部迭代,如:
someObjects.forEach(obj -> {
//what to do here?
})
Run Code Online (Sandbox Code Playgroud)
Jes*_*per 342
如果你需要这个,你不应该使用forEach
,而是使用流上可用的其他方法之一; 哪一个,取决于你的目标是什么.
例如,如果此循环的目标是找到与某个谓词匹配的第一个元素:
Optional<SomeObject> result =
someObjects.stream().filter(obj -> some_condition_met).findFirst();
Run Code Online (Sandbox Code Playgroud)
(注意:这不会迭代整个集合,因为流被懒惰地评估 - 它将停在匹配条件的第一个对象).
如果您只想知道条件为真的集合中是否有元素,您可以使用anyMatch
:
boolean result = someObjects.stream().anyMatch(obj -> some_condition_met);
Run Code Online (Sandbox Code Playgroud)
Hon*_*dek 51
这是可能的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
}
Run Code Online (Sandbox Code Playgroud)
请注意,try...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
}
Run Code Online (Sandbox Code Playgroud)
Ane*_*ran 35
lambda中的返回等于for-each中的continue,但没有相当于break.您可以返回继续:
someObjects.forEach(obj -> {
if (some_condition_met) {
return;
}
})
Run Code Online (Sandbox Code Playgroud)
Jul*_*les 21
您可以在下面找到我在项目中使用的解决方案.而forEach
只是使用allMatch
:
someObjects.allMatch(obj -> {
return !some_condition_met;
});
Run Code Online (Sandbox Code Playgroud)
Jon*_*eet 11
无论您需要使用它使用谓词指示是否继续去(因此它具有跳转代替)的方法,或者你需要抛出一个异常-这是一个非常丑陋的做法,当然.
所以你可以写一个forEachConditional
像这样的方法:
public static <T> void forEachConditional(Iterable<T> source,
Predicate<T> action) {
for (T item : source) {
if (!action.test(item)) {
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
而不是Predicate<T>
,您可能希望使用相同的通用方法定义自己的功能接口(采用T
并返回a的东西bool
),但使用更清楚地表示期望的名称 - Predicate<T>
在这里并不理想.
您可以使用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));
Run Code Online (Sandbox Code Playgroud)
为了在并行操作中获得最佳性能,请使用findAny(),它与findFirst()相似。
Optional<SomeObject> result =
someObjects.stream().filter(obj -> some_condition_met).findAny();
Run Code Online (Sandbox Code Playgroud)
但是,如果需要稳定的结果,请改用findFirst()。
还要注意,匹配模式(anyMatch()/ allMatch)将仅返回布尔值,而不会得到匹配的对象。
小智 6
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");
}
Run Code Online (Sandbox Code Playgroud)
使用Java 9+更新takeWhile
:
MutableBoolean ongoing = MutableBoolean.of(true);
someobjects.stream()...takeWhile(t -> ongoing.value()).forEach(t -> {
// doing something.
if (...) { // want to break;
ongoing.setFalse();
}
});
Run Code Online (Sandbox Code Playgroud)