I have a Stream that contains rows of a table. The first row contains the header row and should be processed differently. The remaining rows should then be processed in a standard way.
I don't want to skip the header row, because I need the information of that row. The naïve solution would be something like this:
Stream<Row> rows = ...;
Row headRow = rows.<what comes here?>;
rows.forEach( this::processRow );
But that will obviously not be possible. Nearest thing I can come up with is:
Stream<Rows> rows = ...;
AtomicReference<Row> headRow = new AtomicReference<>();
rows.takeWhile(r -> {
if (headRow().get()==null) {
headRow.set(r);
return true;
}
return false;
})
.forEach( this::processRow );
This should work but IMHO is somewhat awkward.
Does anyone have a better Idea how to solve this? (It should work on Java 17 without additional libraries like guava.)
Note: Using collect() to create a list first, processing the header row and then converting back to stream and skipping the first element works, but I don't consider it a good solution as it requires much more memory (because all elements have to be held in memory at the same time).
How about using spliterator
?
Stream<Integer> rows = Stream.of(1, 2, 3);
var spliterator = rows.spliterator();
spliterator.tryAdvance(x -> System.out.println("Header " + x));
spliterator.forEachRemaining(x -> System.out.println("Data " + x));
Alternatively, I would consider the following helper function: Stream<T> stream(Iterator<T> iterator)
from Guava. It only depends on JDK classes.
/**
* Returns a sequential {@link Stream} of the remaining contents of {@code iterator}. Do not use
* {@code iterator} directly after passing it to this method.
*/
public static <T extends @Nullable Object> Stream<T> stream(Iterator<T> iterator) {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false);
}
Then:
Stream<Integer> rows = Stream.of(1, 2, 3);
var it = rows.iterator();
var headOpt = it.hasNext() ? Optional.of(it.next()) : Optional.empty();
var tail = stream(it);
System.out.println(headOpt);
tail.forEach(System.out::println);