3

According to this answer an int constant is implicitly converted to short type.

But in my unit test I want to test a getValue() function which returns a Short.

assertEquals(obj.getValue(), 42); 

Obviously the above doesn't work, so I attempt to use Short.valueOf

assertEquals(obj.getValue(), Short.valueOf(42)); 

Yet, this still complains - despite the aforementioned implicit conversion - so I have to cast the literal.

assertEquals(obj.getValue(), Short.valueOf((short)42)); 

Short.valueOf((short)5) seems a bit messy! Is there a cleaner way? ( new Short("42") equally horrible! )

Community
  • 1
  • 1
Richard
  • 2,994
  • 1
  • 19
  • 31
  • 1
    It needs a cast, because **literal integer** values are treated as `int`, so you need to tell the compiler that it is actually a `short`. – Mr. Polywhirl Oct 08 '14 at 10:19
  • Related to this: http://stackoverflow.com/questions/317816/why-are-there-no-byte-or-short-literals-in-java – PeterMmm Oct 08 '14 at 10:19
  • Take a look at Integer Literals in the JLS: http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.1 – René Link Oct 08 '14 at 10:21

4 Answers4

8

It's because converting a number from int to short may fail (overflow) as it's a narrowing primitive conversion. In theory the compiler could recognise that the argument is a constant expression and it could determine whether the conversion is valid at compile time. But it doesn't.

A cleaner way is:

Short s = 42; //autoboxing is done here
assertEquals(obj.getValue(), s );

The reason the above works is that the rules for variable assignment are different. Here the compiler does indeed check whether the constant expression can be converted to short without overflow.

In addition, if the expression is a constant expression (§15.28) of type byte, short, char, or int:

A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable.

A narrowing primitive conversion followed by a boxing conversion may be used if the type of the variable is:

Byte and the value of the constant expression is representable in the type byte.

Short and the value of the constant expression is representable in the type short.

Character and the value of the constant expression is representable in the type char.

The case in bold applies here.

biziclop
  • 48,926
  • 12
  • 77
  • 104
1

The other answers explain why you have this problem. A cleaner option for your code might be:

assertEquals(obj.getValue().intValue(), 42); 

Although as biziclop points out, this would throw a NullPointerException if getValue() returns null. While this would still fail your test, it won't be so obvious what has gone wrong.

Of course, if null values are not allowed, you should return a short not a Short. In which case, you wouldn't need any casts:

assertEquals(obj.getValue(), 42); // fine, if getValue() returns a short
Community
  • 1
  • 1
Duncan Jones
  • 67,400
  • 29
  • 193
  • 254
1

There is no method in Short class that takes int as the paramter , so

Short.valueOf(1); // compilation error

but casting to (short) 1

Short.valueOf((short) 1);

works because there is a method that takes short as the parameter. Why is that compiler cannot do casting automatically for you because

A narrowing primitive conversion may lose information about the overall magnitude of a numeric value and may also lose precision and range.

sol4me
  • 15,233
  • 5
  • 34
  • 34
0

The JLS states

An integer literal is of type long if it is suffixed with an ASCII letter L or l (ell); otherwise it is of type int (§4.2.1).

Therefore you need to cast it to short.

Maybe you are also interested in Why are there no byte or short literals in Java?

Community
  • 1
  • 1
René Link
  • 48,224
  • 13
  • 108
  • 140