我正在编写一个应用程序,需要输出不同长度的小数,并将不同比例缩放为字符串,不带小数点,以便将平面文件写入另一个系统的输入。 e.g。
12345 -> Length:10, Scale:2 -> 0001234500
123.45 -> Length:10, Scale:2 -> 0000012345
123.45 -> Length:10, Scale:3 -> 0000123450
-123.45 -> Length:10, Scale:3, signed:true -> -000123450
123.45 -> Length:10, Scale:3, signed:true -> +000123450
我编写的用于处理此功能的功能在下面,并将被称为数十万次,所以我想确保没有更好,更有效的方法来执行此操作。我已经看过让DecimalFormat为我做更多事情的方法,但我看不到它处理我需要用小数位格式化但没有小数点。
protected String getFormattedDecimal( String value, int len, int scale, Boolean signed ) throws Exception{
StringBuffer retVal = new StringBuffer();
//Need a BigDecimal to facilitiate correct formatting
BigDecimal bd = new BigDecimal( value );
//set the scale to ensure that the correct number of zeroes
//at the end in case of rounding
bd = bd.setScale( scale );
//taking it that if its supposed to have negative it'll be part of the num
if ( ( bd.compareTo( BigDecimal.ZERO ) >= 0 ) && signed ){
retVal.append( "+" );
}
StringBuffer sbFormat = new StringBuffer();
for (int i = 0; i < len; i++)
{
sbFormat.append('0');
}
DecimalFormat df = new DecimalFormat( sbFormat.toString() );
retVal.append( df.format( bd.unscaledValue() ) );
return retVal.toString();
}
答案 0 :(得分:8)
我的性能增强实现如下。它的速度是基于DecimalFormatter的解决方案的4.5倍:在我的机器上运行,使用带有不错的自制测试工具的Eclipse,结果如下:
一些注意事项:
另外:为了模仿原文的行为(但未在评论中给出),这个:
package com.pragmaticsoftwaredevelopment.stackoverflow;
...
final static String formatterZeroes="00000000000000000000000000000000000000000000000000000000000";
protected static String getFormattedDecimal ( String value, int len, int scale, Boolean signed ) throws IllegalArgumentException {
if (value.length() == 0) throw new IllegalArgumentException ("Cannot format a zero-length value");
if (len <= 0) throw new IllegalArgumentException ("Illegal length (" + len + ")");
StringBuffer retVal = new StringBuffer();
String sign=null;
int numStartIdx;
if ("+-".indexOf(value.charAt(0)) < 0) {
numStartIdx=0;
} else {
numStartIdx=1;
if (value.charAt(0) == '-')
sign = "-";
}
if (signed && (value.charAt(0) != '-'))
sign = "+";
if (sign==null)
sign="";
retVal.append(sign);
int dotIdx = value.indexOf('.');
int requestedWholePartLength = (len-scale);
if (dotIdx < 0) {
int wholePartPadLength = (requestedWholePartLength - ((value.length()-numStartIdx)));
if (wholePartPadLength > 0)
retVal.append(formatterZeroes.substring(0, wholePartPadLength));
retVal.append (value.substring(numStartIdx));
if (scale > 0)
retVal.append(formatterZeroes.substring(0, scale));
}
else {
int wholePartPadLength = (requestedWholePartLength - (dotIdx - numStartIdx));
if (wholePartPadLength > 0)
retVal.append(formatterZeroes.substring(0, wholePartPadLength));
retVal.append (value.substring(numStartIdx, dotIdx));
retVal.append (value.substring (dotIdx+1));
int fractionalPartPadLength = (scale - (value.length() - 1 - dotIdx));
if (fractionalPartPadLength > 0)
retVal.append(formatterZeroes.substring(0, fractionalPartPadLength));
}
return retVal.toString();
}
答案 1 :(得分:4)
如果您要将输入作为字符串开头,为什么需要将其转换为BigDecimal并返回?
似乎找到小数点的位置要快得多,将其与长度/比例相比较并相应地填充字符串。
答案 2 :(得分:2)
我同意ChssPly76 wrt手动字符串操作。
但是,如果您要沿着BigDecimal
/ DecimalFormat
路线走下去,您可能需要考虑共享DecimalFormat
而不是每次迭代都创建一个新的ThreadLocal
。请注意,这些类不是线程安全的,因此如果您使用多个线程进行处理,则需要使用Thread
存储之类的内容来维护每{{1}}的格式化程序。