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()
?
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.
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.
You can't.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With