场景复现
public class ForEachTest { public static void main(String[] args) { String[] strs = {"java", "php", "python", "c++", "c#"}; ArrayList<String> list = new ArrayList<>(Arrays.asList(strs)); list.forEach(e -> { if (e.contains("python")) { System.out.print("终止或者跳出循环? "); return; } System.out.print(e + " "); }); } }
输出结果:
java php 终止或者跳出循环? c++ c#
结论:上述代码可知,没有打印出python,我们为了要跳出循环用了return;但是事实上并没有跳出Foreach,继续执行了代码!也就是说这里的return其实相当于普通for循环中的continue关键词。
分析:我们平时在普通的for循环时使用break跳出循环,而在普通的for循环中使用不止会跳出循环,更是会直接返回整个方法结果。但是在java8的forEach中是不能使用“break”和“continue”的,
而return的意思也不是原来return代表的含义了,而是类似continue。
简单看看源码:
@Override public void forEach(Consumer<? super E> action) { Objects.requireNonNull(action); final int expectedModCount = modCount; final Object[] es = elementData; final int size = this.size; for (int i = 0; modCount == expectedModCount && i < size; i++) action.accept(elementAt(es, i)); if (modCount != expectedModCount) throw new ConcurrentModificationException();
可以看出forEach是一个方法,当然是用return来结束的,而且void,没有返回值。
解决方案
1.使用原始的增强for循环+return(idea有强大的提示功能)
public static void main(String[] args) { String[] strs = {"java", "php", "python", "c++", "c#"}; ArrayList<String> list = new ArrayList<>(Arrays.asList(strs)); for (String s : list) { if (s.contains("python")) { System.out.print("终止或者跳出循环? "); return; } System.out.print(s + " "); } System.out.println("return 后不执行,continue 后继续执行"); }
这里发现,python以及后面的都未打印出来,return直接退出整个main方法;
2.使用原始的增强for循环+continue
public static void main(String[] args) { String[] strs = {"java", "php", "python", "c++", "c#"}; ArrayList<String> list = new ArrayList<>(Arrays.asList(strs)); for (String s : list) { if (s.contains("python")) { System.out.print("终止或者跳出循环? "); continue; } System.out.print(s + " "); } System.out.println(" ###return 后不执行,continue 后继续执行"); }
结论:continue会执行后面的逻辑,所以后续逻辑需要执行的话建议使用continue来跳出for。
3.抛异常,做双重捕捉
在实际运行中,往往有很多不突发情况导致代码提前终止,比如:空指针异常,其实,我们也可以通过抛出假异常的方式来达到终止forEach()方法的目的
public static void main(String[] args) { String[] strs = {"java", "php", "python", "c++", "c#"}; ArrayList<String> list = new ArrayList<>(Arrays.asList(strs)); try { list.forEach(e -> { if (e.contains("python")) { System.out.print("终止或者跳出循环? "); throw new RuntimeException("抛出异常"); } System.out.print(e + " "); }); } catch (Exception ignored) {} }
结论:这里内层抛异常,外层捕获但不作处理,也实现了退出for循环。当然也可以抛出想要跑出的内容。
需要注意的一点是:要确保你forEach()方法体内不能有其它代码可能会抛出的异常与自己手动抛出并捕获的异常一样;不然捕获到其他异常又没做处理,这不就成了一个bug么!!!