3

How do I write following procedure using lambda expressions, and how do I write it using streams?

Screen myScreen = new Screen();
Pattern myPattern = new Pattern("img.png");

Iterator<Match> it = myScreen.findAll(myPattern);
  while (it.hasNext())
    it.next().click();
Floern
  • 33,559
  • 24
  • 104
  • 119
hal
  • 831
  • 3
  • 13
  • 32
  • Are you asking how to create a Stream from an Iterator? http://stackoverflow.com/questions/24511052/how-to-convert-an-iterator-to-a-stream. If not, how could we know without knowing anything about the Screen class? – JB Nizet May 06 '17 at 16:30
  • Yes, how to create stream from iterator, or how to use lambda expressions instread of a while loop. – hal May 06 '17 at 16:38
  • 2
    Then click on the link I posted (that I found by googling for "transform Iterator to Stream"). Google is your friend. Use it. You seem to be confused about lambda expressions. They're not a replacement for loops. – JB Nizet May 06 '17 at 16:40

4 Answers4

4

Alternatively, in Java 8, the Iterator interface has a default method forEachRemaining(Consumer).

That one would solve your problem without having to resort to streams. You can simply do:

Iterator<Match> it = myScreen.findAll(myPattern);
it.forEachRemaining(Match::click);
Edwin Dalorzo
  • 76,803
  • 25
  • 144
  • 205
3

Well there will be a way to iterate with streams like a for loop or an iterator - via Stream.iterate, but it will be present in jdk-9. But it is not that trivial to use - because it acts exactly like a for loop and thus not exactly what you might expect. For example:

 Iterator<Integer> iter = List.of(1, 2, 3, 4).iterator();

 Stream<Integer> stream = Stream.iterate(iter.next(),
                   i -> iter.hasNext(), 
                   i -> iter.next()); 
     stream.forEach(System.out::println); // prints [1,2,3]

Or this:

 Iterator<Integer> iter = List.of(1).iterator();

    Stream.iterate(iter.next(), i -> iter.hasNext(), i -> iter.next())
            .forEach(System.out::println); // prints nothing

For the case that you need there's the forEachRemaining, but it's no "magic", internally it does exactly what you do:

default void forEachRemaining(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    while (hasNext())
        action.accept(next());
}
Eugene
  • 117,005
  • 15
  • 201
  • 306
2

You can use Apache Commons Collections utils to do that. For example:

Iterator<Match> matches = s.findAll("someImage.png");
List<Match> list = IteratorUtils.toList(matches);
list.stream().forEach(Match::highlight);
Eugene S
  • 6,709
  • 8
  • 57
  • 91
2

If you really want to use a Stream with lambdas for this you have to convert the Iterator to a Stream first, and then you can use this Stream to iterate over your objects and invoke their click method using a method reference:

Iterator<Match> it = myScreen.findAll(myPattern);

// convert Iterator to Stream
Iterable<Match> iterable = () -> it;
Stream<Match> stream = StreamSupport.stream(iterable.spliterator(), false);

// invoke click on each object
stream.forEach(Match::click);

Or if you want to use an explicit lambda expression:

stream.forEach(match -> match.click());
Floern
  • 33,559
  • 24
  • 104
  • 119