72

I am still in the process of learning Lambda, please excuse me If I am doing something wrong

final Long tempId = 12345L;
List<Entry> updatedEntries = new LinkedList<>();

for (Entry entry : entryList) {
    entry.setTempId(tempId);
    updatedEntries.add(entityManager.update(entry, entry.getId()));
}

//entryList.stream().forEach(entry -> entry.setTempId(tempId));

Seems like forEach can be executed for one statement only. It doesn't return updated stream or function to process further. I might have selected wrong one altogether.

Can someone guide me how to do this effectively?

One more question,

public void doSomething() throws Exception {
    for(Entry entry: entryList){
        if(entry.getA() == null){
            printA() throws Exception;
        }
        if(entry.getB() == null){
            printB() throws Exception;
        }
        if(entry.getC() == null){
            printC() throws Exception;
        }
    }
}
    //entryList.stream().filter(entry -> entry.getA() == null).forEach(entry -> printA()); something like this?

How do I convert this to Lambda expression?

0

5 Answers 5

84

WARNING
As mentioned in comments, Using peek() for production code is considered bad practice
The reasson is that "According to its JavaDocs, the intermediate Stream operation java.util.Stream.peek() “exists mainly to support debugging” purposes."
As a consequence, this proposed solution SHOULD NOT be used.


Forgot to relate to the first code snippet. I wouldn't use forEach at all. Since you are collecting the elements of the Stream into a List, it would make more sense to end the Stream processing with collect. Then you would need peek in order to set the ID.

List<Entry> updatedEntries = 
    entryList.stream()
             .peek(e -> e.setTempId(tempId))
             .collect (Collectors.toList());

For the second snippet, forEach can execute multiple expressions, just like any lambda expression can :

entryList.forEach(entry -> {
  if(entry.getA() == null){
    printA();
  }
  if(entry.getB() == null){
    printB();
  }
  if(entry.getC() == null){
    printC();
  }
});

However (looking at your commented attempt), you can't use filter in this scenario, since you will only process some of the entries (for example, the entries for which entry.getA() == null) if you do.

Sign up to request clarification or add additional context in comments.

2 Comments

isn't it peek() is recommended to use for debugging only. I think one should try map() instead
unfortunately we should not use peek... see rules.sonarsource.com/java/RSPEC-3864
26
List<String> items = new ArrayList<>();
items.add("A");
items.add("B");
items.add("C");
items.add("D");
items.add("E");

//lambda
//Output : A,B,C,D,E
items.forEach(item->System.out.println(item));

//Output : C
items.forEach(item->{
    System.out.println(item);
    System.out.println(item.toLowerCase());
  }
});

1 Comment

It seems like this is invalid syntax. Isn't there an extra } at the end?
7

You don't have to cram multiple operations into one stream/lambda. Consider separating them into 2 statements (using static import of toList()):

entryList.forEach(e->e.setTempId(tempId));

List<Entry> updatedEntries = entryList.stream()
  .map(e->entityManager.update(entry, entry.getId()))
  .collect(toList());

Comments

6

In the first case alternatively to multiline forEach you can use the peek stream operation:

entryList.stream()
         .peek(entry -> entry.setTempId(tempId))
         .forEach(updatedEntries.add(entityManager.update(entry, entry.getId())));

In the second case I'd suggest to extract the loop body to the separate method and use method reference to call it via forEach. Even without lambdas it would make your code more clear as the loop body is independent algorithm which processes the single entry so it might be useful in other places as well and can be tested separately.

Update after question editing. if you have checked exceptions then you have two options: either change them to unchecked ones or don't use lambdas/streams at this piece of code at all.

3 Comments

what's the advantage of using peek. I haven't tried that function
@Reddy In this case I see no real advantage, since you can execute the setTempId call either in peek or in forEach, and the behavior will be similar. If, however, you don't use forEach at all, and use collect instead, in order to produce the output List (see my updated answer), you would need peek in order to call setTempId.
Keep in mind that peek mainly should be used in debug purpose. Use forEach when applying side effects to your streamed data.
2

My preferred approach is to concatenate java.util.function.Consumer<?> with andThen(...).

Applied to your example, it can be written in:

entryList.stream()
  .forEach(
    ((Consumer<Entry>) entry -> entry.setTempId(tempId))
    .andThen(entry -> updatedEntries.add(entityManager.update(entry, entry.getId())))
  );

seen this way, is not that nice to read... but you can move the 2 consumers into local function variables and it would become as nice as:

Consumer<Entry> c1 = entry -> entry.setTempId(tempId);
Consumer<Entry> c2 = entry -> updatedEntries.add(entityManager.update(entry, entry.getId()));
entryList.stream().forEach(c1.andThen(c2));

Bonus

You may write your combinator of consumers like:

public static <T> Consumer<T> combine(Consumer<? super T>... consumers){
  return (T t) ->   Arrays.stream(consumers).forEach(c -> c.accept(t));
}

and it will allow to re-write the above example in:

entryList.stream()
  .forEach(combine(
    entry -> entry.setTempId(tempId),
    entry -> updatedEntries.add(entityManager.update(entry, entry.getId()))));

I wish Consumer class had a method to combine multiple consumers of the same type, maybe this combine already exists somewhere and I'm not aware of it, so I invite you to search 😅

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.