Search code examples
java-8java-stream

Map first element of stream differently than rest


Is there a way in Java's Stream API to map first element of stream differently than other?

Equivalent of this code:

List<Bar> barList = new ArrayList<>();

for (int i=0; i<fooList.size(); i++) {
    Foo foo = fooList.get(i);
    Foo modifiedFoo = foo.getModifiedFoo();
    if (i == 0) {
        barList.add(new Bar(modifiedFoo, false));
    }else {
        barList.add(new Bar(modifiedFoo, true));
    }
}

Stream<Bar> = barList.stream();

Note: I already have a stream setup and I would want some operation after first mapping

fooList.stream()
        .map(Foo::getModifiedFoo)
        .(May be Some operation here to get different new Bar for first modifiedFoo)
        .map(modifiedFoo -> new Bar(modifiedFoo, true));

Solution

  • I would get the first element, create a Stream out of it and apply the needed mappings. Then, I'd take the rest of the list, create a stream out of it and apply the different mappings. Then concat the streams. Something like this:

    Stream<Bar> first = Stream.of(fooList.get(0))
        .map(Foo::getModifiedFoo)
        .map(modifiedFoo -> new Bar(modifiedFoo, false));
    
    Stream<Bar> others = fooList.subList(1, fooList.size()).stream()
        .map(Foo::getModifiedFoo)
        .map(modifiedFoo -> new Bar(modifiedFoo, true));
    
    Stream<Bar> bars = Stream.concat(first, others).flatMap(s -> s);
    

    Another approach:

    Stream<Bar> bars = IntStream.range(0, fooList.size())
        .mapToObj(i -> new Bar(fooList.get(i).getModifiedFoo(), i > 0));
    

    This way is succinct and does the job pretty well.