Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Stream Using Previous Element in Foreach Lambda

Tags:

java

lambda

I have a list of numbers with some 0s inside. Since 0 means invalid measure in my situation, I need change the 0 valued element with the first non 0 element that I can find in the previous positions.

For example the list

45 55 0 0 46 0 39 0 0 0

must become

45 55 55 55 46 46 39 39 39 39

This is the implementation using the classic for each

      int lastNonZeroVal = 0;
        for (MntrRoastDVO vo : res) {
            if (vo.getValColor() > 0) {
                lastNonZeroVal = vo.getValColor();
            } else {
                vo.setValColor(lastNonZeroVal);
            }
        }

Is there a way to implement this with the Java Streams and Lambda Functions?

Since I know that I must not change the source of the stream in the foreach lambda, actually the list is a list of object and I do not change the element of the list but I just assign new values.

This was my first solution

int lastNonZeroVal = 1;
resutl.stream().forEach(vo -> {
        if(vo.getValColor()>0){
            lastNonZeroVal=vo.getValColor();
        }else{
            vo.setValColor(lastNonZeroVal);
        }
});

But I also read here

It's best if the lambdas passed to stream operations are entirely side effect free. that is, that they don't mutate any heapbased state or perform any I/O during their execution.

This is what is worryng me

the data is partitioned, there's no guarantee that when a given element is processed, all elements preceding that element were already processed.

Can this solution produce invalid results, maybe when the number of elements in the list are high? ? Event if I do not use parallelStream() ?

like image 301
Panciz Avatar asked Sep 02 '16 09:09

Panciz


People also ask

How do you continue a stream in forEach?

How to write continue statement inside forEach loop in java 8. A lambda expression is almost equivalent of instance of an anonymous class. Each iteration will call the overridden method in this instance. So if you want to continue, just return the method when condition is met.

Can we use forEach in streams Java?

Stream forEach() method in Java with examples Stream forEach(Consumer action) performs an action for each element of the stream. Stream forEach(Consumer action) is a terminal operation i.e, it may traverse the stream to produce a result or a side-effect.

Can we use break in forEach Java?

You can't.

Is stream forEach better than for loop?

forEach() can be implemented to be faster than for-each loop, because the iterable knows the best way to iterate its elements, as opposed to the standard iterator way. So the difference is loop internally or loop externally.


1 Answers

It's best if the lambdas passed to stream operations are entirely side effect free. that is, that they don't mutate any heapbased state or perform any I/O during their execution.

Your solution does infact have a side effect, it changes your source list to a resource list. To avoid that, you need the map operator and transform your stream to a Collection. Because you can not access the previous element the state must be stored outside in a final field. For reasons of brevity I used Integer instead of your object:

List<Integer> sourceList = Arrays.asList(45, 55, 0, 0, 46, 0, 39, 0, 0, 0);

final Integer[] lastNonZero = new Integer[1]; // stream has no state, so we need a final field to store it
List<Integer> resultList = sourceList.stream()
             .peek(integer -> {
                 if (integer != 0) {
                     lastNonZero[0] = integer;
                 }
             })
             .map(integer -> lastNonZero[0])
             .collect(Collectors.toList());

System.out.println(sourceList); // still the same
System.out.println(resultList); // prints [45, 55, 55, 55, 46, 46, 39, 39, 39, 39]

Using a stream for your problem is not the best solution, unless you need some additional operations like filter, other map operations or sort.

like image 145
Journeycorner Avatar answered Sep 22 '22 07:09

Journeycorner