Say you have a method that
it would look something like this:
<N extends Number & Comparable<N>, S extends N> S ensureLessThan(N threshold, S input) {
if (input.compareTo(threshold) >= 0) {
throw new IllegalArgumentException("Input " + input + " is not less than " + threshold);
}
return input;
}
When run, this method throws a NoSuchMethodError
:
Exception in thread "main" java.lang.NoSuchMethodError: java.lang.Number.compareTo(Ljava/lang/Object;)I
Adding what looks like a redundant cast makes it work:
...
if (((N) input).compareTo(threshold) >= 0) {
...
So what's going on here?
UPDATE: My Java version is
java version "1.6.0_37"
Java(TM) SE Runtime Environment (build 1.6.0_37-b06-434-11M3909)
Java HotSpot(TM) 64-Bit Server VM (build 20.12-b01-434, mixed mode)
And here's a runnable example: https://gist.github.com/4526536
lang. NoSuchMethodError is a runtime error in Java which occurs when a method is called that exists at compile-time, but does not exist at runtime. The Java Garbage Collector (GC) cannot free up the space required for a new object, which causes a java. lang.
In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. Much like the more familiar formal parameters used in method declarations, type parameters provide a way for you to re-use the same code with different inputs.
Dig into the do. something code, decompiling it if you don't have the source, and see what is actually thrown by it. Possibly if the exception gets thrown it might get wrapped in another exception. Make sure that anything thrown by the method does not get eaten (including by your own logging of it).
I suspect it's a bug in the compiler. It has staticly bound to Number.compareTo(Object)
which doesn't exist, when it should be Comparable.compareTo(Object)
.
if (threshold.compareTo(input) < 0) {
will work.
It certainly appears to be a compiler error. The reason this works is that the compiler generates a checked cast to Comparable. Whereas the other way around it does not.
ensureLessThan(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;
L0
LINENUMBER 11 L0
ALOAD 1
CHECKCAST java/lang/Comparable
ALOAD 2
INVOKEINTERFACE java/lang/Comparable.compareTo (Ljava/lang/Object;)I
IFGE L1
versus
ensureLessThan(Ljava/lang/Number;Ljava/lang/Number;)Ljava/lang/Number;
LINENUMBER 11 L0
ALOAD 1
ALOAD 2
INVOKEVIRTUAL java/lang/Number.compareTo (Ljava/lang/Object;)I
IFGE L1
That's strange, the following code compiles and runs from my side:
/**
* @author Buhake Sindi
* @since 14 January 2013
*
*/
public class Test {
public static <N extends Number & Comparable<N>, S extends N> S ensureLessThan(N threshold, S input) {
if (input.compareTo(threshold) >= 0) {
throw new IllegalArgumentException("Input " + input + " is not less than " + threshold);
}
return input;
}
public static void main(String[] args) {
ensureLessThan(10, 5);
}
}
Tested in Eclipse Juno (Java EE), with the following JDK:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With