Home > Software engineering >  Convert a For loop to a lambda expression in Java
Convert a For loop to a lambda expression in Java

Time:07-02

I have the following code

//assume we have a list of custom type "details" already constructed 

 for(int i = 0; i < details.size();   i) {
    CallerID number = details.get(i).getNextNumber();
    ClientData.addToClient(number);
                
 }

I have oversimplified the code. The enum CallerID and the ClientData object work as intended. I am asking for help converting this loop to a lambda function so I can understand the logic of how to do so, then fill in the appropriate code as needed.

CodePudding user response:

Let's first write it as a modern basic for loop and golf it a bit, just so we're comparing apples to apples:

for (var detail : details) clientData.addToClient(detail.getNextNumber());

And this is probably the right answer. It is local var, exception, and control flow transparent (which is what you want), and short.

The lambda form is this, but it's got downsides (mostly, those transparencies). It also isn't any shorter. You shouldn't write it this way.

details.stream().forEach(d -> clientData.addToClient(detail.getNextNumber());

You may be able to just remove stream() from that. But probably not.

Generally when people say "I want it in lambda form", that's not because someone is holding a gun to your head - you are saying that because somebody peddling a religion of sorts to you told you that 'it was better' and that this 'will scale'. Realize that they are full of it. There can be advantages to 'functional style', but none of these snippets are functional. A true functional style would involve a bunch of side-effect-free transformations, and then returning something.

.addToClient? You've lost the functional game there - you would want to instead convert each detail to something (presumably a ClientID), and from there construct an immutable object from that stream. You'd 'collect' your ClientIDs into a clientData object.

Let's say for example that clientData is just a 'list of ClientIDs' and nothing more. Then you'd write something like this:

var clientData = details.stream()
  .map(MyDetailClass::getNextNumber)
  .collect(Collectors.toList());

Is this better? No. However, if you're looking for 'a stream-style, lambda-based functional take on things', that qualifies. The output is constructed by way of collection (and not forEach that does a side-effect operation), and all elements involved are (or can be) immutable.

There's no particular reason why you'd want this, but if for some reason you're convinced this is better, now you know what you want to do. "Just replace it with a lambda" doesn't make it 'functional'.

CodePudding user response:

I am asking for help converting this loop to a lambda function so I can understand the logic of how to do so, then fill in the appropriate code as needed.

A Function returns a value. As you are just updating something what you need is a Consumer which accepts a single argument of a list of some detail. Assuming those are in a Class named SomeDetails, here is how you would do it.

As you iterating over some structure limited by size and using get(i) I am presuming a list is required here.

List<SomeDetails> details = new ArrayList<>(); // then populated

// lambda definition
Consumer<List<SomeDetails>> update = (lst)-> {
            for(SomeDetails detail : lst) {
                  CallerID number = detail.getNextNumber();
                  ClientData.addToClient(number);
            }
};

And then invoke it like this, passing the List.

update.accept(details);

All the above does is encapsulate the for loop (using the enhanced version for simplicity) and perform the operation.

If this is all you wanted, I would recommend just doing it as you were doing it sans the lambda.

  • Related