First, I would point out there's not much wrong with the original code that you want to change. Just because Java has streams, you don't have to use them.
To use streams, I would break up the solution into two phases:
OptionalInt indexOfMatchingItem = IntStream.range(0, tracings.size())
.filter(i -> tracings.get(i).getDestination())
.findFirst();
List<ShipmentTracingDTO> newTracings = new ArrayList<>(
indexOfMatchingItem
.map(i -> tracings.subList(0, i + 1))
.orElse(tracings));
The above can be written as a single expression, but splitting it with a suitably named intermediate variable can make the code self-documenting.
I've created a new ArrayList so that it won't be affected by any subsequent changes to the original list tracings
. If tracings
is immutable, you can skip the construction of a new ArrayList.
The above solution is slightly better performing than the original code in the question, because the ArrayList constructor pre-allocates an array of exactly the required size, and so avoids the overhead of resizing and multiple array copies.
An alternative (perhaps more readable but less performant) solution is:
List<ShipmentTracingDTO> newTracings =
Stream.concat(
tracings.stream().takeWhile(i -> !tracings.get(i).getDestination()),
tracings.stream().dropWhile(i -> !tracings.get(i).getDestination()).limit(1)
).collect(toList());