Let's take a closer look at what happens. In snippet 1:
double dbl = 10.25;
int i1 = (int) Math.round(dbl);
You declare a double
. The result after rounding is a long
. Then comes a cast to int
which is possible since both are primitive types, Java allows the cast. Then you store this inside int
.
In snippet 2 however things change a bit:
double dbl = 10.25;
Long lng = Math.round(dbl);
int i2 = (int) lng;
You declare a double
, round returns a long
but you want to store it inside Long
. So Java automatically transforms long
into Long
, this is called auto-boxing. Java can box all primitive types to their wrapper classes.
Last you try to cast Long
to int
but this is not possible since Long
is an object now. It can however automatically unbox Long
to long
. From there you can go to int
. Let's first take a look at those two variants:
int i2 = (long) lng; // Make unboxing explicit by casting
int i2 = lng.longValue() // Use unboxing method
However it won't compile either due to:
incompatible types: possible lossy conversion from long to int
So the conversion is possible but the compiler warns us that a long
could possibly not fit into an int
(lossy conversion), thus it prevents us from doing so.
We can however do the conversion by again making it explicit by casting:
int i2 = (int) lng.longValue() // The whole process completely explicit
Or if you have Java 8, use Math#toIntExact
(documentation) which will throw an ArithmeticException
if the long
doesn't fit into the int
:
int i2 = Math.toIntExact(lng.longValue());
Note that Java won't unbox your Long
to long
and then cast it to int
automatically, you will need to make the unboxing explicit on your own, as shown.
It's simply one of the casting rules of the JVM, in this case probably to prevent unintentional programming errors.