Pavel Niedoba
Pavel Niedoba

Reputation: 1577

java autoboxing from int to java.lang.Long casting issue

I'm getting compilation error from trivial substraction

Long result;
int operand1 = 10;
int operand2 = 5;
result = operand1 - operand2;

from last line: incompatible types: int cannot be converted to java.lang.Long

beside the fact that I believe it can be converted what's the best solution to this? Any of the following will compile, but it seems awkward

result = (long) operand1 - operand2;
result = (long) (operand1 - operand2);
result = new Long (operand1 - operand2);
result = Long.valueOf(operand1 - operand2);

Which one is best for performance ?

Upvotes: 0

Views: 6407

Answers (3)

Kenney
Kenney

Reputation: 9093

Let's look at the byte code generated by javac 1.8.0_66:

(result is allocated to slot 1, operand1 is in slot 2, and operand2 in slot 3)

Approach 1:

result = (long) operand1 - operand2;

    5: iload_2
    6: i2l
    7: iload_3
    8: i2l
    9: lsub
   10: invokestatic  #2              // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
   13: astore_1

Approach 2:

result = (long) (operand1 - operand2);

   14: iload_2
   15: iload_3
   16: isub
   17: i2l
   18: invokestatic  #2            // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
   21: astore_1

Approach 3:

result = new Long (operand1 - operand2);

   22: new           #3            // class java/lang/Long
   25: dup
   26: iload_2
   27: iload_3
   28: isub
   29: i2l
   30: invokespecial #4            // Method java/lang/Long."<init>":(J)V
   33: astore_1

Approach 4:

result = Long.valueOf(operand1 - operand2);

This produces the exact same bytecode as Approach 2. Omitted for brevity.


As you can see, all four approaches construct a new Long object, since Long.valueOf() will call new Long() (although Long.valueOf() caches Long objects for values between -128 and 127 (in at least Java 1.8.0_66). If the values are outside of that range, calling the constructor is actually a tiny bit faster since it bypasses the cache checks!).

Approach 5: If you're interested in speed, don't use autoboxing, but use primitive types. Here's the change:

long result; // not Long

and the original statement works without complaints from the compiler:

result = operand1 - operand2;

   6: iload_3
   7: iload         4
   9: isub
  10: i2l
  11: lstore_1

As noted elsewhere on this page, there may be overflow issues: the ints are subtracted first, then converted to a long. It might be best to simply use long for all 3 types (which will skip the i2l above).

Upvotes: 3

Andy Turner
Andy Turner

Reputation: 140554

2 and 4 are basically the same. I wouldn't be surprised if they produce the same bytecode.

1 is going to be pretty much the same as 2 and 4 performance-wise, but it might produce slightly different answers if the integer subtraction in 2 and 4 overflows.

  • 1 is equivalent to Long.valueOf((long) op1 - (long) op2)
  • 2 and 4 are equivalent to Long.valueOf((long) (op1 - op2))

The only one I would avoid is 3, because this definitely produces a new value, whereas the others might use a cached value, depending upon implementation of Long.valueOf:

[Long.valueOf] returns a Long instance representing the specified long value. If a new Long instance is not required, this method should generally be used in preference to the constructor Long(long), as this method is likely to yield significantly better space and time performance by caching frequently requested values. Note that unlike the corresponding method in the Integer class, this method is not required to cache values within a particular range.

Upvotes: 1

Sergey Emeliyanov
Sergey Emeliyanov

Reputation: 6991

First 2 lines are supposedly best for performance since you are not creating any objects. 'long' is a primitive data type while 'Long' is a wrapper class for long. Between the first two, I'd say that 2nd is a bit faster, since you do the subtraction on ints and then convert a single value to long, whereas in the 1st - you convert both values to long and then do the subtraction of longs which would be a bit slower.

Regarding the compilation issue - primitive types do convert automatically to a larger one, i.e. int would convert to long if you subtract them. However, if you assign a value of that int to a Long class object you'll get compilation error, since the automatic conversion will not happen, so you'll have to manually convert int primitive to long primitive or to Long object.

Upvotes: 1

Related Questions