背景
在一次需求開發(fā)時,發(fā)現(xiàn)使用Lambda的forEach()跳不出循環(huán)。如下示例代碼,想在遍歷滿足條件時跳出循環(huán)。
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 4, 5, 7, 9, 11);
list.forEach(e -> {
if (e % 2 == 0) {
System.out.println("foreach -- " + e);
return;
}
System.out.println(e);
});
System.out.println(list);
}
運(yùn)行結(jié)果:
可以看出在forEach()中使用return并不會退出整個循環(huán),和普通for循環(huán)return意義不同,仍會繼續(xù)遍歷。
原因
在普通for循環(huán)中,跳出循環(huán)使用break,結(jié)束本次循環(huán)使用continue,結(jié)束for循環(huán)所在的整個執(zhí)行方法使用return。
for (Integer e : list) {
if (e % 2 == 0) {
break; // return直接整個函數(shù)終止執(zhí)行返回,break for循環(huán)方法終止執(zhí)行
}
System.out.println(e);
}
Lambda表達(dá)式中,函數(shù)式接口Consumer 的抽象方法accept引用實(shí)現(xiàn)循環(huán)體中的邏輯。
所以forEach()處理一個個的執(zhí)行方法accept(t),非循環(huán)體。在執(zhí)行方法中使用return將處理方法返回,但不能結(jié)束整個forEach()。
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
優(yōu)化方案
跳出Lambda表達(dá)式forEach()循環(huán)解決思路有以下幾種:
-
拋異常
在遍歷時,若需要跳出循環(huán),通過拋異常結(jié)束forEach()循環(huán),在循環(huán)外catch異常不處理。首先此方案不夠優(yōu)雅,其次若循環(huán)邏輯塊中有其他拋異常的地方,會受影響不易發(fā)現(xiàn)。
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 4, 5, 7, 9, 11);
try {
list.forEach(e -> {
if (e % 2 == 0) {
System.out.println("foreach -- " + e);
throw new RuntimeException("跳出循環(huán)");
}
System.out.println(e);
});
} catch (Exception e) {}
System.out.println(list);
}
執(zhí)行結(jié)果:
-
使用普通for循環(huán)
使用普通for循環(huán)替代Lambda表達(dá)式forEach()循環(huán),在代碼塊中使用break即可跳出循環(huán)。 -
使用Lambda表達(dá)式filter()實(shí)現(xiàn)
換個實(shí)現(xiàn)思路,訴求是遍歷list遇到第一個滿足條件的item跳出循環(huán),那么轉(zhuǎn)成過濾整個list,返回第一個滿足條件的item。
Optional<Integer> first = list.stream().filter(e -> e % 2 == 0).findFirst();
System.out.println(first.orElse(null));
-
使用anyMatch()
原理類似filter(),遇到滿足條件的item跳出遍歷返回。
list.stream().anyMatch(e -> {
if (e % 2 == 0) {
System.out.println("跳出循環(huán) -- " + e);
return true;
}
System.out.println(e);
return false;
});
執(zhí)行結(jié)果:文章來源:http://www.zghlxwxcb.cn/news/detail-693917.html
總結(jié)
Lambda表達(dá)式forEach()函數(shù)不支持return跳出循環(huán),不建議使用拋異常方式結(jié)束循環(huán),可以考慮使用普通for或利用Lambda表達(dá)式的函數(shù)實(shí)現(xiàn)。文章來源地址http://www.zghlxwxcb.cn/news/detail-693917.html
到了這里,關(guān)于跳出Lambda表達(dá)式forEach()循環(huán)解決思路的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!