0

See the tiny method below. The boo1 = ... line goes fine, probably as it does object ID comparison. The second boo2 = ... line gives a compile error "Operator > cannot be applied to T,T". I don't understand why. After all T extends Number (as you can see in the method signature), so comparisons like > should be possible. What am I doing wrong?

public static <T extends Number> int[] where(T[] arr, T val) {
        if (arr == null || arr.length == 0) return null;

        boolean boo1 = arr[0] == val; //Compiles happily, as does "!="
        boolean boo2 = arr[0] > val;  //Doesn't compile (nor does ">=", "<", "<="

        return null;
    }
Med Elgarnaoui
  • 1,612
  • 1
  • 18
  • 35
mkemper
  • 57
  • 6

2 Answers2

5

What am I doing wrong?

You're assuming that the relational operators support Number operands; they don't. Only Numbers that box primitive types (e.g. Integer, Long) do; others such as BigInteger don't.

You can add an additional bound to T to require it to be Comparable:

<T extends Number & Comparable<T>>

And you can pass in any types that are both Numbers and are Comparable: this includes Integer, Long, BigInteger etc.

Then you can use:

arr[0].compareTo(val) > 0

(but you might care to watch out for nulls).

Also, you shouldn't be using == and != to check for equality/inequality: use equals instead:

arr[0].equals(val)  // Instead of ==
!arr[0].equals(val) // Instead of !=

You can, alternatively, use arr[0].compareTo(val) ==/!= 0. That may be better, in fact, because e.g. BigInteger and BigDecimal have equals methods that consider scale, so [1.00].equals([1.0]) is false, whereas [1.00].compareTo([1.0]) == 0 is true. Ultimately, it depends on what you're trying to achieve as to which way to choose.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • Even for those that box primitive types, you're running up against autoboxing. Comparing `Integer` with `>` is illegal. It's just that Java is clever in that case and replaces it with the result of `Integer.intValue`. But that's a trick of the Java compiler, akin to syntax sugar. – Silvio Mayolo Mar 18 '22 at 15:49
  • @SilvioMayolo there's no difference in "legality" or "cleverness" between comparing an `Integer` with an `Integer`, an `int` with an `int` or a `double` with an `int`: in all cases, [the operands undergo binary numeric promotion](https://docs.oracle.com/javase/specs/jls/se17/html/jls-15.html#jls-15.20.1). – Andy Turner Mar 18 '22 at 17:07
-1

Try it this way:

public static <T extends Number> int[] where(T[] arr, T val) {
    if (arr == null || arr.length == 0) return null;

    boolean boo1 = arr[0] == val; //Compiles happily, as does "!="
    boolean boo2 = arr[0].intValue() > val.intValue();
    // Or doubleValue()

    return null;
}
Stewart
  • 17,616
  • 8
  • 52
  • 80
  • 2
    `intValue()` doesn't work for e.g. `arr[0] == 1.2` and `val == 1.1`. `doubleValue()` doesn't work for `Long`s/`BigInteger`s etc that are too big. – Andy Turner Mar 15 '22 at 13:35
  • 1
    @MedElgarnaoui the result is an `int[]`; the parameters aren't, and it's parameters that are being compared. – Andy Turner Mar 15 '22 at 13:38
  • There are many other cases that will not work either. All of `Long`, `Float`, `BigInteger` and `BigDecimal` can hold numbers outside the `int` range, from which you would not get the expected result. – Ole V.V. Mar 15 '22 at 14:20