Girish
Girish

Reputation: 93

typecast vs using valueOf

I need to convert a long variable to double. The value of the long variable is a not a literal, it is a value returned by another method, say, System.currentTimeMillis(). I need to convert it into double for decimal calculations like converting milliseconds to seconds, without losing the decimal part.

So one way to do that is to use Double.valueOf() and then divide the .doubleValue() output by 1000.

long then = System.currentTimeMillis();
long now = System.currentTimeMillis();
double timeElapsed = Double.valueOf(now - then).doubleValue() / 1000;

Is this the right approach? Or should I simply cast them as follows?

double timeElapsed = ((double) now - (double) then) / 1000;

I am wondering which is the best way to do this.

Please shatre your opinions/suggestions.

Thanks.

Upvotes: 4

Views: 1845

Answers (3)

user949300
user949300

Reputation: 15729

I'd go

double timeElapsed = (now - then) / 1000.0;

But, unless you ar doing this 1000s of times in a tight loop it doesn't matter. Do whatever seems clearest to you.

Some claim that "there is no Double.valueOf(long)". Well, Java behaves as if there were. Double.valueOf(2L) does exactly what one thinks it should do. In your code, unless the test were running for years, Double.vaueOf(now - then) would do exactly what you thought it would do. I'd argue that Double.valueOf(long) does exist. It's just not in the Javadocs. If I write double d = 3 + 4.5 does that not exist?

I agree with others here that the Double.valueOf(now - then).doubleValue() is silly, but it should be avoided because it adds confusion, not because it "serves no purpose". With the advent of autoboxing and unboxing, many methods serve no purpose, except, possibly to make things clear. If you think that the explicit Double makes things clearer (in this example, I think not, but your mileage may vary) you should write the code that way.

For example, I still often use the "unnecessary" double primitive = someDouble.doubleValue() to remind myself and other programmers that otherwise auto-unboxing would be happening and a mysterious NPE may be thrown.

Upvotes: -1

Jason C
Jason C

Reputation: 40356

There is no Double.valueOf(long).

What's actually happening in your first example is that now - then is being computed, the result is long, then it is implicitly being cast to a double and passed to Double.valueOf(double). Basically, it is this:

double timeElapsed = Double.valueOf((double)(now - then)).doubleValue() / 1000;

As you can see, that serves no purpose! Note also that auto-unboxing will automatically convert a Double to a double, and so the doubleValue() also serves no purpose.

The cast is the correct approach:

double timeElapsed = (double)(now - then) / 1000.0;

Which, as long as you use 1000.0 instead of 1000, is equivalent to:

double timeElapsed = (now - then) / 1000.0;

The purpose of Double.valueOf(double), by the way, is just to give you a way to explicitly box a double and convert it to a Double if you need to. The purpose of doubleValue() is the opposite. Neither are appropriate for your scenario. (This applies in general to all of the valueOf / *Value methods on primitive wrapper classes.)

By the way, to reduce risk of precision loss (not a big risk in your case but in general), it is generally better to do the above than:

double timeElapsed = ((double)now - (double)than) / 1000.0;

Some explanation of what is happening in your example can be found here. Widening primitive conversions are allowed to happen automatically, and the JLS classifies long to double as a widening conversion.

However, there are risks in the long to double case, the primary risk being that not all values of a long can be represented by a double, and information can be silently lost in the conversion. Consider the following simple test (run it at http://ideone.com/zCmQzg):

for (long a = 1; ; a *= 7) {
    long x = Double.valueOf(a).longValue();
    if (x != a) {
        System.out.println("Conversion fails at input=" + a + " output=" + x);
        break;
    }
}

This test will fail at certain values (e.g. Double.valueOf(11398895185373143L) is not what you expect), becoming guaranteed as as the base-2 mantissa of the long exceeds the range of the mantissa of a double. Another simple test:

long x = 123456789123456789L;
System.out.println(x);
System.out.println(String.format("%20f", Double.valueOf(x))); // implicit
System.out.println(String.format("%20f", (double)x)); // explicit, same thing

Output:

123456789123456789
123456789123456784.000000
123456789123456784.000000

Note the final digit.

This danger exists any time you convert an integer to a double, including in my examples above - however, it is worth noting because passing a long to a Double.valueOf(), in my opinion, can catch one off guard more than the others.

Upvotes: 4

AlexR
AlexR

Reputation: 115378

I've written the following 2 methods:

public static void cast() {
    long l = 123L;
    double d = (double)l / 1000;
}

public static void valueOf() {
    long l = 123L;
    double d = Double.valueOf(l) / 1000;
}

As you can see this is the simplified version of yours code; I did it to make the experiment cleaner.

Now, I compiled the code and then printed the bytecode using javap -v:

  public static void cast();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=4, args_size=0
         0: ldc2_w        #2                  // long 123l
         3: lstore_0
         4: lload_0
         5: l2d
         6: ldc2_w        #4                  // double 1000.0d
         9: ddiv
        10: dstore_2
        11: return
      LineNumberTable:
        line 3: 0
        line 4: 4
        line 5: 11

  public static void valueOf();
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=4, locals=4, args_size=0
         0: ldc2_w        #2                  // long 123l
         3: lstore_0
         4: lload_0
         5: l2d
         6: invokestatic  #6                  // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
         9: invokevirtual #7                  // Method java/lang/Double.doubleValue:()D
        12: ldc2_w        #4                  // double 1000.0d
        15: ddiv
        16: dstore_2
        17: return
      LineNumberTable:
        line 8: 0
        line 9: 4
        line 10: 17

As we can see the code of 2 methods is similar, but in second case we have (as expected) invocations of valueOf() and then of doubleValue().

So, it seems that unless you have some very special reasons you just should use casting. It is shorter, clearer and more cheaper in terms of CPU usage.

Upvotes: -1

Related Questions