Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Peek the next Element in a stream

Is there a way to peek the next element in a stream? The idea rose from a stream of a list of objects, where two following objects should be compared (to smooth some diffs, but that shouldn't matter here). As an old for loop this would look like:

List<Car> autobahn = getCars();
for (int i = 0; i < autobahn.size()-1; i++) {
    if(autobahn.get(i).speed>autobahn.get(i+1).speed)
        autobahn.get(i).honk();
}

The best way so far as stream would be:

autobahn.stream()
            .limit(autobahn.size()-1)
            .filter(car -> car.speed < autobahn.get(autobahn.indexOf(car)+1).speed)
            .forEach(car -> car.honk());

The main-problem with this solution is the indexOf method, since there might be twice the same car on the autobahn. A better solution would be some way to peek the next (or the one before) element (with an helping class, this might be even possible, but looks horrible)

BoxedCar boxedCar = new BoxedCar(autobahn.get(0));
autobahn.stream()
            .skip(1)
            .filter(car -> boxedCar.setContent(car))
            .forEach(car -> car.winTheRace());

with helperclass

class BoxedCar {

    Car content;

    BoxedCar(Car content) {
        this.content = content;
    }
    boolean setContent(Car content) {
        double speed = this.content.speed;
        this.content = content;
        return content.speed > speed;
    }
}

or to divert the Stream<Car> into a kind of Stream<(Car,Car)> with the second stream somehow created by the first one (this sounds also awful and here I have no idea, how this would look).

Is there a nice way to do this with streams, or are we stuck to the for-loop?

like image 228
ctst Avatar asked Mar 02 '16 18:03

ctst


People also ask

How do you use peek in stream?

Java Stream peek() Java Stream peek() method returns a new Stream consisting of all the elements from the original Stream after applying a given Consumer action. Note that the peek() method is an intermediate Stream operation so, to process the Stream elements through peek() , we must use a terminal operation.

What is the use of PEEK ()?

peek() method in Java is used to retrieve or fetch the first element of the Stack or the element present at the top of the Stack. The element retrieved does not get deleted or removed from the Stack.

How do you get one element from a stream?

To get the first element, you can use the reduce() method to ignore the second element, repeatedly, till there is no second element. This reduces the set of elements in a Stream to a single element, which is first. Hence the only single element will be remain in the stream which is the first element.

What is the difference between peek and forEach?

foreach, you can also change the internal property value of each item in the list, etc., but you need to perform "secondary flow processing" to get the smallest item in the list (filter according to age). (2): stream. peek can get the smallest item directly compared with stream. foreach().


Video Answer


1 Answers

Sticking with the for loop wouldn't be a bad idea. The Stream API isn't designed for this type of requirement. You can refer to that answer for more insight.

However, a simple way to do this using the Stream API would be to use a Stream over the indexes of your list, supposing that you have random access.

IntStream.range(0, autobahn.size() - 1)
         .filter(i -> autobahn.get(i).speed > autobahn.get(i+1).speed)
         .forEach(i -> autobahn.get(i).honk());

Note that this highly resemble the for loop.

like image 171
Tunaki Avatar answered Sep 26 '22 12:09

Tunaki