2

I have a requirement where I need to create a list of objects from another list based on 2 conditions. Either the object should be in session or should be active. [This question is vaguely related to- Create list of object from another using java8 streams

class Person
{
    private String firstName;
    private String lastName;
    private String personId;
    //Getters and Setters
}

class UserInfo
{
    private String uFirstName;
    private String uLastName;
    private String userId;
    //Constructor, Getters and Setters
}

Main class:

Boolean isActiveUser = ..... [getting from upstream systems]
HttpSession session = request.session();
List<String> sessionUserIds = session.getAttribute("users");

List<Person> personList = criteria.list(); //Get list from db.

//CURRENT COCDE
List<UserInfo> userList = new ArrayList<>();
for(Person person: personList) {
   UserInfo userInfo = new UserInfo(person);
   if(sessionUserIds.contains(person.getPersonId())){
       userInfo.setLoginTime("");  //Get LoginTime from upstream
       userInfo.setIdleTime("");   // Get IdleTime from Upstream
       userList.add(userInfo);
   } else {
       if(isActiveUser) {
            userList.add(userInfo);
       }
   }
}

 // Trying to GET IT converted to JAVA-8

 List<UserInfo> userList = personList.stream()
                   .filter(p ->  ??)
                   .map( ??
                   .collect(Collectors.toList());

Any help would be appreciated.

4
  • You can't use filter because you need both paths of the conditional branch. While you could obviously write this using streams, I think it's going to actually be much less readable than what you've currently got. Commented Mar 20, 2018 at 13:55
  • Does personId becomes userId in UserInfo class? Commented Mar 20, 2018 at 14:11
  • If you know your active user id, you probably should hold that, instead of a boolean? Otherwise you may collect user information which do not belong to the active user? at least it looks like that. If so, you could use filter, but it probably wouldn't look that much better... do you really need to reset login time and idle time only for the users in the session user id list? Do you even need that information to belong to the user info? Commented Mar 20, 2018 at 14:18
  • @Roland: Otherwise you may collect user information which do not belong to the active user? => Yes that's the business requirement and we are OK with that........ Do you really need to reset login time and idle time only for the users in the session user id list? => Its not a reset but an extra info to be added to these users.... Do you even need that information to belong to the user info? => Yes, we need for downstream systems who don't understand Person object, but understands UserInfo object. Commented Mar 20, 2018 at 14:32

3 Answers 3

2

Do you want to adjust the data for all those users which are in the session user id list, but not for the others? Maybe the following is ok for you (assuming, as you said elsewhere, that getPersonId() returns the same as getUserId()):

List<UserInfo> userList;
userList = personList.stream()
                       .filter(p -> isActiveUser || sessionUserIds.contains(p.getPersonId()))
                       .map(UserInfo::new)
                       .collect(Collectors.toList());
userList.stream()
        .filter(u -> sessionUserIds.contains(u.getUserId())
        .forEach(u -> {
          u.setLoginTime(""); // Get LoginTime from upstream
          u.setIdleTime(""); // Get IdleTime from Upstream
        });

Be sure to read the foreach javadoc.

Alternatively using only one stream:

List<UserInfo> userList;
userList = personList.stream()
                     .filter(p -> isActiveUser || sessionUserIds.contains(p.getPersonId()))
                     .map(p -> {
                        UserInfo u = new UserInfo(p);
                        if (sessionUserIds.contains(u.getUserId())) {
                          u.setLoginTime(""); // Get LoginTime from upstream
                          u.setIdleTime(""); // Get IdleTime from Upstream
                        }
                        return u;
                      })
                     .collect(Collectors.toList());

I can recommend to filter before you map. For me, it's more readable. That's definitely not true for everyone. When mentally debugging through that code, at least I can filter out already some of the elements and concentrate on the things that are important in the further processing.

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

3 Comments

That is unnecessary since the collection is already describing what it holds, sessionUserIds, user ids.
what do you mean by unnecessary? I am still not that sure, what's the purpose of mapping every person to a userinfo, if isActiveUser is true.
I mean the big 'if' is unnecessary since userId and personId are the same. Also the isActiveUser is how is implemented in the current version. if(isActiveUser) { userList.add(userInfo); }, I'm not going to discuss that, besides that could be an abstraction of another method.
1

You can create the stream, then check if the user is active or is in the session, then if the user is in the session use the setters and finally collect.

List<UserInfo> userList = personList.stream()
        .map(UserInfo::new)
        .filter(userInfo -> isUserActive || sessionUserIds.contains(userInfo.getUserId()))
        .map(userInfo -> {
            if(sessionUserIds.contains(userInfo.getUserId())) {
                userInfo.setLoginTime("");
                userInfo.setIdleTime("");
            }
            return userInfo;
        })
        .collect(Collectors.toList());

Or if you don't mind to use the setters in the filter.

List<UserInfo> userList = personList.stream()
        .map(UserInfo::new)
        .filter(userInfo -> {
            if (sessionUserIds.contains(userInfo.getUserId())) {
                userInfo.setLoginTime("");
                userInfo.setIdleTime("");
                return true;
            }
            return isUserActive;
        })
        .collect(Collectors.toList());

8 Comments

Wow!, this is really good. I will try this. Thank you @Jose Da Silva ....
This isn't exactly the same as in the question, but one suggestion nonetheless: be sure to always call the filter before any map, if possible and it seems possible. And I cannot recommend peek for modifying the object. Please also check the javadoc of peek
The only difference is the use of getUserId() instead getPersonId(). Also i always use map, but i normally use inmutable objects. For using just setters peek could be used, the javadoc says mainly, not that is the only porpuse. Anyway changed to map because that is for what is intended.
yes and that both lead to the same value was just mentioned in another comment on another answer ;-) it's ok for me. Still, I would call the filter before map as otherwise you are constructing an object, which you may not even need afterwards.
how is mapping first more readable, if you know that your filter can be applied beforehand? I would rather say the opposite. Whenever you can strip down the elements in your stream by filtering, do so before you map or carry out anything else on them. For me this hasn't to do about performance. It has to do about concentrating on what's worth and work with that.
|
0

Not a very good idea but just a try.

if personId becomes userId then you can try as below:

List<UserInfo> userList = new ArrayList<>();

personList.stream()
          .map(p -> new UserInfo(person)) // person becomes user here
          .forEach(u -> {

                if(sessionUserIds.contains(u.getUserId())){
                   userInfo.setLoginTime("");
                   userInfo.setIdleTime("");
                   userList.add(userInfo);
                } else if(isActiveUser) {
                    userList.add(userInfo);
                }
          }
      });

3 Comments

How do you know UserInfo::getUserId is equivalent to Person::getPersonId ?
@Michael: they are equal in this business case.
@Ajeetkumar: Thanks for the response. There is one condtion that person may be converted to the UserInfo object. I will try out your option.

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.