3

I have this class:

public class StructUserType extends UserType {

    MembersList membersList = new MembersList();

    public List<Member> getMembers() {
        return Collections.unmodifiableList(membersList.members);
    }

    static class MembersList {
        List<Member> members = new ArrayList<>();
    }

    public static class Member implements Identifiable {
        private Integer id;

        public Integer getId() {
            return id;
        }
    }    
} 

And I have a List object:

List<SmbpUserType> userTypes = new ArrayList<>();

I want find Member which is equal to a certain id. I tried as follows:

Integer id = 1;
userTypes.stream()
                .filter(StructUserType.class::isInstance)
                .map(StructUserType.class::cast)
                .forEach(structUserType -> {
                    structUserType.getMembers()
                            .stream()
                            .filter(m -> m.getId() == id)
                            .findFirst().orElse(null);
                });

I want, when the filter in the internal stream runs and finds the first member, to return the parent element that this member contains, those UserType.

Analog in the classical style:

for (UserType userType : userTypes) {
            if (userType instanceof StructUserType) {
                List<StructUserType.Member> members = ((StructUserType) userType).getMembers();

                for (StructUserType.Member member : members) {
                    if (member.getId() == id) {
                        return userType;
                    }
                }
            }
        }
        return null;
Eran
  • 387,369
  • 54
  • 702
  • 768
All_Safe
  • 1,339
  • 2
  • 23
  • 43

2 Answers2

6

Replace forEach with filter, to find StructUserType instances that satisfy the condition of the inner stream pipeline. Then get the first element of the Stream, if such exists.

return
   userTypes.stream()
            .filter(StructUserType.class::isInstance)
            .map(StructUserType.class::cast)
            .filter(st -> st.getMembers()
                            .stream()
                            .anyMatch(m -> m.getId().equals(id)))
            .findFirst()
            .orElse(null);
Eran
  • 387,369
  • 54
  • 702
  • 768
  • 3
    This is a perfect opportunity to return an `Optional` rather than the value if present else `null`. This will document to the user of this method that there may or may not be a value present therefore they can use the `Optional` methods to _safely_ get the value if present. – Ousmane D. Feb 21 '18 at 13:40
3

Instead of forEach you can use a filter for the nested Stream.

At last you can return the first match or collect all matches

...
.filter(structUser -> structUser.getMembers()
                      .stream()
                      .anyMatch(member -> member.getId().equals(id))
       )
...
Michael Seiler
  • 650
  • 1
  • 5
  • 15