Home > Software design >  Reusing lambda from a map stream
Reusing lambda from a map stream

Time:01-01

Still learning Java8. I have code that looks like:

List<String> list = userData.getEmails().stream()  
          .map(email -> codeThatGetsTheHost(email))  
          .peek((email, host) -> {//Only print if email is not null
                System.out.println("email="   email   " host="   host);})  
          .collect(Collectors.toList());  //should collect hosts.

The above code does not work because the peek() does not have access to the main stream variable, that is email used in map(). How do i fix this?

CodePudding user response:

Either put peek before the map to access all the data you need:

List<String> list = userData.getEmails().stream()  
          .peek(email -> System.out.println("email="   email   " host="   email.getHost())) 
          .map(email -> email.getHost())   
          .collect(Collectors.toList());

Or perform both actions (completely legal) in the map method to avoid repeating the getter call:

List<String> list = userData.getEmails().stream()  
          .map(email -> {
               String host = email.getHost();
               System.out.println("email="   email   " host="   host));
               return host;
          })
          .collect(Collectors.toList());

CodePudding user response:

You should use peek before mapping emails to their hosts. This is a sample code for your case:

import java.util.*;  
import java.util.stream.Collectors;


class Email{
    public String email;
    private String host;
    public Email(String email, String host){
        this.email = email;
        this.host = host;
    }
    public String getHost(){
        return host;
    }
}

class UserData{
    List<Email> emails = new LinkedList<>();
    public List<Email> getEmails(){
        return emails;
    }
}

public class MyClass {
    public static void main(String args[]) {
      UserData userData = new UserData();
      userData.emails.add(new Email("[email protected]", "host1"));
      userData.emails.add(new Email("[email protected]", "host2"));
      userData.emails.add(new Email("[email protected]", "host3"));
      List<String> list = userData.getEmails().stream()
          .peek(email -> System.out.println("email="   email   " host="   email.getHost()))  
          .map(email -> email.getHost())  
          .collect(Collectors.toList());
      System.out.println(list);
    }
}

email=Email@7bfcd12c host=host1
email=Email@1c2c22f3 host=host2
email=Email@18e8568 host=host3
[host1, host2, host3]

CodePudding user response:

Keep a Stream<Email> until you don't need them.

.peek(email -> System.out.println("email="   email   " host="   email.getHost()))
.map(Email::getHost)

If host calculation is somewhat expensive, you could make a Stream<Map.Entry<Email, String>> and have them both in the downstream.

userData.getEmails()
    .stream()
      .filter(Objects::nonNull)
      .map(email -> new AbstractMap.SimpleEntry<>(email, codeThatGetsTheHost(email)))
      .peek(entry -> System.out.println("email="   entry.getKey()   " host="   entry.getValue()))
      .map(Map.Entry::getValue)
    .collect(Collectors.toList());
  • Related