How to jump out of a method inside Java 8 Iterator.forEachRemaining?

The following is simplified code. I expected that returning inside the iteration would result in the method being abandoned. Instead, the code performs the next iteration, and then prints after iterations in the method

public static void callIter() { List<String> names = new ArrayList<>(); names.add("A"); names.add("B"); names.add("C"); ListIterator<String> nameIterator = names.listIterator(); nameIterator.forEachRemaining(name -> { if (name.equals("B")) { System.out.println("Found"); return; } System.out.println(name); }); System.out.println("AfterIter"); } 
+5
source share
5 answers

The forEach methods, like Iterable.forEach , Iterator.forEachRemaining or Stream.forEach are designed to do what the name suggests, apply an action to each element, not just some.

Stopping the iteration is not supported by this API, which can be recognized by looking at the functional signature of the Consumer interface, which (T) -> void , does not contain any possibility for the collection or iterator to notice the stopping condition.

At this point you should reconsider whether you are using the right tool for the job. Compare your approach e.g.

 List<String> names = Arrays.asList("A", "B", "C"); int ix = names.indexOf("B"); (ix<0? names: names.subList(0, ix)).forEach(System.out::println); if(ix>=0) System.out.println("Found"); System.out.println("AfterIter"); 

Of course, if printing elements was for debugging purposes only, the actual operation is simplified to

 List<String> names = Arrays.asList("A", "B", "C"); if(names.contains("B")) System.out.println("Found"); System.out.println("AfterIter"); 

If equality was only a placeholder for an arbitrary predicate, you can use

 List<String> names = Arrays.asList("A", "B", "C"); if(names.stream().anyMatch(s -> s.equals("B"))) System.out.println("Found"); System.out.println("AfterIter"); 

which can be adapted to arbitrary conditions.

It can be expanded to

 List<String> names = Arrays.asList("A", "B", "C"); Optional<String> match = names.stream() .peek(System.out::println) .filter(Predicate.isEqual("B")) .findFirst(); if(match.isPresent()) System.out.println("Found"); // or match.ifPresent(s -> System.out.println("Found "+s)); System.out.println("AfterIter"); 

shows how you can debug processing by printing elements, an alternative way to express an equality predicate (you can still replace it with other predicates) and how to get the actual corresponding element for non-trivial predicates.

Generally, if you want to use the new Java 8 APIs, don't try to write your logic in terms of forEach . Rather, try to avoid forEach , using more appropriate operations if possible.

+7
source

return completes the execution of the code that is executed for each (remaining) iterator element. This does not stop the iteration of / forEachRemaining . This is consistent with the behavior you are describing.

Javadoc for forEachRemaining :

Performs a task for each remaining element until all elements have been processed or an action throws an exception. Actions are performed in iteration order, if this order is specified. Exceptions thrown by the action are passed to the caller.

In other words, if you do not want to abuse the exceptions for this, you should not use forEachRemaining if you intend to stop the iteration before processing the last element.

+8
source

forEachRemaining cannot interrupt an iteration. You can search by streaming operations, for example:

 String name = names.stream().filter(name -> name.equals("B")).findFirst().orElse(null); 
+1
source

As others have mentioned, Iterator.forEachRemaining does not have an easy break, as it is designed to run through eachRemaining . The way I ran into this problem was this style:

 Iterator<Object> objects = ...; while (objects.hasNext() && exitCondition) { // Do what you would've inside of the for each } 
0
source

One of my genius colleagues advised me in this situation to throw a RuntimeException in the loop and catch it outside the forEachRemainin loop.

0
source

Source: https://habr.com/ru/post/1274531/


All Articles