0

I don't understand why code snippet 1 works fine, but code snippet 2 gives compile time error incompatible types: java.lang.Long cannot be converted to int

Is related to priority of casting in java? I went through this thread on stackoverflow, but it didn't help.

Please explain in detail what happens behind the scenes in the both the snippets and why it doesn't give error in code snippet 1.

Code snippet 1:

package com.company;

public class Main
{
    public static void main(String[] args)
    {
        double dbl = 10.25;
        int i1 = (int)Math.round(dbl);
    }
}

Code snippet 2:

package com.company;

public class Main
{
    public static void main(String[] args)
    {
        double dbl = 10.25;
        Long lng = Math.round(dbl);
        int i2 = (int)lng;
    }
}
AnV
  • 2,794
  • 3
  • 32
  • 43
  • [Check this](https://stackoverflow.com/a/36331461/3148590) – Kaustubh Khare Nov 18 '17 at 14:16
  • 2
    `int` and `long` and `double` are primitives, they can be casted. `Integer`, `Long`, `Double` are Objects, no cast possible. – Zabuzard Nov 18 '17 at 14:21
  • https://stackoverflow.com/questions/12514958/how-does-double-to-int-cast-work-in-java – Alexis C. Nov 18 '17 at 14:22
  • Check [this SO question](https://stackoverflow.com/questions/30776256/casting-rules-for-primitive-types-in-java) which lists the rules for casting primitives. It looks like `long` to `int` is an allowed narrowing cast. – Tim Biegeleisen Nov 18 '17 at 14:23
  • @Zabuza you made my day. Now I understood what's the issue. So if the use `long` in snippet #1 instead of `Long`, it would work. My goodness! – AnV Nov 18 '17 at 14:26

1 Answers1

1

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.

Zabuzard
  • 25,064
  • 8
  • 58
  • 82