Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resume processing of a Java Stream after running findFirst()

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?


Update 1

Here is an example to help you better understand the motivation behind my question.

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

public String someMethod(String s) {
  return s.toUpperCase();
}

public String anotherMethod(String s) {
  return s.toLowerCase();
}

The final result shall be a List<String> with the following elements, that is, only the first element is converted to upper-case while all other elements are converted to lower-case.

"MARY", "james", "jim", "camilla"

like image 494
Robert Strauch Avatar asked Sep 10 '25 18:09

Robert Strauch


2 Answers

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();

Edit: After Update 1:

You wouldn't want to apply toLowerCase() to the first element after you applied toUpperCase().

like image 54
Valerij Dobler Avatar answered Sep 13 '25 07:09

Valerij Dobler


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();
like image 26
Unmitigated Avatar answered Sep 13 '25 06:09

Unmitigated