JAVA 8 filter list of object with any matching property

Viewed 13731

My requirement is to filter a list of objects by a string matching any of the properties. For example, let say Contact class has three properties: street, city, phone.

I am aware of how java stream filter works, where i have to compare the input string with each property as below:

contactList.stream().filter(contact -> contact.getStreet().equals("dubai") || 
                            contact.getCity().equals("dubai") || .......).collect(Collectors.toList());

However, if a class has 20+ properties and size of list 80,000+, comparing each property with the input string would affect the performance. So my question is, does Java or any other library support filtering the list with any matching property? Something as below:

contactList.stream().filter(contact -> contact.anyProperty.equals("dubai").collect(Collectors.toList());

Can someone help me on this, thanks.

6 Answers

You can use findAny. This will end as soon as the candidate is found:

Optional<Contact> contact = contactList.stream().filter(contact -> contact.getStreet().equals("dubai") || 
                        contact.getCity().equals("dubai") || .......).findAny();

Or if you only need an information if such an object exists, use anyMatch:

boolean exists = contactList.stream().anyMatch(contact -> contact.getStreet().equals("dubai") || 
                        contact.getCity().equals("dubai") || .......);

You can solve this by using reflection to read all class properties

or

By overriding toString() method and check if the result of to String contains input string

One possible way would be to override toString() with required properties and use it to check if it contains a word,

contactList.stream()
    .filter(contact -> contact.toString().contains("dubai"))
    .collect(Collectors.toList());

You may also want to use Pattern to match the exact word.

I have a project that use Gson and JSON, when I read your question, the first thing I think of is:

  1. Convert your list to a JsonArray of JsonObject => You can easily get the keyset of each JsonObject (the properties list of your contact object)
  2. Filter in that list, find all JsonObject that has the value "dubai"

I guess, the code blocked your problem is resolved.

contactList.stream().anyMatch(contact -> contactMacther(contact,"dubai"));
private boolean contactMacther(Contact contact, String match){
    return contact.getStreet().equalsIgnoreCase(match) ||
            contact.getCity().equalsIgnoreCase(match);

You can create list of functions that extract properties, than use it in your filter method:

List<Function<Contact, Object>> getPrperties = Arrays.asList(
        Contact::getStreet, 
        Contact::getCity
        // other
        );

contactList.stream()
        .filter(contact -> getPrperties.stream()
                .map(f -> f.apply(contact))
                .anyMatch("dubai"::equals)
        )
        .collect(Collectors.toList();

Or you can extract test method:

BiFunction<Contact, String, Boolean> test = (contact, values) ->
        getPrperties.stream().map(f -> f.apply(contact)).anyMatch(values::equals);

List<Person> collect = contactList.stream()
        .filter(contact -> test.apply(contact, "dubai"))
        .collect(Collectors.toList());
Related