1

Example:

Is something like this

public double roundDecimal(double val) {
    return Double.parseDouble(new DecimalFormat("#,##0.0").format(val));
}

double d1 = roundDecimal(val);
double d1 = roundDecimal(val);
double d1 = roundDecimal(val);
// A lot more of these...

considered bad practice instead of something like this?

public double roundDecimal(double val, DecimalFormat dFormat) {
    return Double.parseDouble(dFormat.format(val));
}

DecimalFormat dFormat = new DecimalFormat("#,##0.0");

double d1 = roundDecimal(val, dFormat);
double d1 = roundDecimal(val, dFormat);
double d1 = roundDecimal(val, dFormat);
// A lot more of these...

The difference of course being that instead of creating the DecimalFormat object over and over, I just create it once and resuse it. My thoughts are that the garbage collector would ensure something like this wouldn't matter, but I don't understand it enough to know for sure.

2
  • 1
    See also programmers.stackexchange.com/questions/149563/… Commented Sep 12, 2016 at 19:32
  • 1
    @AndyTurner Those statements should be offset by the effects CPU cache line churn and GC costs which may not be much, but become relevant if the actual work per object allocated is very small (implying the instantiation of millions of objects per second). Then there's the infamous time-to-safepoint, etc. Commented Sep 12, 2016 at 19:44

5 Answers 5

2

You are obviously looking at the wrong end. Even the “optimized” variant

public double roundDecimal(double val, DecimalFormat dFormat) {
    return Double.parseDouble(dFormat.format(val));
}

creates multiple objects on each call. On the API side, format returns a new String instance which you pass to parseDouble. Below the surface both operations, format and parseDouble create temporary objects for doing their work. Their implementor(s) had no reason to worry about them, as the tasks of formatting a double to decimal representation and parsing a decimal representation to double are so expensive, that they outweigh anything.

It’s easy to overlook, as for us humans, decimal representations seem to be the most natural thing, but for a computer, converting to a decimal representation and back is very expensive.


But before you continue worrying about the performance, you should start worrying about correctness. Generally, it’s a bad idea to apply the concept formatting to double values. Since their internal representation is fundamentally different to decimal numbers, they can’t represent tenths exactly. If you want a controllable precision of that kind, BigDecimal is the right tool for the job (yes, they are objects…). Or you use the result string of the Formatter for printing or any other UI presentation.

Besides that, by using the format string "#,##0.0", you are requesting a string with a grouping separator which Double.parseDouble does not expect. Further, you are applying the decimal format of the current user’s locale, so if it is not using . as decimal separator, the operation will, break even when the value is too small for grouping. So for English locales, passing the value 1234 is sufficient to break this method, for, e.g. German locales, it will break with every value.

A work-around would be to use the same format for parsing that you used for formatting:

public double roundDecimal(double val, DecimalFormat dFormat) {
    try {
        return dFormat.parse(dFormat.format(val)).doubleValue();
    } catch (ParseException ex) {
        throw new AssertionError(ex);
    }
}

but this still will have a desastrous performance, not because of the temporary objects created.

After all, if you still want to use double values rather than BigDecimal, the solution is straight-forward:

public double roundDecimal(double val) {
    return Math.round(val*10)/10.0;
}
Sign up to request clarification or add additional context in comments.

Comments

2

If you create and throw away a lot of objects it will make the garbage collector work harder. The more garbage you create, the more pauses are needed for GC to catch up. It's a lot better to reuse one object as in your second example.

If you start reworking your code to minimize how many formatters you need, be careful not to reference the same DecimalFormat object across threads, see the API documentation:

Decimal formats are generally not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

Looking at the context in which you're doing this formatting, using a formatter to do rounding seems very questionable, Holger's answer contains good advice.

2 Comments

The idea of using a formatter for this kind of task, is so fundamentally wrong, that the thread safety issue of a shared formatter is only the tip of the iceberg. See this answer
@Holger: i didn't even read that part of the question. Agreed, this is messed up.
1

Instantiating it over and over again seems like an unneccesary overhead. This would only become an issue if you are dealing with thousands of instances. Second approach is recommended for this case.

Comments

1

Yes. Creating multiple instances of a class means executing the constructor multiple times, which definitely costs execution time and probably costs memory, depending on what the constructor does. You’re right that garbage collection will recover the allocated memory, but garbage collection also has a cost.

Comments

1

In general, yes this kind of thing will affect performance. Memory allocation and garbage collection are typically very large time sinks in a Java program. However, in this particular case, I imagine that the compiler would see that the DecimalFormat object is effectively constant and could make that optimization for you.

1 Comment

Allocation itself is as expensive as incrementing a long value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.