Chris Garsonn
Chris Garsonn

Reputation: 777

How to filter data on a list according to multiple parameters in Java?

I have a list of GroupOffices

List<GroupOffice> officesOfTheGroup;

I want to search whether the id is not equal to groupOffice.getId (Long value) but the label is groupOffice.getLabel (String) and assign it to a boolean. The below code is working good, but is there any better approach instead of go through all items with for loop ?

 public GroupOfficeDto saveGroupOffice(GroupOfficeDto groupOfficeDto) {     
            List<GroupOffice> officesOfTheGroup = //some list from db..
            for (GroupOffice go : officesOfTheGroup) {
                if ((!go.getId().equals(groupOfficeDto.getId())) && go.getLabel().equals(groupOfficeDto.getLabel())) {
                    return groupOfficeDto;
                }
        return null:
}

Or how can I use stream ? If so, is using stream is better approach for it ?

Note: I am using Java8

Upvotes: 2

Views: 2686

Answers (3)

John Bollinger
John Bollinger

Reputation: 180171

is there any better approach instead of go through all items with for loop ?

Notably, your code does not go through all the items if it finds an acceptable one before reaching the end of the list. But if you have only the list to work with, then there is no alternative to being prepared to check every list element. As to whether to use a for loop, I think that's just fine.

Or how can I use stream ? If so, is using stream is better approach for it ?

It is indeed pretty fashionable these days to use streams, and although they seem to be used more than I think they should, yours is not an unreasonable use case. You might write it like this:

public GroupOfficeDto saveGroupOffice(GroupOfficeDto groupOfficeDto) {     
    List<GroupOffice> officesOfTheGroup = //some list from db..
    Integer officeId = groupOfficeDto.getId();
    String officeLabel = groupOfficeDto.getLabel();

    return officesOfTheGroup.stream()
            .filter(o -> !o.getId().equals(officeId))
            .anyMatch(o -> o.getLabel().equals(officeLabel))
        ? groupOfficeDto : null;
}

Particularly relevant here is use of the .anyMatch() terminal operation, because it allows stream processing to finish as soon as the result is determined, like your for loop, rather than processing the entire stream. Also note that the ID and Label against which you are comparing the offices are extracted and stored in variables before the stream expression. This allows them to be "effectively final", as is necessary for them to appear in the lambdas in the stream. It's also slightly more efficient to do it this way, instead of retrieving the same objects from the DTO over and over again -- for the for loop case, too.

Do note that the stream version is not much simpler than the loop version, and not much easier to read, either. I don't personally see much advantage for either one over the other.

Upvotes: 2

Max Farsikov
Max Farsikov

Reputation: 2763

Try this:

public GroupOfficeDto saveGroupOffice(GroupOfficeDto groupOfficeDto) {
    ...     
    List<GroupOffice> result = officesOfTheGroup.stream()
        .filter(it -> it.getLabel().equals(groupOfficeDto.getLabel()))
        .filter(it -> !it.getId().equals(groupOfficeDto.getId()))
        .collect(Collectors.toList())
    ...
}

Upvotes: 1

Ruslan
Ruslan

Reputation: 6290

If you need boolean value you can do:

boolean b = officesOfTheGroup.stream()
    .anyMatch(office -> !office.getId().equals(5) && office.getLabel().equals("London"))

Upvotes: 5

Related Questions