0

I'm writing a simple Predicate function as follows:

public static Predicate<String> stringPredicate(String op, String compVal) {
    if (op.equals("=")){
        return p -> p.compareTo(compVal) == 0;
    }
    else if (op.equals("<")){
        return p -> p.compareTo(compVal) == -1;
    }
    else if (op.equals("<=")){
        return p -> p.compareTo(compVal) == 0 || p.compareTo(compVal) == -1;
    }
    else if (op.equals(">")){
        return p -> p.compareTo(compVal) == 1;
    }
    else if (op.equals(">=")){
        return p -> p.compareTo(compVal) == 1 || p.compareTo(compVal) == 0;
    }
    return p -> -1 == 0; //return false 
}

I'd like this function to work for both Integers, Floats and Strings. So, rather than writing 2 identical predicate functions, one for Strings and one for Integer+Float, I'd like to write a single one as compareTo() method works for all 3 of them. I guess I can do it by replacing Predicate<String> with Predicate<Super class of Integer/Float/String>. I tried Object but that didn't work. So, what should I put instead of <String> to use the function in the way I want?

Pshemo
  • 122,468
  • 25
  • 185
  • 269
SpiderRico
  • 1,890
  • 8
  • 28
  • 48

1 Answers1

7

There is no common "superclass" of Integer and String other than Object, which is useless for you since it doesn't have compareTo.

But there is a common interface between the two — Comparable<T>, which provides the compareTo method.

public static <T extends Comparable<T>> Predicate<T> predicate(String op, T compVal) {
    switch (op) {
        case "=": return p -> p.compareTo(compVal) == 0;
        case "<": return p -> p.compareTo(compVal) < 0;
        case "<=": return p -> p.compareTo(compVal) <= 0;
        case ">": return p -> p.compareTo(compVal) > 0;
        case ">=": return p -> p.compareTo(compVal) >= 0;
        default: return p -> false;
    }
}

(Starting from Java 7 you could switch on strings, so there is no point using an if/else chain here. But in your case an enum for op may even be more suitable.)

Community
  • 1
  • 1
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • Thank you. This looks exactly what I need. – SpiderRico Apr 18 '17 at 15:31
  • Consider **currying** based on a `Map`. `functionMap.put(">", (a,b) -> x.compareTo(y) > 0)` etc. Then `return p -> functionMap.get(op).apply(p,compVal)`. Or an enum instead of the map. – slim Apr 18 '17 at 15:40
  • @slim That's just moving the `switch` into a `Map`, you still need to duplicate the same amount of code. I don't how this will improve anything :) – kennytm Apr 18 '17 at 15:44