示例:
是这样的
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...
认为是不好的做法,而不是像这样的事情?
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...
当然不同的是,我不是一遍又一遍地创建DecimalFormat对象,而是创建它一次并重新使用它。我的想法是,垃圾收集器会确保这样的事情无关紧要,但我不明白它是否足以确定。
答案 0 :(得分:2)
如果你创建并丢弃了很多对象,它将使垃圾收集器更加努力。您创建的垃圾越多,GC需要停顿的次数就越多。如第二个例子中那样重用一个对象要好得多。
如果您开始重新编写代码以最小化所需的格式化程序数,请注意不要跨线程引用相同的DecimalFormat对象,请参阅the API documentation:
十进制格式通常不同步。建议为每个线程创建单独的格式实例。如果多个线程同时访问格式,则必须在外部进行同步。
查看您正在进行此格式化的上下文,使用格式化程序进行舍入似乎非常值得怀疑,Holger's answer包含了很好的建议。
答案 1 :(得分:2)
你显然看错了。甚至是“优化的”变体
public double roundDecimal(double val, DecimalFormat dFormat) {
return Double.parseDouble(dFormat.format(val));
}
在每次调用时创建多个对象。在API方面,format
会返回您传递给String
的新parseDouble
实例。在表面两个操作下方,format
和parseDouble
创建用于完成工作的临时对象。他们的实现者没有理由担心它们,因为格式化double
到十进制表示并将十进制表示解析为double
的任务是如此昂贵,以至于它们超过任何东西。
很容易忽视,对于我们人类来说,十进制表示似乎是最自然的事情,但对于计算机来说,转换为十进制表示并返回非常昂贵。
但在您继续担心性能之前,您应该开始担心正确性。通常,将概念格式应用于double
值是个坏主意。由于它们的内部表示与十进制数字根本不同,因此它们不能完全代表十分之一。如果你想要这种可控制的精度,BigDecimal
是工作的正确工具(是的,它们是对象......)。或者您使用Formatter
的结果字符串进行打印或任何其他UI演示。
除此之外,通过使用格式字符串"#,##0.0"
,您正在请求具有分组分隔符的字符串Double.parseDouble
不期望。此外,您正在应用当前用户的区域设置的十进制格式,因此如果它不使用.
作为小数分隔符,则操作将在值太小而无法进行分组时中断。因此,对于英语区域设置,传递值1234
足以打破此方法,例如,德语区域设置,它将与每个值打破。
解决方法是使用相同的格式进行格式化解析:
public double roundDecimal(double val, DecimalFormat dFormat) {
try {
return dFormat.parse(dFormat.format(val)).doubleValue();
} catch (ParseException ex) {
throw new AssertionError(ex);
}
}
但是由于创建了临时对象,这仍然会有一个灾难性的表现,不是。
毕竟,如果您仍想使用double
值而不是BigDecimal
,则解决方案很简单:
public double roundDecimal(double val) {
return Math.round(val*10)/10.0;
}
答案 2 :(得分:1)
一遍又一遍地实例化似乎是一种不必要的开销。如果您要处理数千个实例,这只会成为一个问题。对于这种情况,建议使用第二种方法。
答案 3 :(得分:1)
是。创建类的多个实例意味着多次执行构造函数,这肯定会花费执行时间并且可能花费内存,具体取决于构造函数的作用。你是对的,垃圾收集将恢复分配的内存,但垃圾收集也有成本。
答案 4 :(得分:1)
一般来说,是的,这种事情会影响表现。内存分配和垃圾收集通常是Java程序中非常大的时间接收。但是,在这种特殊情况下,我想编译器会看到DecimalFormat对象实际上是常量并且可以为您进行优化。