Home > Net >  Resume processing of a Java Stream after running findFirst()
Resume processing of a Java Stream after running findFirst()

Time:12-21

Given a simple list of strings:

List<String> strings = Arrays.asList("Mary", "James", "Jim", "Camilla");

I'd like to process each item of the list with a anotherMethod() method, however the first item shall be processed additionally by someMethod().

I've tried something like this:

List<String> strings = Arrays.asList("Mary", "James", "Jim", "Camilla");

var result = strings.stream()
     .findFirst()
     .map(myString -> someMethod(myString))
     // "resume" stream
     .map(myString -> anotherMethod(myString))
     .toList();     

Is there a way to handle such a scenario using a Stream or something similar?

CodePudding user response:

findFirst collapses the stream to an Optional<String>, and there is nothing to resume.

Optional<String> mary = Stream.of("Mary", "James", "Jim", "Camilla").findFirst();

Do you want to reduce the stream to only one element? Then the method limit(1) might be what you are looking for and then concat it with a copy where you skip(1) the element.

List<String> strings = Arrays.asList("Mary", "James", "Jim", "Camilla");
List<String> result = Stream.concat(
      strings.stream()
        .limit(1)
        .map(this::someMethod),
      strings.stream()
        .skip(1))
    .map(this::anotherMethod))
    .toList();

CodePudding user response:

You could create an IntStream over the indexes.

IntStream.range(0, strings.size())
    .mapToObj(i -> {
        var s = strings.get(i);
        if (i == 0) s = someMethod(s);
        return anotherMethod(s);
    }).toList();

CodePudding user response:

Optional.stream()

Your idea of using findFirst() is perfectly viable.

We can apply map() on the Optional result and make use of the Java 9 Optional.stream() (to "resume" the stream).

flatMap() operation in conjunction with Stream.concat() would be handy for combining the very first element with the rest part of the stream.

Apply the final transformation and collect the result into a list.

List<String> strings = Arrays.asList("Mary", "James", "Jim", "Camilla");

List<String> result = strings.stream().findFirst()
    .map(MyClass::someMethod)
    .stream()
    .flatMap(s -> Stream.concat(Stream.of(s), strings.stream().skip(1)))
    .map(MyClass::anotherMethod)
    .toList();

Iterator.forEachRemaining()

Another option would be to use Java 8 Iterator.forEachRemaining():

List<String> strings = Arrays.asList("Mary", "James", "Jim", "Camilla");
List<String> result = new ArrayList<>();

Iterator<String> iterator = strings.iterator();
result.add(anotherMethod(someMethod(iterator.next())));
iterator.forEachRemaining(s -> result.add(anotherMethod(s));
  • Related