Java 8 for each and first index

14,376

Solution 1

May this work for you?

myList.stream().findFirst().ifPresent(e -> System.out.println("Special: " + e));
myList.stream().skip(1).forEach(System.out::println);

Output:

Special: A
B

Alternative:

myList.stream().findFirst().ifPresent(e -> somethingSpecial(e));
myList.stream().forEach(System.out::println);

Solution 2

I don't think there is something provided in stream.

There are several alternatives you may consider:

Method 1:

int[] i = {0};  // I am using it only as an int holder.
myList.stream().forEach(value -> {
  if (i[0]++ == 0) {
    doSomethingSpecial;
  }
  System.out.println(value);
});

Method 2:

If your list is quick for random access (e.g. ArrayList), you may consider:

IntStream.range(0, myList.size())
  .forEach(i -> {
    ValueType value = myList.get(i);
    if (i == 0) {
      doSomethingSpecial();
    }
    System.out.println(value);
  });

Solution 3

Try StreamEx

StreamEx.of("A", "B", "C") //
        .peekFirst(e -> System.out.println(e + " Something special")).skip(1) //
        .forEach(System.out::println);

Solution 4

If you were trying to achieve it in a single stream statement, here's how I'd do it:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

public class Solution {
    public static void main(String[] args) {
        List<String> myList = new ArrayList<>();
        myList.add("A");
        myList.add("B");
        myList.add("C");
        myList.add("D");
        myList.add("E");
        myList.add("F");

        AtomicBoolean firstElementProcessed = new AtomicBoolean(false);
        myList.stream().map(s -> {
            if (firstElementProcessed.getAndSet(true)) {
                return s;
            }
            return (s + " Something special");
        }).forEach(System.out::println);
    }
}

And maybe for better readability, I'd refactor it to:

public class Solution {
        ...

        AtomicBoolean firstElementProcessed = new AtomicBoolean(false);
        myList.stream().map(s -> getString(firstElementProcessed, s)).forEach(System.out::println);
    }

    private static String getString(AtomicBoolean firstElementProcessed, String s) {
        if (firstElementProcessed.getAndSet(true)) {
            return s;
        }
        return (s + " Something special");
    }
}
Share:
14,376
David Dal Busco
Author by

David Dal Busco

Creator of DeckDeckGo | Organizer of the Ionic Zürich Meetup

Updated on June 26, 2022

Comments

  • David Dal Busco
    David Dal Busco almost 2 years

    Anyone knows how to achieve following piece code in a Java 8 way respectively is there any stream methods to detect the first element in a forEach?

    List<String> myList = new ArrayList<String>();
    myList.add("A");
    myList.add("B");
    
    int i = 0;
    
    for (final String value : myList) {
       if (i == 0) {
         System.out.println("Hey that's the first element");
       }
    
       System.out.println(value);
    
       i++;
     }
    

    Java8:

    myList.stream().forEach(value -> {
      // TODO: How to do something special for first element?
    
      System.out.println(value);
    });
    

    Furthermore, let's says that the goal is the following (console output):

    A    Something special
    B
    C
    D
    E
    F
    
  • Adrian Shum
    Adrian Shum about 7 years
    try a list of {"one", "two", "one"}
  • Roland
    Roland about 7 years
    I would rather use myList.stream().findFirst().ifPresent(e -> System.out.println("Special: " + e)); instead of peek... Note that the javadoc of findFirst() says "If the stream has no encounter order, then any element may be returned.", but its ok for ordered lists.
  • Eugene
    Eugene about 7 years
    @Oneiros you are assuming myList is a List, which is not bad, considering the OP wanted that, but if you (accidentally?) switch to Set, this will fail. The proper way would probably be to check the Spliterator for SIZED and SUBSIZED properties.
  • David Dal Busco
    David Dal Busco about 7 years
    As I said, curiosity and looking to learn something are the reasons for my question
  • Oneiros
    Oneiros about 7 years
    Why would OP use a Set considering that he wants to do special actions on first element? Sets are not ordered, it would make no sense in this context.
  • Holger
    Holger about 7 years
    @Oneiros: you’re right, treating the “first” element of an unordered Set specially makes no sense, but you wouldn’t believe how often people want exactly this…
  • David Dal Busco
    David Dal Busco about 7 years
    I marked this answer as the solution but I've to say that the other were also valid. I opened that post for curiosity and because I wanted to learn something, which was achieved. At the end, mostly for performance reason, I most probably gonna use a for like I always did but gonna use forEachOrdered and findFirst in other occasions
  • David Dal Busco
    David Dal Busco about 7 years
    Thx, StreamEx looks handy but my question was about native Java8