Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java 8 method reference to: either `equals` or `equalsIgnoreCase`

I tried to convert the body of a method boolean exists(String value, boolean isCaseSensitive) :

    for(String str : existingNames){
        if(isCaseSensitive ? str.equals(name) : str.equalsIgnoreCase(name)){
            return true;
        }
    }

    return false;

to a solution that utilises java8 method references:

    Predicate<String> equalityPred = isCaseSensitive ? 
            name::equals : 
            name::equalsIgnoreCase;

    return existingNames.stream().anyMatch(equalityPred);

Then I saw that this way the equality is performed in the opposite direction (e.g. value.equals(str) ).
Is there a way to fix this and still use method references, and if no what would be the java8 way.

like image 698
Marinos An Avatar asked May 02 '17 18:05

Marinos An


2 Answers

There is no “opposite direction” for equality. The only issue might be the behavior for null values. Your loop might fail, if the collection contains null, your method references will fail, if name is null.

You may achieve the original behavior using lambda expressions:

boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
    Predicate<String> equalityPred = isCaseSensitive? 
        s -> s.equals(name): 
        s -> s.equalsIgnoreCase(name);

    return existingNames.stream().anyMatch(equalityPred);
}

but it makes little sense to consider null for the name parameter, when it will never be equal, as the code will fail with a NullPointerException, if the collection contains null.

To get a sensible behavior for null, you may use

boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
    Predicate<String> equalityPred = name==null? Objects::isNull:
        isCaseSensitive? name::equals: name::equalsIgnoreCase;

    return existingNames.stream().anyMatch(equalityPred);
}

or just

boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
    return name==null || isCaseSensitive?
        existingNames.contains(name):
        existingNames.stream().anyMatch(name::equalsIgnoreCase);
}

If you know that the Collection will never contain null, but want to support null for the name parameter, you could also use

boolean check(Collection<String> existingNames, String name, boolean isCaseSensitive) {
    return name!=null && existingNames.stream()
        .anyMatch(isCaseSensitive? name::equals: name::equalsIgnoreCase);
}
like image 148
Holger Avatar answered Oct 12 '22 11:10

Holger


Well don't use a method reference then and write your lambda directly:

     static boolean existsJDK8(List<String> existingNames, String value, boolean isCaseSensitive) {
         Predicate<String> equalityPred = isCaseSensitive ? s -> value.equals(s) : s -> value.equalsIgnoreCase(s);

         Predicate<String> equalityPredReversed = isCaseSensitive ? s -> s.equals(value) : s -> s.equalsIgnoreCase(value);

         // return  existingNames.stream().anyMatch(equalityPredReversed);
        return existingNames.stream().anyMatch(equalityPred);
     }
like image 44
Eugene Avatar answered Oct 12 '22 09:10

Eugene