Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we’ll look at several methods in Java for checking if an element in one List is also present in another. We’ll explore various ways how to achieve it using Java Streams, Collections disjoint(), and Apache Commons.

2. Checking for Basic Equivalence

The simplest version of this problem is if we want to check if an element in one List is equivalent to one in another. This could be primitive values or objects, assuming we’ve set up our objects to be compared. Let’s create some Lists to compare:

List<String> listOfLetters = Arrays.asList("a", "b", "c", "d");
List<String> listOfLettersWithOverlap = Arrays.asList("d", "e", "f", "g");
List<String> listOfCities = Arrays.asList("London", "Berlin", "Paris", "Brussels");

The String “d” appears in the first two Lists, so we’d expect any solution to this problem to detect that. We’d also expect comparing either of the first two with listOfCities to return a negative result.

2.1. Using Disjoints

The first option we’ll look at is the disjoint() method found in the Java Collections library. disjoint() returns true if two specified Collections have no elements in common. Therefore, as we are looking to find when two Collections do have elements in common, we’ll reverse the result with the not operator:

@Test
void givenValuesToCompare_whenUsingCollectionsDisjoint_thenDetectElementsInTwoLists() {
    boolean shouldBeTrue = !Collections.disjoint(listOfLetters, listOfLettersWithOverlap);
    assertTrue(shouldBeTrue);

    boolean shouldBeFalse = !Collections.disjoint(listOfLetters, listOfCities);
    assertFalse(shouldBeFalse);
}

Above, we see the expected result of our overlapping lists of letters returning true and a false value returning after comparing them with the list of cities.

2.2. Using Streams

The second way available to us in Java is using Streams. Specifically, we’ll utilize the anyMatch() method, which returns true if any element in the Stream matches the given predicate:

@Test
void givenValuesToCompare_whenUsingStreams_thenDetectElementsInTwoLists() {
    boolean shouldBeTrue = listOfLetters.stream()
      .anyMatch(listOfLettersWithOverlap::contains);
    assertTrue(shouldBeTrue);

    boolean shouldBeFalse = listOfLetters.stream()
      .anyMatch(listOfCities::contains);
    assertFalse(shouldBeFalse);
}

The predicate provided to anyMatch() is a call to the Collections contains() method. This returns true if the Collection contains the specified element.

2.3. Using Apache Commons

Our final method is to use Apache Commons CollectionUtils method containsAny(). In order to use this, we’ll first need to import the dependency into our pom.xml:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.4</version>
 </dependency>

We can find the latest version in the Maven Repository. With that ready, we can then use the library like this:

void givenValuesToCompare_whenUsingApacheCollectionUtils_thenDetectElementsInTwoLists() {
    boolean shouldBeTrue = CollectionUtils.containsAny(listOfLetters, listOfLettersWithOverlap);
    assertTrue(shouldBeTrue);

    boolean shouldBeFalse = CollectionUtils.containsAny(listOfLetters, listOfCities);
    assertFalse(shouldBeFalse);
}

This method is simple and readable. However, it is only likely to be used if we are already using the Apache imports, given that there are inbuilt Java methods.

3. Checking for a Property Within an Object

A more complex version of this problem is if we want to check if any objects in two Lists have matching properties. Let’s create an example object we can use for this:

class Country {
    String name;
    String language;
    // standard getters, setters and constructors
}

Following that, we can create a few instances of the Country class and put them into two Lists:

Country france = new Country("France", "French");
Country mexico = new Country("Mexico", "Spanish");
Country spain = new Country("Spain", "Spanish");
List<Country> franceAndMexico = Arrays.asList(france, mexico);
List<Country> franceAndSpain = Arrays.asList(france, spain);

Both Lists have a country with the language Spanish, so we should be able to detect that when comparing them.

3.1. Using Streams

Let’s use the above Lists and check if we have countries in both that speak the same language. We can use Streams to do this in a similar way to what we saw in section 2.2. The main difference here is we use map() to extract the property we are interested in, the language in this example:

@Test
public void givenPropertiesInObjectsToCompare_whenUsingStreams_thenDetectElementsInTwoLists() {
    boolean shouldBeTrue = franceAndMexico.stream()
      .map(Country::getLanguage)
      .anyMatch(franceAndSpain.stream()
        .map(Country::getLanguage)
        .collect(toSet())::contains);

    assertTrue(shouldBeTrue);
}

We again utilize anyMatch(). However, this time we collect the languages into a Set and use contains() to check if the current language is in the Set. As shown above, we find a match as both Lists contain a Spanish-speaking country.

4. Conclusion

In this article, we’ve seen that Streams are the most versatile solution to this problem. We can easily use them to compare entire objects or properties within the objects. Additionally, we’ve looked at alternatives for simpler use cases with Java’s disjoint() and Apache’s containsAny(). Both of which are easy to use and produce readable code.

As always, the full code for the examples is available over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.