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

Alex :

The simplified code is below. I expected that return inside the iteration will result in jumping out of the method. Instead the code executes the next iteration and then the print after iterations within 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");
}
Holger :

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

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

At this place, you should reconsider whether you are using the right tool for the job. Compare your approach with, 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 the printing of the elements was only for debugging purposes, the actual operation simplifies 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 may 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.

This 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");

showing, how you can debug the processing by printing the elements, an alternative way to express the equality predicate (still can be replaced by other predicates), and how to get the actual matching element for nontrivial predicates.

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

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=474375&siteId=1