Arguments to createTimer

Yes, just as index changes in your original code for each iteration.That’s what index = index + 1 does.

But the difference here is that the forEach will be calling the lambda with the index on each iteration through the loop. It will therefore exist as a separate variable and will not be impacted by subsequent iterations of the loop.

I don’t have time to go too far into detail. But at a high level, every time you see a [ | ] you are seeing a lambda. A lambda is a function that you can pass around like any other Object.

The forEach method takes one of these lambdas as it’s argument. It will take a lambda that requires one argument (forEach[GroupItem gPS|) or it takes one that requires two arguments (forEach[GroupItem gPS, int index |). Behind the scenes forEach calls this lambda with the one or two arguments for each Item in the list in turn. The stuff before the | are the function arguments.

In your original code, you created a variable outside the forEach lambda. Then you created the forEach lambda. When you create a lambda it inherits all the variables in it’s current context. This means that it inherits index. This is why you can increment index from inside the lambda. (Since you claim this works this must be a recent change as this used to not work and only vals could be references from inside the lambda.)

But, only one lambda is created for use by forEach, not a separate one for each member. Therefore there is only one index variable and all the Timers created inside the forEach lambda end up pointing to the exact same index variable. So obviously, by the time the timer goes off, index is set to 8.

You need each timer to have it’s own copy of index instead of sharing the index variable defined outside the lambda.

Lukics provided one way to achieve this. It should work.

But the language has a way to do this too which is what I suggest. When you add the int index as an argument to the forEach lambda you are being passed a copy of the index that the forEach function is managing. So that value won’t change for subsequent calls of the forEach call to the lambda.

I don’t have time to really review the code, but it strikes me as being significantly more complicated than it probably needs to be. You might review the following to see if there is anything you can apply:

At the quick scan level, use findFirst instead of filter .head.

Avoid using primitives. Use Number where ever possible. Where not possible, avoid converting a Number to an int (for example) by calling .intValue until the last possible moment.

I’d split this up some. For example, I’d move the time/day of week calculations into their own set of Rules (see the time of day design pattern above).

I’d not rely on the index of a Pump Item in the members list for anything. The order of that list is not guaranteed to be the same every time.