Java unboxing on method return value

244 Views Asked by At

Given following method:

Long getLong() {
    ...
}

If I call it and assign the return value to a variable like this:

long abc = getLong();

Will a Long object get generated and then converted to long or Java is smart enough to avoid generating the intermediate Long object? Or it might actually depends on the implementation of getLong()?

The reason I am asking this is that the wrapper object size is usually much bigger than the corresponding primitive type size. If I have to call this method a lot of times and each time memory needs to be allocated to the Long object, the program will end up consuming a lot more memory than it actually needs, which triggers more GC cycles.

Also, how can I verify the exactly steps happening when executing long abc = getLong() (basically also looking for guidance on how can I get answers myself for the questions above)?

3

There are 3 best solutions below

0
Edwin Dalorzo On BEST ANSWER

Perhaps the simplest way to test your question is by writing a small example and then run the Java disassembler.

Let's say we had this class:

public class Unboxing {

    public static void main(String[] args) {
        long l = getLong();
    }

    public static Long getLong() {
        return 10L;
    }

}

Then we can compile it (javac Unboxing.java) and once compiled we can disassemble it (javap -c -s Unboxing) to see its bytecodes and learn what the JVM is doing under the hood.

public class Unboxing {
  public Unboxing();
    descriptor: ()V
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    Code:
       0: invokestatic  #7                  // Method getLong:()Ljava/lang/Long;
       3: invokevirtual #13                 // Method java/lang/Long.longValue:()J
       6: lstore_1
       7: return

  public static java.lang.Long getLong();
    descriptor: ()Ljava/lang/Long;
    Code:
       0: ldc2_w        #19                 // long 10l
       3: invokestatic  #21                 // Method java/lang/Long.valueOf:(J)Ljava/lang/Long;
       6: areturn
}

You can see in the code that it gets an Long object, and then call its longValue method on it:

0: invokestatic  #7                  // Method getLong:()Ljava/lang/Long;
3: invokevirtual #13                 // Method java/lang/Long.longValue:()J

After that it stores it into the variable l (lstore_1).

So, that probably answers your question.

0
Victor Polo De Gyves Montero On

You asked: "Will a Long object get generated and then converted to long or Java is smart enough to avoid generating the intermediate Long object? Or it might actually depends on the implementation of getLong()?"

Java is smart enough to protect you from shooting your own foot, so it will create a Long object, just as it is requested by the method signature, then if your code assigns it to a long it will unbox it. Whichever reason the developer had to return Long from getLong() must be strictly respected. Boxing/Unboxing is focused on readability and not on performance. It is strictly required to create a new long getLong() method if you want to only use long all along your code, which will usually be faster.

For the other question, you just need to use a debugger and use the "step into" tools provided by the debugger, try with Eclipse, IntelliJ or NetBeans, to name a few

0
Anonymous On

By all probability you have no need or reason to care.

Yes, as the others say, when a method returns a Long object, then it returns a Long object. Or null, but that doesn’t seem to be the case here. However, if that object is created in the method just before return, then it’s a very short-lived object. The garbage collector handles such efficiently, so allocation of the space is unlikely to hurt you. You will not end up with any considerable memory consumption since you have got only one (1) Long object at a time.

In the case in Edwin Dalorzo’s answer and many other cases the Long object will not even be allocated and garbage collected at all and will not require any more memory than the primitive long. How come? Long objects for the range from -127 through 128 are pre-allocated and shared. So when Edwin’s method returns 10L, in practice a reference to the pre-allocated object is just returned. No allocation takes place at return.

That said, if the method never returns null, for readability reasons returning an object is a bad design. It should return a primitive. If in some cases there is no long value to return, one may consider returning an OptionalLong. Those are not pre-allocated, but are also short-lived and therefore handled efficiently by the garbage collector.