DecimalFormat详解
Posted xt-xutao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DecimalFormat详解相关的知识,希望对你有一定的参考价值。
DecimalFormat继承自NumberFormat,可以使用它将十进制的数以不同形式格式化为字符串形式,可以控制前导和尾随0、前缀、后缀、分组(千)、小数分隔符等,如果要更改格式符号(例如小数点分隔符)。
它有各种各样的设计使其能够解析和格式化数字的特征区域设置,包括对西方、阿拉伯和印度数字的支持。它也支持不同类型的数字,包括整数(123),定点数字(123.4),科学符号(1.23 e4),百分比(12%),以及货币金额(123美元)。所有这些都可以本地化。
可以将其DecimalFormatSymbols
与DecimalFormat
类一起使用。这些类在数字格式化方面提供了极大的灵活性,但它们可以代码更加复杂。
包:import java.text.DecimalFormat;
构建模式
使用DecimalFormat模式指定格式设置String的模式属性pattern:
DecimalFormat df = new DecimalFormat(pattern);
关于pattern,有:
数字格式模式语法
可以按照以下BNF(巴科斯范式)图表指定的规则为数字设计自己的格式模式:
pattern: subpattern {; subpattern} subpattern(子模式): {prefix} integer {.fraction(分数)} {suffix}
prefix(前缀):‘\ u0000‘..‘\ uFFFD‘ - specialCharacters suffix(后缀):‘\ u0000‘..‘\ uFFFD‘ - specialCharacters integer:‘#‘*‘0‘*‘0‘ 分数: ‘0‘*‘#‘*
上图中使用的符号如下表所示:
符号 | 描述 |
---|---|
X* |
0个或更多个X实例 |
(X | Y) |
X或Y |
X..Y |
从X到Y的任何字符,包括在内 |
S - T |
S中的字符,除了T中的字符 |
{X} |
X是可选的 |
模式中的特殊符号:
符号 | 描述 |
0 | 一个数字 |
# | 一个数字,0显示为缺省(即空字符) |
. | 小数点 |
, | 分组分隔符 |
E | 指数表示的底数指数分隔符 |
; | 分隔格式 |
- | 负号前缀 |
% | 乘以100并显示为百分比 |
? | 乘以1000并显示为千分比 |
¤ | 货币符号; 用货币符号代替; 如果加倍,用国际货币符号代替; 如果存在于模式中,则使用货币小数分隔符而不是小数分隔符 |
X | 任何其他字符都可以在前缀或者后缀中使用 |
“ | 用于引号前缀或后缀中的特殊符号 |
示例:
value | pattern | output | 说明 |
---|---|---|---|
123456.789 | ###,###。### | 123,456.789 | 井号(#)表示一个数字,逗号是分组分隔符的占位符,句点是小数分隔符的占位符。 |
123456.789 | ###。## | 123456.79 | 将value 有三个数字的小数点右边,但pattern 只有两个。该format 方法通过四舍五入来处理这个问题。 |
123.78 | 000000.000 | 000123.780 | 的pattern 指定前导和尾随零,因为0字符被用来代替井号(#)。 |
12345.67 | $ ###,###。### | $ 12,345.67 | pattern 美元符号($)中的第一个字符。请注意,它紧接在格式化的最左边的数字之前output 。 |
12345.67 | u00A5 ###,###。### | ¥12,345.67 | 在pattern 与Unicode值00A5指定为日元(¥)货币符号。 |
1 DecimalFormat df = new DecimalFormat("000.###"); 2 String s = df.format( 1.11111); 3 System.out.println(s); 4 //output: 001.111 5 6 df.applyPattern("000.000"); //重新应用新的模式 7 System.out.println(df.format(1.11111)); 8 //output: 001.111 9 10 df.applyPattern("000E000"); 11 System.out.println(df.format(1111111)); 12 //output: 111E004 (1111111 约等于111 X 10^4) 13 df.applyPattern("0E0"); 14 System.out.println(df.format(1000000000)); 15 //output: 1E9 16 17 df.applyPattern("###,###,###.###"); 18 System.out.println(df.format(11111111.11)); 19 //output:11,111,111.11 20 21 df.applyPattern("0.0%"); 22 System.out.println(df.format(0.1)); 23 //output: 10.0% 24 25 df.applyPattern("sd.00"); //可添加其他常规字符 26 System.out.println(df.format(0.1)); 27 //output: sd.10
区域敏感格式
前面的示例DecimalFormat
为默认值创建了一个对象Locale
。如果您想要一个DecimalFormat
非默认对象Locale
,则实例化a NumberFormat
然后将其强制转换为DecimalFormat
。这是一个例子:
NumberFormat nf = NumberFormat.getNumberInstance(loc); DecimalFormat df =(DecimalFormat)nf; df.applyPattern(图案); String output = df.format(value); System.out.println(pattern +“”+ output +“”+ loc.toString());
运行上一个代码示例将导致后面的输出。格式化的数字位于第二列,具体取决于Locale
:
###,###。### 123,456.789 zh_CN ###,###。### 123.456,789 de_DE ###,###。### 123 456,789 fr_FR
到目前为止,这里讨论的格式模式遵循美国英语的惯例。例如,在模式###,###。##中,逗号是千位分隔符,句点表示小数点。如果您的最终用户没有接触到它,那么这个约定很好。但是,某些应用程序(如电子表格和报表生成器)允许最终用户定义自己的格式设置模式。对于这些应用程序,最终用户指定的格式模式应使用本地化表示法。在这些情况下,您将要调用applyLocalizedPattern
该DecimalFormat
对象上的方法。
改变格式符号
您可以使用 DecimalFormatSymbols类更改format
方法生成的格式化数字中出现的符号。这些符号包括小数分隔符,分组分隔符,减号和百分号等。
下一个示例DecimalFormatSymbols
通过将奇怪的格式应用于数字来演示该类。这种不寻常的格式是调用的结果setDecimalSeparator
,setGroupingSeparator
和setGroupingSize
方法。
DecimalFormatSymbols unusualSymbols = new DecimalFormatSymbols(currentLocale); unusualSymbols.setDecimalSeparator( ‘|‘); unusualSymbols.setGroupingSeparator( ‘^‘); String strange =“#,## 0。###”; DecimalFormat weirdFormatter = new DecimalFormat(strange,unusualSymbols); weirdFormatter.setGroupingSize(4); String bizarre = weirdFormatter.format(12345.678); 的System.out.println(奇异);
运行时,此示例以奇怪的格式打印数字:
1 ^ 2345 | 678
date:
2018-10-31 12:57:51
参考:
https://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html#numberpattern
附DecimalFormat类源码:
1 /* 2 * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. 3 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 4 */ 5 6 /* 7 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved 8 * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved 9 * 10 * The original version of this source code and documentation is copyrighted 11 * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These 12 * materials are provided under terms of a License Agreement between Taligent 13 * and Sun. This technology is protected by multiple US and International 14 * patents. This notice and attribution to Taligent may not be removed. 15 * Taligent is a registered trademark of Taligent, Inc. 16 * 17 */ 18 19 package java.text; 20 21 import java.io.IOException; 22 import java.io.InvalidObjectException; 23 import java.io.ObjectInputStream; 24 import java.math.BigDecimal; 25 import java.math.BigInteger; 26 import java.math.RoundingMode; 27 import java.text.spi.NumberFormatProvider; 28 import java.util.ArrayList; 29 import java.util.Currency; 30 import java.util.Locale; 31 import java.util.ResourceBundle; 32 import java.util.concurrent.ConcurrentHashMap; 33 import java.util.concurrent.ConcurrentMap; 34 import java.util.concurrent.atomic.AtomicInteger; 35 import java.util.concurrent.atomic.AtomicLong; 36 import sun.util.locale.provider.LocaleProviderAdapter; 37 import sun.util.locale.provider.ResourceBundleBasedAdapter; 38 39 /** 40 * <code>DecimalFormat</code> is a concrete subclass of 41 * <code>NumberFormat</code> that formats decimal numbers. It has a variety of 42 * features designed to make it possible to parse and format numbers in any 43 * locale, including support for Western, Arabic, and Indic digits. It also 44 * supports different kinds of numbers, including integers (123), fixed-point 45 * numbers (123.4), scientific notation (1.23E4), percentages (12%), and 46 * currency amounts ($123). All of these can be localized. 47 * 48 * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the 49 * default locale, call one of <code>NumberFormat</code>‘s factory methods, such 50 * as <code>getInstance()</code>. In general, do not call the 51 * <code>DecimalFormat</code> constructors directly, since the 52 * <code>NumberFormat</code> factory methods may return subclasses other than 53 * <code>DecimalFormat</code>. If you need to customize the format object, do 54 * something like this: 55 * 56 * <blockquote><pre> 57 * NumberFormat f = NumberFormat.getInstance(loc); 58 * if (f instanceof DecimalFormat) { 59 * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true); 60 * } 61 * </pre></blockquote> 62 * 63 * <p>A <code>DecimalFormat</code> comprises a <em>pattern</em> and a set of 64 * <em>symbols</em>. The pattern may be set directly using 65 * <code>applyPattern()</code>, or indirectly using the API methods. The 66 * symbols are stored in a <code>DecimalFormatSymbols</code> object. When using 67 * the <code>NumberFormat</code> factory methods, the pattern and symbols are 68 * read from localized <code>ResourceBundle</code>s. 69 * 70 * <h3>Patterns</h3> 71 * 72 * <code>DecimalFormat</code> patterns have the following syntax: 73 * <blockquote><pre> 74 * <i>Pattern:</i> 75 * <i>PositivePattern</i> 76 * <i>PositivePattern</i> ; <i>NegativePattern</i> 77 * <i>PositivePattern:</i> 78 * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i> 79 * <i>NegativePattern:</i> 80 * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i> 81 * <i>Prefix:</i> 82 * any Unicode characters except \uFFFE, \uFFFF, and special characters 83 * <i>Suffix:</i> 84 * any Unicode characters except \uFFFE, \uFFFF, and special characters 85 * <i>Number:</i> 86 * <i>Integer</i> <i>Exponent<sub>opt</sub></i> 87 * <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i> 88 * <i>Integer:</i> 89 * <i>MinimumInteger</i> 90 * # 91 * # <i>Integer</i> 92 * # , <i>Integer</i> 93 * <i>MinimumInteger:</i> 94 * 0 95 * 0 <i>MinimumInteger</i> 96 * 0 , <i>MinimumInteger</i> 97 * <i>Fraction:</i> 98 * <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i> 99 * <i>MinimumFraction:</i> 100 * 0 <i>MinimumFraction<sub>opt</sub></i> 101 * <i>OptionalFraction:</i> 102 * # <i>OptionalFraction<sub>opt</sub></i> 103 * <i>Exponent:</i> 104 * E <i>MinimumExponent</i> 105 * <i>MinimumExponent:</i> 106 * 0 <i>MinimumExponent<sub>opt</sub></i> 107 * </pre></blockquote> 108 * 109 * <p>A <code>DecimalFormat</code> pattern contains a positive and negative 110 * subpattern, for example, <code>"#,##0.00;(#,##0.00)"</code>. Each 111 * subpattern has a prefix, numeric part, and suffix. The negative subpattern 112 * is optional; if absent, then the positive subpattern prefixed with the 113 * localized minus sign (<code>‘-‘</code> in most locales) is used as the 114 * negative subpattern. That is, <code>"0.00"</code> alone is equivalent to 115 * <code>"0.00;-0.00"</code>. If there is an explicit negative subpattern, it 116 * serves only to specify the negative prefix and suffix; the number of digits, 117 * minimal digits, and other characteristics are all the same as the positive 118 * pattern. That means that <code>"#,##0.0#;(#)"</code> produces precisely 119 * the same behavior as <code>"#,##0.0#;(#,##0.0#)"</code>. 120 * 121 * <p>The prefixes, suffixes, and various symbols used for infinity, digits, 122 * thousands separators, decimal separators, etc. may be set to arbitrary 123 * values, and they will appear properly during formatting. However, care must 124 * be taken that the symbols and strings do not conflict, or parsing will be 125 * unreliable. For example, either the positive and negative prefixes or the 126 * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able 127 * to distinguish positive from negative values. (If they are identical, then 128 * <code>DecimalFormat</code> will behave as if no negative subpattern was 129 * specified.) Another example is that the decimal separator and thousands 130 * separator should be distinct characters, or parsing will be impossible. 131 * 132 * <p>The grouping separator is commonly used for thousands, but in some 133 * countries it separates ten-thousands. The grouping size is a constant number 134 * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for 135 * 1,0000,0000. If you supply a pattern with multiple grouping characters, the 136 * interval between the last one and the end of the integer is the one that is 137 * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> == 138 * <code>"##,####,####"</code>. 139 * 140 * <h4>Special Pattern Characters</h4> 141 * 142 * <p>Many characters in a pattern are taken literally; they are matched during 143 * parsing and output unchanged during formatting. Special characters, on the 144 * other hand, stand for other characters, strings, or classes of characters. 145 * They must be quoted, unless noted otherwise, if they are to appear in the 146 * prefix or suffix as literals. 147 * 148 * <p>The characters listed here are used in non-localized patterns. Localized 149 * patterns use the corresponding characters taken from this formatter‘s 150 * <code>DecimalFormatSymbols</code> object instead, and these characters lose 151 * their special status. Two exceptions are the currency sign and quote, which 152 * are not localized. 153 * 154 * <blockquote> 155 * <table class="striped"> 156 * <caption style="display:none">Chart showing symbol, location, localized, and meaning.</caption> 157 * <thead> 158 * <tr> 159 * <th style="text-align:left">Symbol 160 * <th style="text-align:left">Location 161 * <th style="text-align:left">Localized? 162 * <th style="text-align:left">Meaning 163 * </thead> 164 * <tbody> 165 * <tr style="vertical-align:top"> 166 * <td><code>0</code> 167 * <td>Number 168 * <td>Yes 169 * <td>Digit 170 * <tr style="vertical-align: top"> 171 * <td><code>#</code> 172 * <td>Number 173 * <td>Yes 174 * <td>Digit, zero shows as absent 175 * <tr style="vertical-align:top"> 176 * <td><code>.</code> 177 * <td>Number 178 * <td>Yes 179 * <td>Decimal separator or monetary decimal separator 180 * <tr style="vertical-align: top"> 181 * <td><code>-</code> 182 * <td>Number 183 * <td>Yes 184 * <td>Minus sign 185 * <tr style="vertical-align:top"> 186 * <td><code>,</code> 187 * <td>Number 188 * <td>Yes 189 * <td>Grouping separator 190 * <tr style="vertical-align: top"> 191 * <td><code>E</code> 192 * <td>Number 193 * <td>Yes 194 * <td>Separates mantissa and exponent in scientific notation. 195 * <em>Need not be quoted in prefix or suffix.</em> 196 * <tr style="vertical-align:top"> 197 * <td><code>;</code> 198 * <td>Subpattern boundary 199 * <td>Yes 200 * <td>Separates positive and negative subpatterns 201 * <tr style="vertical-align: top"> 202 * <td><code>%</code> 203 * <td>Prefix or suffix 204 * <td>Yes 205 * <td>Multiply by 100 and show as percentage 206 * <tr style="vertical-align:top"> 207 * <td><code>\u2030</code> 208 * <td>Prefix or suffix 209 * <td>Yes 210 * <td>Multiply by 1000 and show as per mille value 211 * <tr style="vertical-align: top"> 212 * <td><code>¤</code> (<code>\u00A4</code>) 213 * <td>Prefix or suffix 214 * <td>No 215 * <td>Currency sign, replaced by currency symbol. If 216 * doubled, replaced by international currency symbol. 217 * If present in a pattern, the monetary decimal separator 218 * is used instead of the decimal separator. 219 * <tr style="vertical-align:top"> 220 * <td><code>‘</code> 221 * <td>Prefix or suffix 222 * <td>No 223 * <td>Used to quote special characters in a prefix or suffix, 224 * for example, <code>"‘#‘#"</code> formats 123 to 225 * <code>"#123"</code>. To create a single quote 226 * itself, use two in a row: <code>"# o‘‘clock"</code>. 227 * </tbody> 228 * </table> 229 * </blockquote> 230 * 231 * <h4>Scientific Notation</h4> 232 * 233 * <p>Numbers in scientific notation are expressed as the product of a mantissa 234 * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3. The 235 * mantissa is often in the range 1.0 ≤ x {@literal <} 10.0, but it need not 236 * be. 237 * <code>DecimalFormat</code> can be instructed to format and parse scientific 238 * notation <em>only via a pattern</em>; there is currently no factory method 239 * that creates a scientific notation format. In a pattern, the exponent 240 * character immediately followed by one or more digit characters indicates 241 * scientific notation. Example: <code>"0.###E0"</code> formats the number 242 * 1234 as <code>"1.234E3"</code>. 243 * 244 * <ul> 245 * <li>The number of digit characters after the exponent character gives the 246 * minimum exponent digit count. There is no maximum. Negative exponents are 247 * formatted using the localized minus sign, <em>not</em> the prefix and suffix 248 * from the pattern. This allows patterns such as <code>"0.###E0 m/s"</code>. 249 * 250 * <li>The minimum and maximum number of integer digits are interpreted 251 * together: 252 * 253 * <ul> 254 * <li>If the maximum number of integer digits is greater than their minimum number 255 * and greater than 1, it forces the exponent to be a multiple of the maximum 256 * number of integer digits, and the minimum number of integer digits to be 257 * interpreted as 1. The most common use of this is to generate 258 * <em>engineering notation</em>, in which the exponent is a multiple of three, 259 * e.g., <code>"##0.#####E0"</code>. Using this pattern, the number 12345 260 * formats to <code>"12.345E3"</code>, and 123456 formats to 261 * <code>"123.456E3"</code>. 262 * 263 * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the 264 * exponent. Example: 0.00123 formatted with <code>"00.###E0"</code> yields 265 * <code>"12.3E-4"</code>. 266 * </ul> 267 * 268 * <li>The number of significant digits in the mantissa is the sum of the 269 * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is 270 * unaffected by the maximum integer digits. For example, 12345 formatted with 271 * <code>"##0.##E0"</code> is <code>"12.3E3"</code>. To show all digits, set 272 * the significant digits count to zero. The number of significant digits 273 * does not affect parsing. 274 * 275 * <li>Exponential patterns may not contain grouping separators. 276 * </ul> 277 * 278 * <h4>Rounding</h4> 279 * 280 * <code>DecimalFormat</code> provides rounding modes defined in 281 * {@link java.math.RoundingMode} for formatting. By default, it uses 282 * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}. 283 * 284 * <h4>Digits</h4> 285 * 286 * For formatting, <code>DecimalFormat</code> uses the ten consecutive 287 * characters starting with the localized zero digit defined in the 288 * <code>DecimalFormatSymbols</code> object as digits. For parsing, these 289 * digits as well as all Unicode decimal digits, as defined by 290 * {@link Character#digit Character.digit}, are recognized. 291 * 292 * <h4>Special Values</h4> 293 * 294 * <p><code>NaN</code> is formatted as a string, which typically has a single character 295 * <code>\uFFFD</code>. This string is determined by the 296 * <code>DecimalFormatSymbols</code> object. This is the only value for which 297 * the prefixes and suffixes are not used. 298 * 299 * <p>Infinity is formatted as a string, which typically has a single character 300 * <code>\u221E</code>, with the positive or negative prefixes and suffixes 301 * applied. The infinity string is determined by the 302 * <code>DecimalFormatSymbols</code> object. 303 * 304 * <p>Negative zero (<code>"-0"</code>) parses to 305 * <ul> 306 * <li><code>BigDecimal(0)</code> if <code>isParseBigDecimal()</code> is 307 * true, 308 * <li><code>Long(0)</code> if <code>isParseBigDecimal()</code> is false 309 * and <code>isParseIntegerOnly()</code> is true, 310 * <li><code>Double(-0.0)</code> if both <code>isParseBigDecimal()</code> 311 * and <code>isParseIntegerOnly()</code> are false. 312 * </ul> 313 * 314 * <h4><a id="synchronization">Synchronization</a></h4> 315 * 316 * <p> 317 * Decimal formats are generally not synchronized. 318 * It is recommended to create separate format instances for each thread. 319 * If multiple threads access a format concurrently, it must be synchronized 320 * externally. 321 * 322 * <h4>Example</h4> 323 * 324 * <blockquote><pre>{@code 325 * <strong>// Print out a number using the localized number, integer, currency, 326 * // and percent format for each locale</strong> 327 * Locale[] locales = NumberFormat.getAvailableLocales(); 328 * double myNumber = -1234.56; 329 * NumberFormat form; 330 * for (int j = 0; j < 4; ++j) { 331 * System.out.println("FORMAT"); 332 * for (int i = 0; i < locales.length; ++i) { 333 * if (locales[i].getCountry().length() == 0) { 334 * continue; // Skip language-only locales 335 * } 336 * System.out.print(locales[i].getDisplayName()); 337 * switch (j) { 338 * case 0: 339 * form = NumberFormat.getInstance(locales[i]); break; 340 * case 1: 341 * form = NumberFormat.getIntegerInstance(locales[i]); break; 342 * case 2: 343 * form = NumberFormat.getCurrencyInstance(locales[i]); break; 344 * default: 345 * form = NumberFormat.getPercentInstance(locales[i]); break; 346 * } 347 * if (form instanceof DecimalFormat) { 348 * System.out.print(": " + ((DecimalFormat) form).toPattern()); 349 * } 350 * System.out.print(" -> " + form.format(myNumber)); 351 * try { 352 * System.out.println(" -> " + form.parse(form.format(myNumber))); 353 * } catch (ParseException e) {} 354 * } 355 * } 356 * }</pre></blockquote> 357 * 358 * @see <a href="http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a> 359 * @see NumberFormat 360 * @see DecimalFormatSymbols 361 * @see ParsePosition 362 * @author Mark Davis 363 * @author Alan Liu 364 * @since 1.1 365 */ 366 public class DecimalFormat extends NumberFormat { 367 368 /** 369 * Creates a DecimalFormat using the default pattern and symbols 370 * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. 371 * This is a convenient way to obtain a 372 * DecimalFormat when internationalization is not the main concern. 373 * <p> 374 * To obtain standard formats for a given locale, use the factory methods 375 * on NumberFormat such as getNumberInstance. These factories will 376 * return the most appropriate sub-class of NumberFormat for a given 377 * locale. 378 * 379 * @see java.text.NumberFormat#getInstance 380 * @see java.text.NumberFormat#getNumberInstance 381 * @see java.text.NumberFormat#getCurrencyInstance 382 * @see java.text.NumberFormat#getPercentInstance 383 */ 384 public DecimalFormat() { 385 // Get the pattern for the default locale. 386 Locale def = Locale.getDefault(Locale.Category.FORMAT); 387 LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(NumberFormatProvider.class, def); 388 if (!(adapter instanceof ResourceBundleBasedAdapter)) { 389 adapter = LocaleProviderAdapter.getResourceBundleBased(); 390 } 391 String[] all = adapter.getLocaleResources(def).getNumberPatterns(); 392 393 // Always applyPattern after the symbols are set 394 this.symbols = DecimalFormatSymbols.getInstance(def); 395 applyPattern(all[0], false); 396 } 397 398 399 /** 400 * Creates a DecimalFormat using the given pattern and the symbols 401 * for the default {@link java.util.Locale.Category#FORMAT FORMAT} locale. 402 * This is a convenient way to obtain a 403 * DecimalFormat when internationalization is not the main concern. 404 * <p> 405 * To obtain standard formats for a given locale, use the factory methods 406 * on NumberFormat such as getNumberInstance. These factories will 407 * return the most appropriate sub-class of NumberFormat for a given 408 * locale. 409 * 410 * @param pattern a non-localized pattern string. 411 * @exception NullPointerException if <code>pattern</code> is null 412 * @exception IllegalArgumentException if the given pattern is invalid. 413 * @see java.text.NumberFormat#getInstance 414 * @see java.text.NumberFormat#getNumberInstance 415 * @see java.text.NumberFormat#getCurrencyInstance 416 * @see java.text.NumberFormat#getPercentInstance 417 */ 418 public DecimalFormat(String pattern) { 419 // Always applyPattern after the symbols are set 420 this.symbols = DecimalFormatSymbols.getInstance(Locale.getDefault(Locale.Category.FORMAT)); 421 applyPattern(pattern, false); 422 } 423 424 425 /** 426 * Creates a DecimalFormat using the given pattern and symbols. 427 * Use this constructor when you need to completely customize the 428 * behavior of the format. 429 * <p> 430 * To obtain standard formats for a given 431 * locale, use the factory methods on NumberFormat such as 432 * getInstance or getCurrencyInstance. If you need only minor adjustments 433 * to a standard format, you can modify the format returned by 434 * a NumberFormat factory method. 435 * 436 * @param pattern a non-localized pattern string 437 * @param symbols the set of symbols to be used 438 * @exception NullPointerException if any of the given arguments is null 439 * @exception IllegalArgumentException if the given pattern is invalid 440 * @see java.text.NumberFormat#getInstance 441 * @see java.text.NumberFormat#getNumberInstance 442 * @see java.text.NumberFormat#getCurrencyInstance 443 * @see java.text.NumberFormat#getPercentInstance 444 * @see java.text.DecimalFormatSymbols 445 */ 446 public DecimalFormat (String pattern, DecimalFormatSymbols symbols) { 447 // Always applyPattern after the symbols are set 448 this.symbols = (DecimalFormatSymbols)symbols.clone(); 449 applyPattern(pattern, false); 450 } 451 452 453 // Overrides 454 /** 455 * Formats a number and appends the resulting text to the given string 456 * buffer. 457 * The number can be of any subclass of {@link java.lang.Number}. 458 * <p> 459 * This implementation uses the maximum precision permitted. 460 * @param number the number to format 461 * @param toAppendTo the <code>StringBuffer</code> to which the formatted 462 * text is to be appended 463 * @param pos On input: an alignment field, if desired. 464 * On output: the offsets of the alignment field. 465 * @return the value passed in as <code>toAppendTo</code> 466 * @exception IllegalArgumentException if <code>number</code> is 467 * null or not an instance of <code>Number</code>. 468 * @exception NullPointerException if <code>toAppendTo</code> or 469 * <code>pos</code> is null 470 * @exception ArithmeticException if rounding is needed with rounding 471 * mode being set to RoundingMode.UNNECESSARY 472 * @see java.text.FieldPosition 473 */ 474 @Override 475 public final StringBuffer format(Object number, 476 StringBuffer toAppendTo, 477 FieldPosition pos) { 478 if (number instanceof Long || number instanceof Integer || 479 number instanceof Short || number instanceof Byte || 480 number instanceof AtomicInteger || 481 number instanceof AtomicLong || 482 (number instanceof BigInteger && 483 ((BigInteger)number).bitLength () < 64)) { 484 return format(((Number)number).longValue(), toAppendTo, pos); 485 } else if (number instanceof BigDecimal) { 486 return format((BigDecimal)number, toAppendTo, pos); 487 } else if (number instanceof BigInteger) { 488 return format((BigInteger)number, toAppendTo, pos); 489 } else if (number instanceof Number) { 490 return format(((Number)number).doubleValue(), toAppendTo, pos); 491 } else { 492 throw new IllegalArgumentException("Cannot format given Object as a Number"); 493 } 494 } 495 496 /** 497 * Formats a double to produce a string. 498 * @param number The double to format 499 * @param result where the text is to be appended 500 * @param fieldPosition On input: an alignment field, if desired. 501 * On output: the offsets of the alignment field. 502 * @exception NullPointerException if {@code result} or 503 * {@code fieldPosition} is {@code null} 504 * @exception ArithmeticException if rounding is needed with rounding 505 * mode being set to RoundingMode.UNNECESSARY 506 * @return The formatted number string 507 * @see java.text.FieldPosition 508 */ 509 @Override 510 public StringBuffer format(double number, StringBuffer result, 511 FieldPosition fieldPosition) { 512 // If fieldPosition is a DontCareFieldPosition instance we can 513 // try to go to fast-path code. 514 boolean tryFastPath = false; 515 if (fieldPosition == DontCareFieldPosition.INSTANCE) 516 tryFastPath = true; 517 else { 518 fieldPosition.setBeginIndex(0); 519 fieldPosition.setEndIndex(0); 520 } 521 522 if (tryFastPath) { 523 String tempResult = fastFormat(number); 524 if (tempResult != null) { 525 result.append(tempResult); 526 return result; 527 } 528 } 529 530 // if fast-path could not work, we fallback to standard code. 531 return format(number, result, fieldPosition.getFieldDelegate()); 532 } 533 534 /** 535 * Formats a double to produce a string. 536 * @param number The double to format 537 * @param result where the text is to be appended 538 * @param delegate notified of locations of sub fields 539 * @exception ArithmeticException if rounding is needed with rounding 540 * mode being set to RoundingMode.UNNECESSARY 541 * @return The formatted number string 542 */ 543 private StringBuffer format(double number, StringBuffer result, 544 FieldDelegate delegate) { 545 if (Double.isNaN(number) || 546 (Double.isInfinite(number) && multiplier == 0)) { 547 int iFieldStart = result.length(); 548 result.append(symbols.getNaN()); 549 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, 550 iFieldStart, result.length(), result); 551 return result; 552 } 553 554 /* Detecting whether a double is negative is easy with the exception of 555 * the value -0.0. This is a double which has a zero mantissa (and 556 * exponent), but a negative sign bit. It is semantically distinct from 557 * a zero with a positive sign bit, and this distinction is important 558 * to certain kinds of computations. However, it‘s a little tricky to 559 * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may 560 * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) == 561 * -Infinity. Proper detection of -0.0 is needed to deal with the 562 * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98. 563 */ 564 boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0); 565 566 if (multiplier != 1) { 567 number *= multiplier; 568 } 569 570 if (Double.isInfinite(number)) { 571 if (isNegative) { 572 append(result, negativePrefix, delegate, 573 getNegativePrefixFieldPositions(), Field.SIGN); 574 } else { 575 append(result, positivePrefix, delegate, 576 getPositivePrefixFieldPositions(), Field.SIGN); 577 } 578 579 int iFieldStart = result.length(); 580 result.append(symbols.getInfinity()); 581 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, 582 iFieldStart, result.length(), result); 583 584 if (isNegative) { 585 append(result, negativeSuffix, delegate, 586 getNegativeSuffixFieldPositions(), Field.SIGN); 587 } else { 588 append(result, positiveSuffix, delegate, 589 getPositiveSuffixFieldPositions(), Field.SIGN); 590 } 591 592 return result; 593 } 594 595 if (isNegative) { 596 number = -number; 597 } 598 599 // at this point we are guaranteed a nonnegative finite number. 600 assert(number >= 0 && !Double.isInfinite(number)); 601 602 synchronized(digitList) { 603 int maxIntDigits = super.getMaximumIntegerDigits(); 604 int minIntDigits = super.getMinimumIntegerDigits(); 605 int maxFraDigits = super.getMaximumFractionDigits(); 606 int minFraDigits = super.getMinimumFractionDigits(); 607 608 digitList.set(isNegative, number, useExponentialNotation ? 609 maxIntDigits + maxFraDigits : maxFraDigits, 610 !useExponentialNotation); 611 return subformat(result, delegate, isNegative, false, 612 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); 613 } 614 } 615 616 /** 617 * Format a long to produce a string. 618 * @param number The long to format 619 * @param result where the text is to be appended 620 * @param fieldPosition On input: an alignment field, if desired. 621 * On output: the offsets of the alignment field. 622 * @exception NullPointerException if {@code result} or 623 * {@code fieldPosition} is {@code null} 624 * @exception ArithmeticException if rounding is needed with rounding 625 * mode being set to RoundingMode.UNNECESSARY 626 * @return The formatted number string 627 * @see java.text.FieldPosition 628 */ 629 @Override 630 public StringBuffer format(long number, StringBuffer result, 631 FieldPosition fieldPosition) { 632 fieldPosition.setBeginIndex(0); 633 fieldPosition.setEndIndex(0); 634 635 return format(number, result, fieldPosition.getFieldDelegate()); 636 } 637 638 /** 639 * Format a long to produce a string. 640 * @param number The long to format 641 * @param result where the text is to be appended 642 * @param delegate notified of locations of sub fields 643 * @return The formatted number string 644 * @exception ArithmeticException if rounding is needed with rounding 645 * mode being set to RoundingMode.UNNECESSARY 646 * @see java.text.FieldPosition 647 */ 648 private StringBuffer format(long number, StringBuffer result, 649 FieldDelegate delegate) { 650 boolean isNegative = (number < 0); 651 if (isNegative) { 652 number = -number; 653 } 654 655 // In general, long values always represent real finite numbers, so 656 // we don‘t have to check for +/- Infinity or NaN. However, there 657 // is one case we have to be careful of: The multiplier can push 658 // a number near MIN_VALUE or MAX_VALUE outside the legal range. We 659 // check for this before multiplying, and if it happens we use 660 // BigInteger instead. 661 boolean useBigInteger = false; 662 if (number < 0) { // This can only happen if number == Long.MIN_VALUE. 663 if (multiplier != 0) { 664 useBigInteger = true; 665 } 666 } else if (multiplier != 1 && multiplier != 0) { 667 long cutoff = Long.MAX_VALUE / multiplier; 668 if (cutoff < 0) { 669 cutoff = -cutoff; 670 } 671 useBigInteger = (number > cutoff); 672 } 673 674 if (useBigInteger) { 675 if (isNegative) { 676 number = -number; 677 } 678 BigInteger bigIntegerValue = BigInteger.valueOf(number); 679 return format(bigIntegerValue, result, delegate, true); 680 } 681 682 number *= multiplier; 683 if (number == 0) { 684 isNegative = false; 685 } else { 686 if (multiplier < 0) { 687 number = -number; 688 isNegative = !isNegative; 689 } 690 } 691 692 synchronized(digitList) { 693 int maxIntDigits = super.getMaximumIntegerDigits(); 694 int minIntDigits = super.getMinimumIntegerDigits(); 695 int maxFraDigits = super.getMaximumFractionDigits(); 696 int minFraDigits = super.getMinimumFractionDigits(); 697 698 digitList.set(isNegative, number, 699 useExponentialNotation ? maxIntDigits + maxFraDigits : 0); 700 701 return subformat(result, delegate, isNegative, true, 702 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); 703 } 704 } 705 706 /** 707 * Formats a BigDecimal to produce a string. 708 * @param number The BigDecimal to format 709 * @param result where the text is to be appended 710 * @param fieldPosition On input: an alignment field, if desired. 711 * On output: the offsets of the alignment field. 712 * @return The formatted number string 713 * @exception ArithmeticException if rounding is needed with rounding 714 * mode being set to RoundingMode.UNNECESSARY 715 * @see java.text.FieldPosition 716 */ 717 private StringBuffer format(BigDecimal number, StringBuffer result, 718 FieldPosition fieldPosition) { 719 fieldPosition.setBeginIndex(0); 720 fieldPosition.setEndIndex(0); 721 return format(number, result, fieldPosition.getFieldDelegate()); 722 } 723 724 /** 725 * Formats a BigDecimal to produce a string. 726 * @param number The BigDecimal to format 727 * @param result where the text is to be appended 728 * @param delegate notified of locations of sub fields 729 * @exception ArithmeticException if rounding is needed with rounding 730 * mode being set to RoundingMode.UNNECESSARY 731 * @return The formatted number string 732 */ 733 private StringBuffer format(BigDecimal number, StringBuffer result, 734 FieldDelegate delegate) { 735 if (multiplier != 1) { 736 number = number.multiply(getBigDecimalMultiplier()); 737 } 738 boolean isNegative = number.signum() == -1; 739 if (isNegative) { 740 number = number.negate(); 741 } 742 743 synchronized(digitList) { 744 int maxIntDigits = getMaximumIntegerDigits(); 745 int minIntDigits = getMinimumIntegerDigits(); 746 int maxFraDigits = getMaximumFractionDigits(); 747 int minFraDigits = getMinimumFractionDigits(); 748 int maximumDigits = maxIntDigits + maxFraDigits; 749 750 digitList.set(isNegative, number, useExponentialNotation ? 751 ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) : 752 maxFraDigits, !useExponentialNotation); 753 754 return subformat(result, delegate, isNegative, false, 755 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); 756 } 757 } 758 759 /** 760 * Format a BigInteger to produce a string. 761 * @param number The BigInteger to format 762 * @param result where the text is to be appended 763 * @param fieldPosition On input: an alignment field, if desired. 764 * On output: the offsets of the alignment field. 765 * @return The formatted number string 766 * @exception ArithmeticException if rounding is needed with rounding 767 * mode being set to RoundingMode.UNNECESSARY 768 * @see java.text.FieldPosition 769 */ 770 private StringBuffer format(BigInteger number, StringBuffer result, 771 FieldPosition fieldPosition) { 772 fieldPosition.setBeginIndex(0); 773 fieldPosition.setEndIndex(0); 774 775 return format(number, result, fieldPosition.getFieldDelegate(), false); 776 } 777 778 /** 779 * Format a BigInteger to produce a string. 780 * @param number The BigInteger to format 781 * @param result where the text is to be appended 782 * @param delegate notified of locations of sub fields 783 * @return The formatted number string 784 * @exception ArithmeticException if rounding is needed with rounding 785 * mode being set to RoundingMode.UNNECESSARY 786 * @see java.text.FieldPosition 787 */ 788 private StringBuffer format(BigInteger number, StringBuffer result, 789 FieldDelegate delegate, boolean formatLong) { 790 if (multiplier != 1) { 791 number = number.multiply(getBigIntegerMultiplier()); 792 } 793 boolean isNegative = number.signum() == -1; 794 if (isNegative) { 795 number = number.negate(); 796 } 797 798 synchronized(digitList) { 799 int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits; 800 if (formatLong) { 801 maxIntDigits = super.getMaximumIntegerDigits(); 802 minIntDigits = super.getMinimumIntegerDigits(); 803 maxFraDigits = super.getMaximumFractionDigits(); 804 minFraDigits = super.getMinimumFractionDigits(); 805 maximumDigits = maxIntDigits + maxFraDigits; 806 } else { 807 maxIntDigits = getMaximumIntegerDigits(); 808 minIntDigits = getMinimumIntegerDigits(); 809 maxFraDigits = getMaximumFractionDigits(); 810 minFraDigits = getMinimumFractionDigits(); 811 maximumDigits = maxIntDigits + maxFraDigits; 812 if (maximumDigits < 0) { 813 maximumDigits = Integer.MAX_VALUE; 814 } 815 } 816 817 digitList.set(isNegative, number, 818 useExponentialNotation ? maximumDigits : 0); 819 820 return subformat(result, delegate, isNegative, true, 821 maxIntDigits, minIntDigits, maxFraDigits, minFraDigits); 822 } 823 } 824 825 /** 826 * Formats an Object producing an <code>AttributedCharacterIterator</code>. 827 * You can use the returned <code>AttributedCharacterIterator</code> 828 * to build the resulting String, as well as to determine information 829 * about the resulting String. 830 * <p> 831 * Each attribute key of the AttributedCharacterIterator will be of type 832 * <code>NumberFormat.Field</code>, with the attribute value being the 833 * same as the attribute key. 834 * 835 * @exception NullPointerException if obj is null. 836 * @exception IllegalArgumentException when the Format cannot format the 837 * given object. 838 * @exception ArithmeticException if rounding is needed with rounding 839 * mode being set to RoundingMode.UNNECESSARY 840 * @param obj The object to format 841 * @return AttributedCharacterIterator describing the formatted value. 842 * @since 1.4 843 */ 844 @Override 845 public AttributedCharacterIterator formatToCharacterIterator(Object obj) { 846 CharacterIteratorFieldDelegate delegate = 847 new CharacterIteratorFieldDelegate(); 848 StringBuffer sb = new StringBuffer(); 849 850 if (obj instanceof Double || obj instanceof Float) { 851 format(((Number)obj).doubleValue(), sb, delegate); 852 } else if (obj instanceof Long || obj instanceof Integer || 853 obj instanceof Short || obj instanceof Byte || 854 obj instanceof AtomicInteger || obj instanceof AtomicLong) { 855 format(((Number)obj).longValue(), sb, delegate); 856 } else if (obj instanceof BigDecimal) { 857 format((BigDecimal)obj, sb, delegate); 858 } else if (obj instanceof BigInteger) { 859 format((BigInteger)obj, sb, delegate, false); 860 } else if (obj == null) { 861 throw new NullPointerException( 862 "formatToCharacterIterator must be passed non-null object"); 863 } else { 864 throw new IllegalArgumentException( 865 "Cannot format given Object as a Number"); 866 } 867 return delegate.getIterator(sb.toString()); 868 } 869 870 // ==== Begin fast-path formating logic for double ========================= 871 872 /* Fast-path formatting will be used for format(double ...) methods iff a 873 * number of conditions are met (see checkAndSetFastPathStatus()): 874 * - Only if instance properties meet the right predefined conditions. 875 * - The abs value of the double to format is <= Integer.MAX_VALUE. 876 * 877 * The basic approach is to split the binary to decimal conversion of a 878 * double value into two phases: 879 * * The conversion of the integer portion of the double. 880 * * The conversion of the fractional portion of the double 881 * (limited to two or three digits). 882 * 883 * The isolation and conversion of the integer portion of the double is 884 * straightforward. The conversion of the fraction is more subtle and relies 885 * on some rounding properties of double to the decimal precisions in 886 * question. Using the terminology of BigDecimal, this fast-path algorithm 887 * is applied when a double value has a magnitude less than Integer.MAX_VALUE 888 * and rounding is to nearest even and the destination format has two or 889 * three digits of *scale* (digits after the decimal point). 890 * 891 * Under a rounding to nearest even policy, the returned result is a digit 892 * string of a number in the (in this case decimal) destination format 893 * closest to the exact numerical value of the (in this case binary) input 894 * value. If two destination format numbers are equally distant, the one 895 * with the last digit even is returned. To compute such a correctly rounded 896 * value, some information about digits beyond the smallest returned digit 897 * position needs to be consulted. 898 * 899 * In general, a guard digit, a round digit, and a sticky *bit* are needed 900 * beyond the returned digit position. If the discarded portion of the input 901 * is sufficiently large, the returned digit string is incremented. In round 902 * to nearest even, this threshold to increment occurs near the half-way 903 * point between digits. The sticky bit records if there are any remaining 904 * trailing digits of the exact input value in the new format; the sticky bit 905 * is consulted only in close to half-way rounding cases. 906 * 907 * Given the computation of the digit and bit values, rounding is then 908 * reduced to a table lookup problem. For decimal, the even/odd cases look 909 * like this: 910 * 911 * Last Round Sticky 912 * 6 5 0 => 6 // exactly halfway, return even digit. 913 * 6 5 1 => 7 // a little bit more than halfway, round up. 914 * 7 5 0 => 8 // exactly halfway, round up to even. 915 * 7 5 1 => 8 // a little bit more than halfway, round up. 916 * With analogous entries for other even and odd last-returned digits. 917 * 918 * However, decimal negative powers of 5 smaller than 0.5 are *not* exactly 919 * representable as binary fraction. In particular, 0.005 (the round limit 920 * for a two-digit scale) and 0.0005 (the round limit for a three-digit 921 * scale) are not representable. Therefore, for input values near these cases 922 * the sticky bit is known to be set which reduces the rounding logic to: 923 * 924 * Last Round Sticky 925 * 6 5 1 => 7 // a little bit more than halfway, round up. 926 * 7 5 1 => 8 // a little bit more than halfway, round up. 927 * 928 * In other words, if the round digit is 5, the sticky bit is known to be 929 * set. If the round digit is something other than 5, the sticky bit is not 930 * relevant. Therefore, some of the logic about whether or not to increment 931 * the destination *decimal* value can occur based on tests of *binary* 932 * computations of the binary input number. 933 */ 934 935 /** 936 * Check validity of using fast-path for this instance. If fast-path is valid 937 * for this instance, sets fast-path state as true and initializes fast-path 938 * utility fields as needed. 939 * 940 * This method is supposed to be called rarely, otherwise that will break the 941 * fast-path performance. That means avoiding frequent changes of the 942 * properties of the instance, since for most properties, each time a change 943 * happens, a call to this method is needed at the next format call. 944 * 945 * FAST-PATH RULES: 946 * Similar to the default DecimalFormat instantiation case. 947 * More precisely: 948 * - HALF_EVEN rounding mode, 949 * - isGroupingUsed() is true, 950 * - groupingSize of 3, 951 * - multiplier is 1, 952 * - Decimal separator not mandatory, 953 * - No use of exponential notation, 954 * - minimumIntegerDigits is exactly 1 and maximumIntegerDigits at least 10 955 * - For number of fractional digits, the exact values found in the default case: 956 * Currency : min = max = 2. 957 * Decimal : min = 0. max = 3. 958 * 959 */ 960 private boolean checkAndSetFastPathStatus() { 961 962 boolean fastPathWasOn = isFastPath; 963 964 if ((roundingMode == RoundingMode.HALF_EVEN) && 965 (isGroupingUsed()) && 966 (groupingSize == 3) && 967 (multiplier == 1) && 968 (!decimalSeparatorAlwaysShown) && 969 (!useExponentialNotation)) { 970 971 // The fast-path algorithm is semi-hardcoded against 972 // minimumIntegerDigits and maximumIntegerDigits. 973 isFastPath = ((minimumIntegerDigits == 1) && 974 (maximumIntegerDigits >= 10)); 975 976 // The fast-path algorithm is hardcoded against 977 // minimumFractionDigits and maximumFractionDigits. 978 if (isFastPath) { 979 if (isCurrencyFormat) { 980 if ((minimumFractionDigits != 2) || 981 (maximumFractionDigits != 2)) 982 isFastPath = false; 983 } else if ((minimumFractionDigits != 0) || 984 (maximumFractionDigits != 3)) 985 isFastPath = false; 986 } 987 } else 988 isFastPath = false; 989 990 resetFastPathData(fastPathWasOn); 991 fastPathCheckNeeded = false; 992 993 /* 994 * Returns true after successfully checking the fast path condition and 995 * setting the fast path data. The return value is used by the 996 * fastFormat() method to decide whether to call the resetFastPathData 997 * method to reinitialize fast path data or is it already initialized 998 * in this method. 999 */ 1000 return true; 1001 } 1002 1003 private void resetFastPathData(boolean fastPathWasOn) { 1004 // Since some instance properties may have changed while still falling 1005 // in the fast-path case, we need to reinitialize fastPathData anyway. 1006 if (isFastPath) { 1007 // We need to instantiate fastPathData if not already done. 1008 if (fastPathData == null) { 1009 fastPathData = new FastPathData(); 1010 } 1011 1012 // Sets up the locale specific constants used when formatting. 1013 // ‘0‘ is our default representation of zero. 1014 fastPathData.zeroDelta = symbols.getZeroDigit() - ‘0‘; 1015 fastPathData.groupingChar = symbols.getGroupingSeparator(); 1016 1017 // Sets up fractional constants related to currency/decimal pattern. 1018 fastPathData.fractionalMaxIntBound = (isCurrencyFormat) 1019 ? 99 : 999; 1020 fastPathData.fractionalScaleFactor = (isCurrencyFormat) 1021 ? 100.0d : 1000.0d; 1022 1023 // Records the need for adding prefix or suffix 1024 fastPathData.positiveAffixesRequired 1025 = (positivePrefix.length() != 0) 1026 || (positiveSuffix.length() != 0); 1027 fastPathData.negativeAffixesRequired 1028 = (negativePrefix.length() != 0) 1029 || (negativeSuffix.length() != 0); 1030 1031 // Creates a cached char container for result, with max possible size. 1032 int maxNbIntegralDigits = 10; 1033 int maxNbGroups = 3; 1034 int containerSize 1035 = Math.max(positivePrefix.length(), negativePrefix.length()) 1036 + maxNbIntegralDigits + maxNbGroups + 1 1037 + maximumFractionDigits 1038 + Math.max(positiveSuffix.length(), negativeSuffix.length()); 1039 1040 fastPathData.fastPathContainer = new char[containerSize]; 1041 1042 // Sets up prefix and suffix char arrays constants. 1043 fastPathData.charsPositiveSuffix = positiveSuffix.toCharArray(); 1044 fastPathData.charsNegativeSuffix = negativeSuffix.toCharArray(); 1045 fastPathData.charsPositivePrefix = positivePrefix.toCharArray(); 1046 fastPathData.charsNegativePrefix = negativePrefix.toCharArray(); 1047 1048 // Sets up fixed index positions for integral and fractional digits. 1049 // Sets up decimal point in cached result container. 1050 int longestPrefixLength 1051 = Math.max(positivePrefix.length(), 1052 negativePrefix.length()); 1053 int decimalPointIndex 1054 = maxNbIntegralDigits + maxNbGroups + longestPrefixLength; 1055 1056 fastPathData.integralLastIndex = decimalPointIndex - 1; 1057 fastPathData.fractionalFirstIndex = decimalPointIndex + 1; 1058 fastPathData.fastPathContainer[decimalPointIndex] 1059 = isCurrencyFormat 1060 ? symbols.getMonetaryDecimalSeparator() 1061 : symbols.getDecimalSeparator(); 1062 1063 } else if (fastPathWasOn) { 1064 // Previous state was fast-path and is no more. 1065 // Resets cached array constants. 1066 fastPathData.fastPathContainer = null; 1067 fastPathData.charsPositiveSuffix = null; 1068 fastPathData.charsNegativeSuffix = null; 1069 fastPathData.charsPositivePrefix = null; 1070 fastPathData.charsNegativePrefix = null; 1071 } 1072 } 1073 1074 /** 1075 * Returns true if rounding-up must be done on {@code scaledFractionalPartAsInt}, 1076 * false otherwise. 1077 * 1078 * This is a utility method that takes correct half-even rounding decision on 1079 * passed fractional value at the scaled decimal point (2 digits for currency 1080 * case and 3 for decimal case), when the approximated fractional part after 1081 * scaled decimal point is exactly 0.5d. This is done by means of exact 1082 * calculations on the {@code fractionalPart} floating-point value. 1083 * 1084 * This method is supposed to be called by private {@code fastDoubleFormat} 1085 * method only. 1086 * 1087 * The algorithms used for the exact calculations are : 1088 * 1089 * The <b><i>FastTwoSum</i></b> algorithm, from T.J.Dekker, described in the 1090 * papers "<i>A Floating-Point Technique for Extending the Available 1091 * Precision</i>" by Dekker, and in "<i>Adaptive Precision Floating-Point 1092 * Arithmetic and Fast Robust Geometric Predicates</i>" from J.Shewchuk. 1093 * 1094 * A modified version of <b><i>Sum2S</i></b> cascaded summation described in 1095 * "<i>Accurate Sum and Dot Product</i>" from Takeshi Ogita and All. As 1096 * Ogita says in this paper this is an equivalent of the Kahan-Babuska‘s 1097 * summation algorithm because we order the terms by magnitude before summing 1098 * them. For this reason we can use the <i>FastTwoSum</i> algorithm rather 1099 * than the more expensive Knuth‘s <i>TwoSum</i>. 1100 * 1101 * We do this to avoid a more expensive exact "<i>TwoProduct</i>" algorithm, 1102 * like those described in Shewchuk‘s paper above. See comments in the code 1103 * below. 1104 * 1105 * @param fractionalPart The fractional value on which we take rounding 1106 * decision. 1107 * @param scaledFractionalPartAsInt The integral part of the scaled 1108 * fractional value. 1109 * 1110 * @return the decision that must be taken regarding half-even rounding. 1111 */ 1112 private boolean exactRoundUp(double fractionalPart, 1113 int scaledFractionalPartAsInt) { 1114 1115 /* exactRoundUp() method is called by fastDoubleFormat() only. 1116 * The precondition expected to be verified by the passed parameters is : 1117 * scaledFractionalPartAsInt == 1118 * (int) (fractionalPart * fastPathData.fractionalScaleFactor). 1119 * This is ensured by fastDoubleFormat() code. 1120 */ 1121 1122 /* We first calculate roundoff error made by fastDoubleFormat() on 1123 * the scaled fractional part. We do this with exact calculation on the 1124 * passed fractionalPart. Rounding decision will then be taken from roundoff. 1125 */ 1126 1127 /* ---- TwoProduct(fractionalPart, scale factor (i.e. 1000.0d or 100.0d)). 1128 * 1129 * The below is an optimized exact "TwoProduct" calculation of passed 1130 * fractional part with scale factor, using Ogita‘s Sum2S cascaded 1131 * summation adapted as Kahan-Babuska equivalent by using FastTwoSum 1132 * (much faster) rather than Knuth‘s TwoSum. 1133 * 1134 * We can do this because we order the summation from smallest to 1135 * greatest, so that FastTwoSum can be used without any additional error. 1136 * 1137 * The "TwoProduct" exact calculation needs 17 flops. We replace this by 1138 * a cascaded summation of FastTwoSum calculations, each involving an 1139 * exact multiply by a power of 2. 1140 * 1141 * Doing so saves overall 4 multiplications and 1 addition compared to 1142 * using traditional "TwoProduct". 1143 * 1144 * The scale factor is either 100 (currency case) or 1000 (decimal case). 1145 * - when 1000, we replace it by (1024 - 16 - 8) = 1000. 1146 * - when 100, we replace it by (128 - 32 + 4) = 100. 1147 * Every multiplication by a power of 2 (1024, 128, 32, 16, 8, 4) is exact. 1148 * 1149 */ 1150 double approxMax; // Will always be positive. 1151 double approxMedium; // Will always be negative. 1152 double approxMin; 1153 1154 double fastTwoSumApproximation = 0.0d; 1155 double fastTwoSumRoundOff = 0.0d; 1156 double bVirtual = 0.0d; 1157 1158 if (isCurrencyFormat) { 1159 // Scale is 100 = 128 - 32 + 4. 1160 // Multiply by 2**n is a shift. No roundoff. No error. 1161 approxMax = fractionalPart * 128.00d; 1162 approxMedium = - (fractionalPart * 32.00d); 1163 approxMin = fractionalPart * 4.00d; 1164 } else { 1165 // Scale is 1000 = 1024 - 16 - 8. 1166 // Multiply by 2**n is a shift. No roundoff. No error. 1167 approxMax = fractionalPart * 1024.00d; 1168 approxMedium = - (fractionalPart * 16.00d); 1169 approxMin = - (fractionalPart * 8.00d); 1170 } 1171 1172 // Shewchuk/Dekker‘s FastTwoSum(approxMedium, approxMin). 1173 assert(-approxMedium >= Math.abs(approxMin)); 1174 fastTwoSumApproximation = approxMedium + approxMin; 1175 bVirtual = fastTwoSumApproximation - approxMedium; 1176 fastTwoSumRoundOff = approxMin - bVirtual; 1177 double approxS1 = fastTwoSumApproximation; 1178 double roundoffS1 = fastTwoSumRoundOff; 1179 1180 // Shewchuk/Dekker‘s FastTwoSum(approxMax, approxS1); 1181 assert(approxMax >= Math.abs(approxS1)); 1182 fastTwoSumApproximation = approxMax + approxS1; 1183 bVirtual = fastTwoSumApproximation - approxMax; 1184 fastTwoSumRoundOff = approxS1 - bVirtual; 1185 double roundoff1000 = fastTwoSumRoundOff; 1186 double approx1000 = fastTwoSumApproximation; 1187 double roundoffTotal = roundoffS1 + roundoff1000; 1188 1189 // Shewchuk/Dekker‘s FastTwoSum(approx1000, roundoffTotal); 1190 assert(approx1000 >= Math.abs(roundoffTotal)); 1191 fastTwoSumApproximation = approx1000 + roundoffTotal; 1192 bVirtual = fastTwoSumApproximation - approx1000; 1193 1194 // Now we have got the roundoff for the scaled fractional 1195 double scaledFractionalRoundoff = roundoffTotal - bVirtual; 1196 1197 // ---- TwoProduct(fractionalPart, scale (i.e. 1000.0d or 100.0d)) end. 1198 1199 /* ---- Taking the rounding decision 1200 * 1201 * We take rounding decision based on roundoff and half-even rounding 1202 * rule. 1203 * 1204 * The above TwoProduct gives us the exact roundoff on the approximated 1205 * scaled fractional, and we know that this approximation is exactly 1206 * 0.5d, since that has already been tested by the caller 1207 * (fastDoubleFormat). 1208 * 1209 * Decision comes first from the sign of the calculated exact roundoff. 1210 * - Since being exact roundoff, it cannot be positive with a scaled 1211 * fractional less than 0.5d, as well as negative with a scaled 1212 * fractional greater than 0.5d. That leaves us with following 3 cases. 1213 * - positive, thus scaled fractional == 0.500....0fff ==> round-up. 1214 * - negative, thus scaled fractional == 0.499....9fff ==> don‘t round-up. 1215 * - is zero, thus scaled fractioanl == 0.5 ==> half-even rounding applies : 1216 * we round-up only if the integral part of the scaled fractional is odd. 1217 * 1218 */ 1219 if (scaledFractionalRoundoff > 0.0) { 1220 return true; 1221 } else if (scaledFractionalRoundoff < 0.0) { 1222 return false; 1223 } else if ((scaledFractionalPartAsInt & 1) != 0) { 1224 return true; 1225 } 1226 1227 return false; 1228 1229 // ---- Taking the rounding decision end 1230 } 1231 1232 /** 1233 * Collects integral digits from passed {@code number}, while setting 1234 * grouping chars as needed. Updates {@code firstUsedIndex} accordingly. 1235 * 1236 * Loops downward starting from {@code backwardIndex} position (inclusive). 1237 * 1238 * @param number The int value from which we collect digits. 1239 * @param digitsBuffer The char array container where digits and grouping chars 1240 * are stored. 1241 * @param backwardIndex the position from which we start storing digits in 1242 * digitsBuffer. 1243 * 1244 */ 1245 private void collectIntegralDigits(int number, 1246 char[] digitsBuffer, 1247 int backwardIndex) { 1248 int index = backwardIndex; 1249 int q; 1250 int r; 1251 while (number > 999) { 1252 // Generates 3 digits per iteration. 1253 q = number / 1000; 1254 r = number - (q << 10) + (q << 4) + (q << 3); // -1024 +16 +8 = 1000. 1255 number = q; 1256 1257 digitsBuffer[index--] = DigitArrays.DigitOnes1000[r]; 1258 digitsBuffer[index--] = DigitArrays.DigitTens1000[r]; 1259 digitsBuffer[index--] = DigitArrays.DigitHundreds1000[r]; 1260 digitsBuffer[index--] = fastPathData.groupingChar; 1261 } 1262 1263 // Collects last 3 or less digits. 1264 digitsBuffer[index] = DigitArrays.DigitOnes1000[number]; 1265 if (number > 9) { 1266 digitsBuffer[--index] = DigitArrays.DigitTens1000[number]; 1267 if (number > 99) 1268 digitsBuffer[--index] = DigitArrays.DigitHundreds1000[number]; 1269 } 1270 1271 fastPathData.firstUsedIndex = index; 1272 } 1273 1274 /** 1275 * Collects the 2 (currency) or 3 (decimal) fractional digits from passed 1276 * {@code number}, starting at {@code startIndex} position 1277 * inclusive. There is no punctuation to set here (no grouping chars). 1278 * Updates {@code fastPathData.lastFreeIndex} accordingly. 1279 * 1280 * 1281 * @param number The int value from which we collect digits. 1282 * @param digitsBuffer The char array container where digits are stored. 1283 * @param startIndex the position from which we start storing digits in 1284 * digitsBuffer. 1285 * 1286 */ 1287 private void collectFractionalDigits(int number, 1288 char[] digitsBuffer, 1289 int startIndex) { 1290 int index = startIndex; 1291 1292 char digitOnes = DigitArrays.DigitOnes1000[number]; 1293 char digitTens = DigitArrays.DigitTens1000[number]; 1294 1295 if (isCurrencyFormat) { 1296 // Currency case. Always collects fractional digits. 1297 digitsBuffer[index++] = digitTens; 1298 digitsBuffer[index++] = digitOnes; 1299 } else if (number != 0) { 1300 // Decimal case. Hundreds will always be collected 1301 digitsBuffer[index++] = DigitArrays.DigitHundreds1000[number]; 1302 1303 // Ending zeros won‘t be collected. 1304 if (digitOnes != ‘0‘) { 1305 digitsBuffer[index++] = digitTens; 1306 digitsBuffer[index++] = digitOnes; 1307 } else if (digitTens != ‘0‘) 1308 digitsBuffer[index++] = digitTens; 1309 1310 } else 1311 // This is decimal pattern and fractional part is zero. 1312 // We must remove decimal point from result. 1313 index--; 1314 1315 fastPathData.lastFreeIndex = index; 1316 } 1317 1318 /** 1319 * Internal utility. 1320 * Adds the passed {@code prefix} and {@code suffix} to {@code container}. 1321 * 1322 * @param container Char array container which to prepend/append the 1323 * prefix/suffix. 1324 * @param prefix Char sequence to prepend as a prefix. 1325 * @param suffix Char sequence to append as a suffix. 1326 * 1327 */ 1328 // private void addAffixes(boolean isNegative, char[] container) { 1329 private void addAffixes(char[] container, char[] prefix, char[] suffix) { 1330 1331 // We add affixes only if needed (affix length > 0). 1332 int pl = prefix.length; 1333 int sl = suffix.length; 1334 if (pl != 0) prependPrefix(prefix, pl, container); 1335 if (sl != 0) appendSuffix(suffix, sl, container); 1336 1337 } 1338 1339 /** 1340 * Prepends the passed {@code prefix} chars to given result 1341 * {@code container}. Updates {@code fastPathData.firstUsedIndex} 1342 * accordingly. 1343 * 1344 * @param prefix The prefix characters to prepend to result. 1345 * @param len The number of chars to prepend. 1346 * @param container Char array container which to prepend the prefix 1347 */ 1348 private void prependPrefix(char[] prefix, 1349 int len, 1350 char[] container) { 1351 1352 fastPathData.firstUsedIndex -= len; 1353 int startIndex = fastPathData.firstUsedIndex; 1354 1355 // If prefix to prepend is only 1 char long, just assigns this char. 1356 // If prefix is less or equal 4, we use a dedicated algorithm that 1357 // has shown to run faster than System.arraycopy. 1358 // If more than 4, we use System.arraycopy. 1359 if (len == 1) 1360 container[startIndex] = prefix[0]; 1361 else if (len <= 4) { 1362 int dstLower = startIndex; 1363 int dstUpper = dstLower + len - 1; 1364 int srcUpper = len - 1; 1365 container[dstLower] = prefix[0]; 1366 container[dstUpper] = prefix[srcUpper]; 1367 1368 if (len > 2) 1369 container[++dstLower] = prefix[1]; 1370 if (len == 4) 1371 container[--dstUpper] = prefix[2]; 1372 } else 1373 System.arraycopy(prefix, 0, container, startIndex, len); 1374 } 1375 1376 /** 1377 * Appends the passed {@code suffix} chars to given result 1378 * {@code container}. Updates {@code fastPathData.lastFreeIndex} 1379 * accordingly. 1380 * 1381 * @param suffix The suffix characters to append to result. 1382 * @param len The number of chars to append. 1383 * @param container Char array container which to append the suffix 1384 */ 1385 private void appendSuffix(char[] suffix, 1386 int len, 1387 char[] container) { 1388 1389 int startIndex = fastPathData.lastFreeIndex; 1390 1391 // If suffix to append is only 1 char long, just assigns this char. 1392 // If suffix is less or equal 4, we use a dedicated algorithm that 1393 // has shown to run faster than System.arraycopy. 1394 // If more than 4, we use System.arraycopy. 1395 if (len == 1) 1396 container[startIndex] = suffix[0]; 1397 else if (len <= 4) { 1398 int dstLower = startIndex; 1399 int dstUpper = dstLower + len - 1; 1400 int srcUpper = len - 1; 1401 container[dstLower] = suffix[0]; 1402 container[dstUpper] = suffix[srcUpper]; 1403 1404 if (len > 2) 1405 container[++dstLower] = suffix[1]; 1406 if (len == 4) 1407 container[--dstUpper] = suffix[2]; 1408 } else 1409 System.arraycopy(suffix, 0, container, startIndex, len); 1410 1411 fastPathData.lastFreeIndex += len; 1412 } 1413 1414 /** 1415 * Converts digit chars from {@code digitsBuffer} to current locale. 1416 * 1417 * Must be called before adding affixes since we refer to 1418 * {@code fastPathData.firstUsedIndex} and {@code fastPathData.lastFreeIndex}, 1419 * and do not support affixes (for speed reason). 1420 * 1421 * We loop backward starting from last used index in {@code fastPathData}. 1422 * 1423 * @param digitsBuffer The char array container where the digits are stored. 1424 */ 1425 private void localizeDigits(char[] digitsBuffer) { 1426 1427 // We will localize only the digits, using the groupingSize, 1428 // and taking into account fractional part. 1429 1430 // First take into account fractional part. 1431 int digitsCounter = 1432 fastPathData.lastFreeIndex - fastPathData.fractionalFirstIndex; 1433 1434 // The case when there is no fractional digits. 1435 if (digitsCounter < 0) 1436 digitsCounter = groupingSize; 1437 1438 // Only the digits remains to localize. 1439 for (int cursor = fastPathData.lastFreeIndex - 1; 1440 cursor >= fastPathData.firstUsedIndex; 1441 cursor--) { 1442 if (digitsCounter != 0) { 1443 // This is a digit char, we must localize it. 1444 digitsBuffer[cursor] += fastPathData.zeroDelta; 1445 digitsCounter--; 1446 } else { 1447 // Decimal separator or grouping char. Reinit counter only. 1448 digitsCounter = groupingSize; 1449 } 1450 } 1451 } 1452 1453 /** 1454 * This is the main entry point for the fast-path format algorithm. 1455 * 1456 * At this point we are sure to be in the expected conditions to run it. 1457 * This algorithm builds the formatted result and puts it in the dedicated 1458 * {@code fastPathData.fastPathContainer}. 1459 * 1460 * @param d the double value to be formatted. 1461 * @param negative Flag precising if {@code d} is negative. 1462 */ 1463 private void fastDoubleFormat(double d, 1464 boolean negative) { 1465 1466 char[] container = fastPathData.fastPathContainer; 1467 1468 /* 1469 * The principle of the algorithm is to : 1470 * - Break the passed double into its integral and fractional parts 1471 * converted into integers. 1472 * - Then decide if rounding up must be applied or not by following 1473 * the half-even rounding rule, first using approximated scaled 1474 * fractional part. 1475 * - For the difficult cases (approximated scaled fractional part 1476 * being exactly 0.5d), we refine the rounding decision by calling 1477 * exactRoundUp utility method that both calculates the exact roundoff 1478 * on the approximation and takes correct rounding decision. 1479 * - We round-up the fractional part if needed, possibly propagating the 1480 * rounding to integral part if we meet a "all-nine" case for the 1481 * scaled fractional part. 1482 * - We then collect digits from the resulting integral and fractional 1483 * parts, also setting the required grouping chars on the fly. 1484 * - Then we localize the collected digits if needed, and 1485 * - Finally prepend/append prefix/suffix if any is needed. 1486 */ 1487 1488 // Exact integral part of d. 1489 int integralPartAsInt = (int) d; 1490 1491 // Exact fractional part of d (since we subtract it‘s integral part). 1492 double exactFractionalPart = d - (double) integralPartAsInt; 1493 1494 // Approximated scaled fractional part of d (due to multiplication). 1495 double scaledFractional = 1496 exactFractionalPart * fastPathData.fractionalScaleFactor; 1497 1498 // Exact integral part of scaled fractional above. 1499 int fractionalPartAsInt = (int) scaledFractional; 1500 1501 // Exact fractional part of scaled fractional above. 1502 scaledFractional = scaledFractional - (double) fractionalPartAsInt; 1503 1504 // Only when scaledFractional is exactly 0.5d do we have to do exact 1505 // calculations and take fine-grained rounding decision, since 1506 // approximated results above may lead to incorrect decision. 1507 // Otherwise comparing against 0.5d (strictly greater or less) is ok. 1508 boolean roundItUp = false; 1509 if (scaledFractional >= 0.5d) { 1510 if (scaledFractional == 0.5d) 1511 // Rounding need fine-grained decision. 1512 roundItUp = exactRoundUp(exactFractionalPart, fractionalPartAsInt); 1513 else 1514 roundItUp = true; 1515 1516 if (roundItUp) { 1517 // Rounds up both fractional part (and also integral if needed). 1518 if (fractionalPartAsInt < fastPathData.fractionalMaxIntBound) { 1519 fractionalPartAsInt++; 1520 } else { 1521 // Propagates rounding to integral part since "all nines" case. 1522 fractionalPartAsInt = 0; 1523 integralPartAsInt++; 1524 } 1525 } 1526 } 1527 1528 // Collecting digits. 1529 collectFractionalDigits(fractionalPartAsInt, container, 1530 fastPathData.fractionalFirstIndex); 1531 collectIntegralDigits(integralPartAsInt, container, 1532 fastPathData.integralLastIndex); 1533 1534 // Localizing digits. 1535 if (fastPathData.zeroDelta != 0) 1536 localizeDigits(container); 1537 1538 // Adding prefix and suffix. 1539 if (negative) { 1540 if (fastPathData.negativeAffixesRequired) 1541 addAffixes(container, 1542 fastPathData.charsNegativePrefix, 1543 fastPathData.charsNegativeSuffix); 1544 } else if (fastPathData.positiveAffixesRequired) 1545 addAffixes(container, 1546 fastPathData.charsPositivePrefix, 1547 fastPathData.charsPositiveSuffix); 1548 } 1549 1550 /** 1551 * A fast-path shortcut of format(double) to be called by NumberFormat, or by 1552 * format(double, ...) public methods. 1553 * 1554 * If instance can be applied fast-path and passed double is not NaN or 1555 * Infinity, is in the integer range, we call {@code fastDoubleFormat} 1556 * after changing {@code d} to its positive value if necessary. 1557 * 1558 * Otherwise returns null by convention since fast-path can‘t be exercized. 1559 * 1560 * @param d The double value to be formatted 1561 * 1562 * @return the formatted result for {@code d} as a string. 1563 */ 1564 String fastFormat(double d) { 1565 boolean isDataSet = false; 1566 // (Re-)Evaluates fast-path status if needed. 1567 if (fastPathCheckNeeded) { 1568 isDataSet = checkAndSetFastPathStatus(); 1569 } 1570 1571 if (!isFastPath ) 1572 // DecimalFormat instance is not in a fast-path state. 1573 return null; 1574 1575 if (!Double.isFinite(d)) 1576 // Should not use fast-path for Infinity and NaN. 1577 return null; 1578 1579 // Extracts and records sign of double value, possibly changing it 1580 // to a positive one, before calling fastDoubleFormat(). 1581 boolean negative = false; 1582 if (d < 0.0d) { 1583 negative = true; 1584 d = -d; 1585 } else if (d == 0.0d) { 1586 negative = (Math.copySign(1.0d, d) == -1.0d); 1587 d = +0.0d; 1588 } 1589 1590 if (d > MAX_INT_AS_DOUBLE) 1591 // Filters out values that are outside expected fast-path range 1592 return null; 1593 else { 1594 if (!isDataSet) { 1595 /* 1596 * If the fast path data is not set through 1597 * checkAndSetFastPathStatus() and fulfil the 1598 * fast path conditions then reset the data 1599 * directly through resetFastPathData() 1600 */ 1601 resetFastPathData(isFastPath); 1602 } 1603 fastDoubleFormat(d, negative); 1604 1605 } 1606 1607 1608 // Returns a new string from updated fastPathContainer. 1609 return new String(fastPathData.fastPathContainer, 1610 fastPathData.firstUsedIndex, 1611 fastPathData.lastFreeIndex - fastPathData.firstUsedIndex); 1612 1613 } 1614 1615 // ======== End fast-path formating logic for double ========================= 1616 1617 /** 1618 * Complete the formatting of a finite number. On entry, the digitList must 1619 * be filled in with the correct digits. 1620 */ 1621 private StringBuffer subformat(StringBuffer result, FieldDelegate delegate, 1622 boolean isNegative, boolean isInteger, 1623 int maxIntDigits, int minIntDigits, 1624 int maxFraDigits, int minFraDigits) { 1625 // NOTE: This isn‘t required anymore because DigitList takes care of this. 1626 // 1627 // // The negative of the exponent represents the number of leading 1628 // // zeros between the decimal and the first non-zero digit, for 1629 // // a value < 0.1 (e.g., for 0.00123, -fExponent == 2). If this 1630 // // is more than the maximum fraction digits, then we have an underflow 1631 // // for the printed representation. We recognize this here and set 1632 // // the DigitList representation to zero in this situation. 1633 // 1634 // if (-digitList.decimalAt >= getMaximumFractionDigits()) 1635 // { 1636 // digitList.count = 0; 1637 // } 1638 1639 char zero = symbols.getZeroDigit(); 1640 int zeroDelta = zero - ‘0‘; // ‘0‘ is the DigitList representation of zero 1641 char grouping = symbols.getGroupingSeparator(); 1642 char decimal = isCurrencyFormat ? 1643 symbols.getMonetaryDecimalSeparator() : 1644 symbols.getDecimalSeparator(); 1645 1646 /* Per bug 4147706, DecimalFormat must respect the sign of numbers which 1647 * format as zero. This allows sensible computations and preserves 1648 * relations such as signum(1/x) = signum(x), where x is +Infinity or 1649 * -Infinity. Prior to this fix, we always formatted zero values as if 1650 * they were positive. Liu 7/6/98. 1651 */ 1652 if (digitList.isZero()) { 1653 digitList.decimalAt = 0; // Normalize 1654 } 1655 1656 if (isNegative) { 1657 append(result, negativePrefix, delegate, 1658 getNegativePrefixFieldPositions(), Field.SIGN); 1659 } else { 1660 append(result, positivePrefix, delegate, 1661 getPositivePrefixFieldPositions(), Field.SIGN); 1662 } 1663 1664 if (useExponentialNotation) { 1665 int iFieldStart = result.length(); 1666 int iFieldEnd = -1; 1667 int fFieldStart = -1; 1668 1669 // Minimum integer digits are handled in exponential format by 1670 // adjusting the exponent. For example, 0.01234 with 3 minimum 1671 // integer digits is "123.4E-4". 1672 1673 // Maximum integer digits are interpreted as indicating the 1674 // repeating range. This is useful for engineering notation, in 1675 // which the exponent is restricted to a multiple of 3. For 1676 // example, 0.01234 with 3 maximum integer digits is "12.34e-3". 1677 // If maximum integer digits are > 1 and are larger than 1678 // minimum integer digits, then minimum integer digits are 1679 // ignored. 1680 int exponent = digitList.decimalAt; 1681 int repeat = maxIntDigits; 1682 int minimumIntegerDigits = minIntDigits; 1683 if (repeat > 1 && repeat > minIntDigits) { 1684 // A repeating range is defined; adjust to it as follows. 1685 // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3; 1686 // -3,-4,-5=>-6, etc. This takes into account that the 1687 // exponent we have here is off by one from what we expect; 1688 // it is for the format 0.MMMMMx10^n. 1689 if (exponent >= 1) { 1690 exponent = ((exponent - 1) / repeat) * repeat; 1691 } else { 1692 // integer division rounds towards 0 1693 exponent = ((exponent - repeat) / repeat) * repeat; 1694 } 1695 minimumIntegerDigits = 1; 1696 } else { 1697 // No repeating range is defined; use minimum integer digits. 1698 exponent -= minimumIntegerDigits; 1699 } 1700 1701 // We now output a minimum number of digits, and more if there 1702 // are more digits, up to the maximum number of digits. We 1703 // place the decimal point after the "integer" digits, which 1704 // are the first (decimalAt - exponent) digits. 1705 int minimumDigits = minIntDigits + minFraDigits; 1706 if (minimumDigits < 0) { // overflow? 1707 minimumDigits = Integer.MAX_VALUE; 1708 } 1709 1710 // The number of integer digits is handled specially if the number 1711 // is zero, since then there may be no digits. 1712 int integerDigits = digitList.isZero() ? minimumIntegerDigits : 1713 digitList.decimalAt - exponent; 1714 if (minimumDigits < integerDigits) { 1715 minimumDigits = integerDigits; 1716 } 1717 int totalDigits = digitList.count; 1718 if (minimumDigits > totalDigits) { 1719 totalDigits = minimumDigits; 1720 } 1721 boolean addedDecimalSeparator = false; 1722 1723 for (int i=0; i<totalDigits; ++i) { 1724 if (i == integerDigits) { 1725 // Record field information for caller. 1726 iFieldEnd = result.length(); 1727 1728 result.append(decimal); 1729 addedDecimalSeparator = true; 1730 1731 // Record field information for caller. 1732 fFieldStart = result.length(); 1733 } 1734 result.append((i < digitList.count) ? 1735 (char)(digitList.digits[i] + zeroDelta) : 1736 zero); 1737 } 1738 1739 if (decimalSeparatorAlwaysShown && totalDigits == integerDigits) { 1740 // Record field information for caller. 1741 iFieldEnd = result.length(); 1742 1743 result.append(decimal); 1744 addedDecimalSeparator = true; 1745 1746 // Record field information for caller. 1747 fFieldStart = result.length(); 1748 } 1749 1750 // Record field information 1751 if (iFieldEnd == -1) { 1752 iFieldEnd = result.length(); 1753 } 1754 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, 1755 iFieldStart, iFieldEnd, result); 1756 if (addedDecimalSeparator) { 1757 delegate.formatted(Field.DECIMAL_SEPARATOR, 1758 Field.DECIMAL_SEPARATOR, 1759 iFieldEnd, fFieldStart, result); 1760 } 1761 if (fFieldStart == -1) { 1762 fFieldStart = result.length(); 1763 } 1764 delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION, 1765 fFieldStart, result.length(), result); 1766 1767 // The exponent is output using the pattern-specified minimum 1768 // exponent digits. There is no maximum limit to the exponent 1769 // digits, since truncating the exponent would result in an 1770 // unacceptable inaccuracy. 1771 int fieldStart = result.length(); 1772 1773 result.append(symbols.getExponentSeparator()); 1774 1775 delegate.formatted(Field.EXPONENT_SYMBOL, Field.EXPONENT_SYMBOL, 1776 fieldStart, result.length(), result); 1777 1778 // For zero values, we force the exponent to zero. We 1779 // must do this here, and not earlier, because the value 1780 // is used to determine integer digit count above. 1781 if (digitList.isZero()) { 1782 exponent = 0; 1783 } 1784 1785 boolean negativeExponent = exponent < 0; 1786 if (negativeExponent) { 1787 exponent = -exponent; 1788 fieldStart = result.length(); 1789 result.append(symbols.getMinusSign()); 1790 delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN, 1791 fieldStart, result.length(), result); 1792 } 1793 digitList.set(negativeExponent, exponent); 1794 1795 int eFieldStart = result.length(); 1796 1797 for (int i=digitList.decimalAt; i<minExponentDigits; ++i) { 1798 result.append(zero); 1799 } 1800 for (int i=0; i<digitList.decimalAt; ++i) { 1801 result.append((i < digitList.count) ? 1802 (char)(digitList.digits[i] + zeroDelta) : zero); 1803 } 1804 delegate.formatted(Field.EXPONENT, Field.EXPONENT, eFieldStart, 1805 result.length(), result); 1806 } else { 1807 int iFieldStart = result.length(); 1808 1809 // Output the integer portion. Here ‘count‘ is the total 1810 // number of integer digits we will display, including both 1811 // leading zeros required to satisfy getMinimumIntegerDigits, 1812 // and actual digits present in the number. 1813 int count = minIntDigits; 1814 int digitIndex = 0; // Index into digitList.fDigits[] 1815 if (digitList.decimalAt > 0 && count < digitList.decimalAt) { 1816 count = digitList.decimalAt; 1817 } 1818 1819 // Handle the case where getMaximumIntegerDigits() is smaller 1820 // than the real number of integer digits. If this is so, we 1821 // output the least significant max integer digits. For example, 1822 // the value 1997 printed with 2 max integer digits is just "97". 1823 if (count > maxIntDigits) { 1824 count = maxIntDigits; 1825 digitIndex = digitList.decimalAt - count; 1826 } 1827 1828 int sizeBeforeIntegerPart = result.length(); 1829 for (int i=count-1; i>=0; --i) { 1830 if (i < digitList.decimalAt && digitIndex < digitList.count) { 1831 // Output a real digit 1832 result.append((char)(digitList.digits[digitIndex++] + zeroDelta)); 1833 } else { 1834 // Output a leading zero 1835 result.append(zero); 1836 } 1837 1838 // Output grouping separator if necessary. Don‘t output a 1839 // grouping separator if i==0 though; that‘s at the end of 1840 // the integer part. 1841 if (isGroupingUsed() && i>0 && (groupingSize != 0) && 1842 (i % groupingSize == 0)) { 1843 int gStart = result.length(); 1844 result.append(grouping); 1845 delegate.formatted(Field.GROUPING_SEPARATOR, 1846 Field.GROUPING_SEPARATOR, gStart, 1847 result.length(), result); 1848 } 1849 } 1850 1851 // Determine whether or not there are any printable fractional 1852 // digits. If we‘ve used up the digits we know there aren‘t. 1853 boolean fractionPresent = (minFraDigits > 0) || 1854 (!isInteger && digitIndex < digitList.count); 1855 1856 // If there is no fraction present, and we haven‘t printed any 1857 // integer digits, then print a zero. Otherwise we won‘t print 1858 // _any_ digits, and we won‘t be able to parse this string. 1859 if (!fractionPresent && result.length() == sizeBeforeIntegerPart) { 1860 result.append(zero); 1861 } 1862 1863 delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER, 1864 iFieldStart, result.length(), result); 1865 1866 // Output the decimal separator if we always do so. 1867 int sStart = result.length(); 1868 if (decimalSeparatorAlwaysShown || fractionPresent) { 1869 result.append(decimal); 1870 } 1871 1872 if (sStart != result.length()) { 1873 delegate.formatted(Field.DECIMAL_SEPARATOR, 1874 Field.DECIMAL_SEPARATOR, 1875 sStart, result.length(), result); 1876 } 1877 int fFieldStart = result.length(); 1878 1879 for (int i=0; i < maxFraDigits; ++i) { 1880 // Here is where we escape from the loop. We escape if we‘ve 1881 // output the maximum fraction digits (specified in the for 1882 // expression above). 1883 // We also stop when we‘ve output the minimum digits and either: 1884 // we have an integer, so there is no fractional stuff to 1885 // display, or we‘re out of significant digits. 1886 if (i >= minFraDigits && 1887 (isInteger || digitIndex >= digitList.count)) { 1888 break; 1889 } 1890 1891 // Output leading fractional zeros. These are zeros that come 1892 // after the decimal but before any significant digits. These 1893 // are only output if abs(number being formatted) < 1.0. 1894 if (-1-i > (digitList.decimalAt-1)) { 1895 result.append(zero); 1896 continue; 1897 } 1898 1899 // Output a digit, if we have any precision left, or a 1900 // zero if we don‘t. We don‘t want to output noise digits. 1901 if (!isInteger && digitIndex < digitList.count) { 1902 result.append((char)(digitList.digits[digitIndex++] + zeroDelta)); 1903 } else { 1904 result.append(zero); 1905 } 1906 } 1907 1908 // Record field information for caller. 1909 delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION, 1910 fFieldStart, result.length(), result); 1911 } 1912 1913 if (isNegative) { 1914 append(result, negativeSuffix, delegate, 1915 getNegativeSuffixFieldPositions(), Field.SIGN); 1916 } else { 1917 append(result, positiveSuffix, delegate, 1918 getPositiveSuffixFieldPositions(), Field.SIGN); 1919 } 1920 1921 return result; 1922 } 1923 1924 /** 1925 * Appends the String <code>string</code> to <code>result</code>. 1926 * <code>delegate</code> is notified of all the 1927 * <code>FieldPosition</code>s in <code>positions</code>. 1928 * <p> 1929 * If one of the <code>FieldPosition</code>s in <code>positions</code> 1930 * identifies a <code>SIGN</code> attribute, it is mapped to 1931 * <code>signAttribute</code>. This is used 1932 * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code> 1933 * attribute as necessary. 1934 * <p> 1935 * This is used by <code>subformat</code> to add the prefix/suffix. 1936 */ 1937 private void append(StringBuffer result, String string, 1938 FieldDelegate delegate, 1939 FieldPosition[] positions, 1940 Format.Field signAttribute) { 1941 int start = result.length(); 1942 1943 if (string.length() > 0) { 1944 result.append(string); 1945 for (int counter = 0, max = positions.length; counter < max; 1946 counter++) { 1947 FieldPosition fp = positions[counter]; 1948 Format.Field attribute = fp.getFieldAttribute(); 1949 1950 if (attribute == Field.SIGN) { 1951 attribute = signAttribute; 1952 } 1953 delegate.formatted(attribute, attribute, 1954 start + fp.getBeginIndex(), 1955 start + fp.getEndIndex(), result); 1956 } 1957 } 1958 } 1959 1960 /** 1961 * Parses text from a string to produce a <code>Number</code>. 1962 * <p> 1963 * The method attempts to parse text starting at the index given by 1964 * <code>pos</code>. 1965 * If parsing succeeds, then the index of <code>pos</code> is updated 1966 * to the index after the last character used (parsing does not necessarily 1967 * use all characters up to the end of the string), and the parsed 1968 * number is returned. The updated <code>pos</code> can be used to 1969 * indicate the starting point for the next call to this method. 1970 * If an error occurs, then the index of <code>pos</code> is not 1971 * changed, the error index of <code>pos</code> is set to the index of 1972 * the character where the error occurred, and null is returned. 1973 * <p> 1974 * The subclass returned depends on the value of {@link #isParseBigDecimal} 1975 * as well as on the string being parsed. 1976 * <ul> 1977 * <li>If <code>isParseBigDecimal()</code> is false (the default), 1978 * most integer values are returned as <code>Long</code> 1979 * objects, no matter how they are written: <code>"17"</code> and 1980 * <code>"17.000"</code> both parse to <code>Long(17)</code>. 1981 * Values that cannot fit into a <code>Long</code> are returned as 1982 * <code>Double</code>s. This includes values with a fractional part, 1983 * infinite values, <code>NaN</code>, and the value -0.0. 1984 * <code>DecimalFormat</code> does <em>not</em> decide whether to 1985 * return a <code>Double</code> or a <code>Long</code> based on the 1986 * presence of a decimal separator in the source string. Doing so 1987 * would prevent integers that overflow the mantissa of a double, 1988 * such as <code>"-9,223,372,036,854,775,808.00"</code>, from being 1989 * parsed accurately. 1990 * <p> 1991 * Callers may use the <code>Number</code> methods 1992 * <code>doubleValue</code>, <code>longValue</code>, etc., to obtain 1993 * the type they want. 1994 * <li>If <code>isParseBigDecimal()</code> is true, values are returned 1995 * as <code>BigDecimal</code> objects. The values are the ones 1996 * constructed by {@link java.math.BigDecimal#BigDecimal(String)} 1997 * for corresponding strings in locale-independent format. The 1998 * special cases negative and positive infinity and NaN are returned 1999 * as <code>Double</code> instances holding the values of the 2000 * corresponding <code>Double</code> constants. 2001 * </ul> 2002 * <p> 2003 * <code>DecimalFormat</code> parses all Unicode characters that represent 2004 * decimal digits, as defined by <code>Character.digit()</code>. In 2005 * addition, <code>DecimalFormat</code> also recognizes as digits the ten 2006 * consecutive characters starting with the localized zero digit defined in 2007 * the <code>DecimalFormatSymbols</code> object. 2008 * 2009 * @param text the string to be parsed 2010 * @param pos A <code>ParsePosition</code> object with index and error 2011 * index information as described above. 2012 * @return the parsed value, or <code>null</code> if the parse fails 2013 * @exception NullPointerException if <code>text</code> or 2014 * <code>pos</code> is null. 2015 */ 2016 @Override 2017 public Number parse(String text, ParsePosition pos) { 2018 // special case NaN 2019 if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) { 2020 pos.index = pos.index + symbols.getNaN().length(); 2021 return Double.valueOf(Double.NaN); 2022 } 2023 2024 boolean[] status = new boolean[STATUS_LENGTH]; 2025 if (!subparse(text, pos, positivePrefix, negativePrefix, digitList, false, status)) { 2026 return null; 2027 } 2028 2029 // special case INFINITY 2030 if (status[STATUS_INFINITE]) { 2031 if (status[STATUS_POSITIVE] == (multiplier >= 0)) { 2032 return Double.valueOf(Double.POSITIVE_INFINITY); 2033 } else { 2034 return Double.valueOf(Double.NEGATIVE_INFINITY); 2035 } 2036 } 2037 2038 if (multiplier == 0) { 2039 if (digitList.isZero()) { 2040 return Double.valueOf(Double.NaN); 2041 } else if (status[STATUS_POSITIVE]) { 2042 return Double.valueOf(Double.POSITIVE_INFINITY); 2043 } else { 2044 return Double.valueOf(Double.NEGATIVE_INFINITY); 2045 } 2046 } 2047 2048 if (isParseBigDecimal()) { 2049 BigDecimal bigDecimalResult = digitList.getBigDecimal(); 2050 2051 if (multiplier != 1) { 2052 try { 2053 bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier()); 2054 } 2055 catch (ArithmeticException e) { // non-terminating decimal expansion 2056 bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier(), roundingMode); 2057 } 2058 } 2059 2060 if (!status[STATUS_POSITIVE]) { 2061 bigDecimalResult = bigDecimalResult.negate(); 2062 } 2063 return bigDecimalResult; 2064 } else { 2065 boolean gotDouble = true; 2066 boolean gotLongMinimum = false; 2067 double doubleResult = 0.0; 2068 long longResult = 0; 2069 2070 // Finally, have DigitList parse the digits into a value. 2071 if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) { 2072 gotDouble = false; 2073 longResult = digitList.getLong(); 2074 if (longResult < 0) { // got Long.MIN_VALUE 2075 gotLongMinimum = true; 2076 } 2077 } else { 2078 doubleResult = digitList.getDouble(); 2079 } 2080 2081 // Divide by multiplier. We have to be careful here not to do 2082 // unneeded conversions between double and long. 2083 if (multiplier != 1) { 2084 if (gotDouble) { 2085 doubleResult /= multiplier; 2086 } else { 2087 // Avoid converting to double if we can 2088 if (longResult % multiplier == 0) { 2089 longResult /= multiplier; 2090 } else { 2091 doubleResult = ((double)longResult) / multiplier; 2092 gotDouble = true; 2093 } 2094 } 2095 } 2096 2097 if (!status[STATUS_POSITIVE] && !gotLongMinimum) { 2098 doubleResult = -doubleResult; 2099 longResult = -longResult; 2100 } 2101 2102 // At this point, if we divided the result by the multiplier, the 2103 // result may fit into a long. We check for this case and return 2104 // a long if possible. 2105 // We must do this AFTER applying the negative (if appropriate) 2106 // in order to handle the case of LONG_MIN; otherwise, if we do 2107 // this with a positive value -LONG_MIN, the double is > 0, but 2108 // the long is < 0. We also must retain a double in the case of 2109 // -0.0, which will compare as == to a long 0 cast to a double 2110 // (bug 4162852). 2111 if (multiplier != 1 && gotDouble) { 2112 longResult = (long)doubleResult; 2113 gotDouble = ((doubleResult != (double)longResult) || 2114 (doubleResult == 0.0 && 1/doubleResult < 0.0)) && 2115 !isParseIntegerOnly(); 2116 } 2117 2118 // cast inside of ?: because of binary numeric promotion, JLS 15.25 2119 return gotDouble ? (Number)doubleResult : (Number)longResult; 2120 } 2121 } 2122 2123 /** 2124 * Return a BigInteger multiplier. 2125 */ 2126 private BigInteger getBigIntegerMultiplier() { 2127 if (bigIntegerMultiplier == null) { 2128 bigIntegerMultiplier = BigInteger.valueOf(multiplier); 2129 } 2130 return bigIntegerMultiplier; 2131 } 2132 private transient BigInteger bigIntegerMultiplier; 2133 2134 /** 2135 * Return a BigDecimal multiplier. 2136 */ 2137 private BigDecimal getBigDecimalMultiplier() { 2138 if (bigDecimalMultiplier == null) { 2139 bigDecimalMultiplier = new BigDecimal(multiplier); 2140 } 2141 return bigDecimalMultiplier; 2142 } 2143 private transient BigDecimal bigDecimalMultiplier; 2144 2145 private static final int STATUS_INFINITE = 0; 2146 private static final int STATUS_POSITIVE = 1; 2147 private static final int STATUS_LENGTH = 2; 2148 2149 /** 2150 * Parse the given text into a number. The text is parsed beginning at 2151 * parsePosition, until an unparseable character is seen. 2152 * @param text The string to parse. 2153 * @param parsePosition The position at which to being parsing. Upon 2154 * return, the first unparseable character. 2155 * @param digits The DigitList to set to the parsed value. 2156 * @param isExponent If true, parse an exponent. This means no 2157 * infinite values and integer only. 2158 * @param status Upon return contains boolean status flags indicating 2159 * whether the value was infinite and whether it was positive. 2160 */ 2161 private final boolean subparse(String text, ParsePosition parsePosition, 2162 String positivePrefix, String negativePrefix, 2163 DigitList digits, boolean isExponent, 2164 boolean status[]) { 2165 int position = parsePosition.index; 2166 int oldStart = parsePosition.index; 2167 int backup; 2168 boolean gotPositive, gotNegative; 2169 2170 // check for positivePrefix; take longest 2171 gotPositive = text.regionMatches(position, positivePrefix, 0, 2172 positivePrefix.length()); 2173 gotNegative = text.regionMatches(position, negativePrefix, 0, 2174 negativePrefix.length()); 2175 2176 if (gotPositive && gotNegative) { 2177 if (positivePrefix.length() > negativePrefix.length()) { 2178 gotNegative = false; 2179 } else if (positivePrefix.length() < negativePrefix.length()) { 2180 gotPositive = false; 2181 } 2182 } 2183 2184 if (gotPositive) { 2185 position += positivePrefix.length(); 2186 } else if (gotNegative) { 2187 position += negativePrefix.length(); 2188 } else { 2189 parsePosition.errorIndex = position; 2190 return false; 2191 } 2192 2193 // process digits or Inf, find decimal position 2194 status[STATUS_INFINITE] = false; 2195 if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0, 2196 symbols.getInfinity().length())) { 2197 position += symbols.getInfinity().length(); 2198 status[STATUS_INFINITE] = true; 2199 } else { 2200 // We now have a string of digits, possibly with grouping symbols, 2201 // and decimal points. We want to process these into a DigitList. 2202 // We don‘t want to put a bunch of leading zeros into the DigitList 2203 // though, so we keep track of the location of the decimal point, 2204 // put only significant digits into the DigitList, and adjust the 2205 // exponent as needed. 2206 2207 digits.decimalAt = digits.count = 0; 2208 char zero = symbols.getZeroDigit(); 2209 char decimal = isCurrencyFormat ? 2210 symbols.getMonetaryDecimalSeparator() : 2211 symbols.getDecimalSeparator(); 2212 char grouping = symbols.getGroupingSeparator(); 2213 String exponentString = symbols.getExponentSeparator(); 2214 boolean sawDecimal = false; 2215 boolean sawExponent = false; 2216 boolean sawDigit = false; 2217 int exponent = 0; // Set to the exponent value, if any 2218 2219 // We have to track digitCount ourselves, because digits.count will 2220 // pin when the maximum allowable digits is reached. 2221 int digitCount = 0; 2222 2223 backup = -1; 2224 for (; position < text.length(); ++position) { 2225 char ch = text.charAt(position); 2226 2227 /* We recognize all digit ranges, not only the Latin digit range 2228 * ‘0‘..‘9‘. We do so by using the Character.digit() method, 2229 * which converts a valid Unicode digit to the range 0..9. 2230 * 2231 * The character ‘ch‘ may be a digit. If so, place its value 2232 * from 0 to 9 in ‘digit‘. First try using the locale digit, 2233 * which may or MAY NOT be a standard Unicode digit range. If 2234 * this fails, try using the standard Unicode digit ranges by 2235 * calling Character.digit(). If this also fails, digit will 2236 * have a value outside the range 0..9. 2237 */ 2238 int digit = ch - zero; 2239 if (digit < 0 || digit > 9) { 2240 digit = Character.digit(ch, 10); 2241 } 2242 2243 if (digit == 0) { 2244 // Cancel out backup setting (see grouping handler below) 2245 backup = -1; // Do this BEFORE continue statement below!!! 2246 sawDigit = true; 2247 2248 // Handle leading zeros 2249 if (digits.count == 0) { 2250 // Ignore leading zeros in integer part of number. 2251 if (!sawDecimal) { 2252 continue; 2253 } 2254 2255 // If we have seen the decimal, but no significant 2256 // digits yet, then we account for leading zeros by 2257 // decrementing the digits.decimalAt into negative 2258 // values. 2259 --digits.decimalAt; 2260 } else { 2261 ++digitCount; 2262 digits.append((char)(digit + ‘0‘)); 2263 } 2264 } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above 2265 sawDigit = true; 2266 ++digitCount; 2267 digits.append((char)(digit + ‘0‘)); 2268 2269 // Cancel out backup setting (see grouping handler below) 2270 backup = -1; 2271 } else if (!isExponent && ch == decimal) { 2272 // If we‘re only parsing integers, or if we ALREADY saw the 2273 // decimal, then don‘t parse this one. 2274 if (isParseIntegerOnly() || sawDecimal) { 2275 break; 2276 } 2277 digits.decimalAt = digitCount; // Not digits.count! 2278 sawDecimal = true; 2279 } else if (!isExponent && ch == grouping && isGroupingUsed()) { 2280 if (sawDecimal) { 2281 break; 2282 } 2283 // Ignore grouping characters, if we are using them, but 2284 // require that they be followed by a digit. Otherwise 2285 // we backup and reprocess them. 2286 backup = position; 2287 } else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length()) 2288 && !sawExponent) { 2289 // Process the exponent by recursively calling this method. 2290 ParsePosition pos = new ParsePosition(position + exponentString.length()); 2291 boolean[] stat = new boolean[STATUS_LENGTH]; 2292 DigitList exponentDigits = new DigitList(); 2293 2294 if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) && 2295 exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) { 2296 position = pos.index; // Advance past the exponent 2297 exponent = (int)exponentDigits.getLong(); 2298 if (!stat[STATUS_POSITIVE]) { 2299 exponent = -exponent; 2300 } 2301 sawExponent = true; 2302 } 2303 break; // Whether we fail or succeed, we exit this loop 2304 } else { 2305 break; 2306 } 2307 } 2308 2309 if (backup != -1) { 2310 position = backup; 2311 } 2312 2313 // If there was no decimal point we have an integer 2314 if (!sawDecimal) { 2315 digits.decimalAt = digitCount; // Not digits.count! 2316 } 2317 2318 // Adjust for exponent, if any 2319 digits.decimalAt += exponent; 2320 2321 // If none of the text string was recognized. For example, parse 2322 // "x" with pattern "#0.00" (return index and error index both 0) 2323 // parse "$" with pattern "$#0.00". (return index 0 and error 2324 // index 1). 2325 if (!sawDigit && digitCount == 0) { 2326 parsePosition.index = oldStart; 2327 parsePosition.errorIndex = oldStart; 2328 return false; 2329 } 2330 } 2331 2332 // check for suffix 2333 if (!isExponent) { 2334 if (gotPositive) { 2335 gotPositive = text.regionMatches(position,positiveSuffix,0, 2336 positiveSuffix.length()); 2337 } 2338 if (gotNegative) { 2339 gotNegative = text.regionMatches(position,negativeSuffix,0, 2340 negativeSuffix.length()); 2341 } 2342 2343 // if both match, take longest 2344 if (gotPositive && gotNegative) { 2345 if (positiveSuffix.length() > negativeSuffix.length()) { 2346 gotNegative = false; 2347 } else if (positiveSuffix.length() < negativeSuffix.length()) { 2348 gotPositive = false; 2349 } 2350 } 2351 2352 // fail if neither or both 2353 if (gotPositive == gotNegative) { 2354 parsePosition.errorIndex = position; 2355 return false; 2356 } 2357 2358 parsePosition.index = position + 2359 (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success! 2360 } else { 2361 parsePosition.index = position; 2362 } 2363 2364 status[STATUS_POSITIVE] = gotPositive; 2365 if (parsePosition.index == oldStart) { 2366 parsePosition.errorIndex = position; 2367 return false; 2368 } 2369 return true; 2370 } 2371 2372 /** 2373 * Returns a copy of the decimal format symbols, which is generally not 2374 * changed by the programmer or user. 2375 * @return a copy of the desired DecimalFormatSymbols 2376 * @see java.text.DecimalFormatSymbols 2377 */ 2378 public DecimalFormatSymbols getDecimalFormatSymbols() { 2379 try { 2380 // don‘t allow multiple references 2381 return (DecimalFormatSymbols) symbols.clone(); 2382 } catch (Exception foo) { 2383 return null; // should never happen 2384 } 2385 } 2386 2387 2388 /** 2389 * Sets the decimal format symbols, which is generally not changed 2390 * by the programmer or user. 2391 * @param newSymbols desired DecimalFormatSymbols 2392 * @see java.text.DecimalFormatSymbols 2393 */ 2394 public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) { 2395 try { 2396 // don‘t allow multiple references 2397 symbols = (DecimalFormatSymbols) newSymbols.clone(); 2398 expandAffixes(); 2399 fastPathCheckNeeded = true; 2400 } catch (Exception foo) { 2401 // should never happen 2402 } 2403 } 2404 2405 /** 2406 * Get the positive prefix. 2407 * <P>Examples: +123, $123, sFr123 2408 * 2409 * @return the positive prefix 2410 */ 2411 public String getPositivePrefix () { 2412 return positivePrefix; 2413 } 2414 2415 /** 2416 * Set the positive prefix. 2417 * <P>Examples: +123, $123, sFr123 2418 * 2419 * @param newValue the new positive prefix 2420 */ 2421 public void setPositivePrefix (String newValue) { 2422 positivePrefix = newValue; 2423 posPrefixPattern = null; 2424 positivePrefixFieldPositions = null; 2425 fastPathCheckNeeded = true; 2426 } 2427 2428 /** 2429 * Returns the FieldPositions of the fields in the prefix used for 2430 * positive numbers. This is not used if the user has explicitly set 2431 * a positive prefix via <code>setPositivePrefix</code>. This is 2432 * lazily created. 2433 * 2434 * @return FieldPositions in positive prefix 2435 */ 2436 private FieldPosition[] getPositivePrefixFieldPositions() { 2437 if (positivePrefixFieldPositions == null) { 2438 if (posPrefixPattern != null) { 2439 positivePrefixFieldPositions = expandAffix(posPrefixPattern); 2440 } else { 2441 positivePrefixFieldPositions = EmptyFieldPositionArray; 2442 } 2443 } 2444 return positivePrefixFieldPositions; 2445 } 2446 2447 /** 2448 * Get the negative prefix. 2449 * <P>Examples: -123, ($123) (with negative suffix), sFr-123 2450 * 2451 * @return the negative prefix 2452 */ 2453 public String getNegativePrefix () { 2454 return negativePrefix; 2455 } 2456 2457 /** 2458 * Set the negative prefix. 2459 * <P>Examples: -123, ($123) (with negative suffix), sFr-123 2460 * 2461 * @param newValue the new negative prefix 2462 */ 2463 public void setNegativePrefix (String newValue) { 2464 negativePrefix = newValue; 2465 negPrefixPattern = null; 2466 fastPathCheckNeeded = true; 2467 } 2468 2469 /** 2470 * Returns the FieldPositions of the fields in the prefix used for 2471 * negative numbers. This is not used if the user has explicitly set 2472 * a negative prefix via <code>setNegativePrefix</code>. This is 2473 * lazily created. 2474 * 2475 * @return FieldPositions in positive prefix 2476 */ 2477 private FieldPosition[] getNegativePrefixFieldPositions() { 2478 if (negativePrefixFieldPositions == null) { 2479 if (negPrefixPattern != null) { 2480 negativePrefixFieldPositions = expandAffix(negPrefixPattern); 2481 } else { 2482 negativePrefixFieldPositions = EmptyFieldPositionArray; 2483 } 2484 } 2485 return negativePrefixFieldPositions; 2486 } 2487 2488 /** 2489 * Get the positive suffix. 2490 * <P>Example: 123% 2491 * 2492 * @return the positive suffix 2493 */ 2494 public String getPositiveSuffix () { 2495 return positiveSuffix; 2496 } 2497 2498 /** 2499 * Set the positive suffix. 2500 * <P>Example: 123% 2501 * 2502 * @param newValue the new positive suffix 2503 */ 2504 public void setPositiveSuffix (String newValue) { 2505 positiveSuffix = newValue; 2506 posSuffixPattern = null; 2507 fastPathCheckNeeded = true; 2508 } 2509 2510 /** 2511 * Returns the FieldPositions of the fields in the suffix used for 2512 * positive numbers. This is not used if the user has explicitly set 2513 * a positive suffix via <code>setPositiveSuffix</code>. This is 2514 * lazily created. 2515 * 2516 * @return FieldPositions in positive prefix 2517 */ 2518 private FieldPosition[] getPositiveSuffixFieldPositions() { 2519 if (positiveSuffixFieldPositions == null) { 2520 if (posSuffixPattern != null) { 2521 positiveSuffixFieldPositions = expandAffix(posSuffixPattern); 2522 } else { 2523 positiveSuffixFieldPositions = EmptyFieldPositionArray; 2524 } 2525 } 2526 return positiveSuffixFieldPositions; 2527 } 2528 2529 /** 2530 * Get the negative suffix. 2531 * <P>Examples: -123%, ($123) (with positive suffixes) 2532 * 2533 * @return the negative suffix 2534 */ 2535 public String getNegativeSuffix () { 2536 return negativeSuffix; 2537 } 2538 2539 /** 2540 * Set the negative suffix. 2541 * <P>Examples: 123% 2542 * 2543 * @param newValue the new negative suffix 2544 */ 2545 public void setNegativeSuffix (String newValue) { 2546 negativeSuffix = newValue; 2547 negSuffixPattern = null; 2548 fastPathCheckNeeded = true; 2549 } 2550 2551 /** 2552 * Returns the FieldPositions of the fields in the suffix used for 2553 * negative numbers. This is not used if the user has explicitly set 2554 * a negative suffix via <code>setNegativeSuffix</code>. This is 2555 * lazily created. 2556 * 2557 * @return FieldPositions in positive prefix 2558 */ 2559 private FieldPosition[] getNegativeSuffixFieldPositions() { 2560 if (negativeSuffixFieldPositions == null) { 2561 if (negSuffixPattern != null) { 2562 negativeSuffixFieldPositions = expandAffix(negSuffixPattern); 2563 } else { 2564 negativeSuffixFieldPositions = EmptyFieldPositionArray; 2565 } 2566 } 2567 return negativeSuffixFieldPositions; 2568 } 2569 2570 /** 2571 * Gets the multiplier for use in percent, per mille, and similar 2572 * formats. 2573 * 2574 * @return the multiplier 2575 * @see #setMultiplier(int) 2576 */ 2577 public int getMultiplier () { 2578 return multiplier; 2579 } 2580 2581 /** 2582 * Sets the multiplier for use in percent, per mille, and similar 2583 * formats. 2584 * For a percent format, set the multiplier to 100 and the suffixes to 2585 * have ‘%‘ (for Arabic, use the Arabic percent sign). 2586 * For a per mille format, set the multiplier to 1000 and the suffixes to 2587 * have ‘\u2030‘. 2588 * 2589 * <P>Example: with multiplier 100, 1.23 is formatted as "123", and 2590 * "123" is parsed into 1.23. 2591 * 2592 * @param newValue the new multiplier 2593 * @see #getMultiplier 2594 */ 2595 public void setMultiplier (int newValue) { 2596 multiplier = newValue; 2597 bigDecimalMultiplier = null; 2598 bigIntegerMultiplier = null; 2599 fastPathCheckNeeded = true; 2600 } 2601 2602 /** 2603 * {@inheritDoc} 2604 */ 2605 @Override 2606 public void setGroupingUsed(boolean newValue) { 2607 super.setGroupingUsed(newValue); 2608 fastPathCheckNeeded = true; 2609 } 2610 2611 /** 2612 * Return the grouping size. Grouping size is the number of digits between 2613 * grouping separators in the integer portion of a number. For example, 2614 * in the number "123,456.78", the grouping size is 3. 2615 * 2616 * @return the grouping size 2617 * @see #setGroupingSize 2618 * @see java.text.NumberFormat#isGroupingUsed 2619 * @see java.text.DecimalFormatSymbols#getGroupingSeparator 2620 */ 2621 public int getGroupingSize () { 2622 return groupingSize; 2623 } 2624 2625 /** 2626 * Set the grouping size. Grouping size is the number of digits between 2627 * grouping separators in the integer portion of a number. For example, 2628 * in the number "123,456.78", the grouping size is 3. 2629 * <br> 2630 * The value passed in is converted to a byte, which may lose information. 2631 * 2632 * @param newValue the new grouping size 2633 * @see #getGroupingSize 2634 * @see java.text.NumberFormat#setGroupingUsed 2635 * @see java.text.DecimalFormatSymbols#setGroupingSeparator 2636 */ 2637 public void setGroupingSize (int newValue) { 2638 groupingSize = (byte)newValue; 2639 fastPathCheckNeeded = true; 2640 } 2641 2642 /** 2643 * Allows you to get the behavior of the decimal separator with integers. 2644 * (The decimal separator will always appear with decimals.) 2645 * <P>Example: Decimal ON: 12345 → 12345.; OFF: 12345 → 12345 2646 * 2647 * @return {@code true} if the decimal separator is always shown; 2648 * {@code false} otherwise 2649 */ 2650 public boolean isDecimalSeparatorAlwaysShown() { 2651 return decimalSeparatorAlwaysShown; 2652 } 2653 2654 /** 2655 * Allows you to set the behavior of the decimal separator with integers. 2656 * (The decimal separator will always appear with decimals.) 2657 * <P>Example: Decimal ON: 12345 → 12345.; OFF: 12345 → 12345 2658 * 2659 * @param newValue {@code true} if the decimal separator is always shown; 2660 * {@code false} otherwise 2661 */ 2662 public void setDecimalSeparatorAlwaysShown(boolean newValue) { 2663 decimalSeparatorAlwaysShown = newValue; 2664 fastPathCheckNeeded = true; 2665 } 2666 2667 /** 2668 * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)} 2669 * method returns <code>BigDecimal</code>. The default value is false. 2670 * 2671 * @return {@code true} if the parse method returns BigDecimal; 2672 * {@code false} otherwise 2673 * @see #setParseBigDecimal 2674 * @since 1.5 2675 */ 2676 public boolean isParseBigDecimal() { 2677 return parseBigDecimal; 2678 } 2679 2680 /** 2681 * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)} 2682 * method returns <code>BigDecimal</code>. 2683 * 2684 * @param newValue {@code true} if the parse method returns BigDecimal; 2685 * {@code false} otherwise 2686 * @see #isParseBigDecimal 2687 * @since 1.5 2688 */ 2689 public void setParseBigDecimal(boolean newValue) { 2690 parseBigDecimal = newValue; 2691 } 2692 2693 /** 2694 * Standard override; no change in semantics. 2695 */ 2696 @Override 2697 public Object clone() { 2698 DecimalFormat other = (DecimalFormat) super.clone(); 2699 other.symbols = (DecimalFormatSymbols) symbols.clone(); 2700 other.digitList = (DigitList) digitList.clone(); 2701 2702 // Fast-path is almost stateless algorithm. The only logical state is the 2703 // isFastPath flag. In addition fastPathCheckNeeded is a sentinel flag 2704 // that forces recalculation of all fast-path fields when set to true. 2705 // 2706 // There is thus no need to clone all the fast-path fields. 2707 // We just only need to set fastPathCheckNeeded to true when cloning, 2708 // and init fastPathData to null as if it were a truly new instance. 2709 // Every fast-path field will be recalculated (only once) at next usage of 2710 // fast-path algorithm. 2711 other.fastPathCheckNeeded = true; 2712 other.isFastPath = false; 2713 other.fastPathData = null; 2714 2715 return other; 2716 } 2717 2718 /** 2719 * Overrides equals 2720 */ 2721 @Override 2722 public boolean equals(Object obj) 2723 { 2724 if (obj == null) 2725 return false; 2726 if (!super.equals(obj)) 2727 return false; // super does class check 2728 DecimalFormat other = (DecimalFormat) obj; 2729 return ((posPrefixPattern == other.posPrefixPattern && 2730 positivePrefix.equals(other.positivePrefix)) 2731 || (posPrefixPattern != null && 2732 posPrefixPattern.equals(other.posPrefixPattern))) 2733 && ((posSuffixPattern == other.posSuffixPattern && 2734 positiveSuffix.equals(other.positiveSuffix)) 2735 || (posSuffixPattern != null && 2736 posSuffixPattern.equals(other.posSuffixPattern))) 2737 && ((negPrefixPattern == other.negPrefixPattern && 2738 negativePrefix.equals(other.negativePrefix)) 2739 || (negPrefixPattern != null && 2740 negPrefixPattern.equals(other.negPrefixPattern))) 2741 && ((negSuffixPattern == other.negSuffixPattern && 2742 negativeSuffix.equals(other.negativeSuffix)) 2743 || (negSuffixPattern != null && 2744 negSuffixPattern.equals(other.negSuffixPattern))) 2745 && multiplier == other.multiplier 2746 && groupingSize == other.groupingSize 2747 && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown 2748 && parseBigDecimal == other.parseBigDecimal 2749 && useExponentialNotation == other.useExponentialNotation 2750 && (!useExponentialNotation || 2751 minExponentDigits == other.minExponentDigits) 2752 && maximumIntegerDigits == other.maximumIntegerDigits 2753 && minimumIntegerDigits == other.minimumIntegerDigits 2754 && maximumFractionDigits == other.maximumFractionDigits 2755 && minimumFractionDigits == other.minimumFractionDigits 2756 && roundingMode == other.roundingMode 2757 && symbols.equals(other.symbols); 2758 } 2759 2760 /** 2761 * Overrides hashCode 2762 */ 2763 @Override 2764 public int hashCode() { 2765 return super.hashCode() * 37 + positivePrefix.hashCode(); 2766 // just enough fields for a reasonable distribution 2767 } 2768 2769 /** 2770 * Synthesizes a pattern string that represents the current state 2771 * of this Format object. 2772 * 2773 * @return a pattern string 2774 * @see #applyPattern 2775 */ 2776 public String toPattern() { 2777 return toPattern( false ); 2778 } 2779 2780 /** 2781 * Synthesizes a localized pattern string that represents the current 2782 * state of this Format object. 2783 * 2784 * @return a localized pattern string 2785 * @see #applyPattern 2786 */ 2787 public String toLocalizedPattern() { 2788 return toPattern( true ); 2789 } 2790 2791 /** 2792 * Expand the affix pattern strings into the expanded affix strings. If any 2793 * affix pattern string is null, do not expand it. This method should be 2794 * called any time the symbols or the affix patterns change in order to keep 2795 * the expanded affix strings up to date. 2796 */ 2797 private void expandAffixes() { 2798 // Reuse one StringBuffer for better performance 2799 StringBuffer buffer = new StringBuffer(); 2800 if (posPrefixPattern != null) { 2801 positivePrefix = expandAffix(posPrefixPattern, buffer); 2802 positivePrefixFieldPositions = null; 2803 } 2804 if (posSuffixPattern != null) { 2805 positiveSuffix = expandAffix(posSuffixPattern, buffer); 2806 positiveSuffixFieldPositions = null; 2807 } 2808 if (negPrefixPattern != null) { 2809 negativePrefix = expandAffix(negPrefixPattern, buffer); 2810 negativePrefixFieldPositions = null; 2811 } 2812 if (negSuffixPattern != null) { 2813 negativeSuffix = expandAffix(negSuffixPattern, buffer); 2814 negativeSuffixFieldPositions = null; 2815 } 2816 } 2817 2818 /** 2819 * Expand an affix pattern into an affix string. All characters in the 2820 * pattern are literal unless prefixed by QUOTE. The following characters 2821 * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE, 2822 * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE + 2823 * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217 2824 * currency code. Any other character after a QUOTE represents itself. 2825 * QUOTE must be followed by another character; QUOTE may not occur by 2826 * itself at the end of the pattern. 2827 * 2828 * @param pattern the non-null, possibly empty pattern 2829 * @param buffer a scratch StringBuffer; its contents will be lost 2830 * @return the expanded equivalent of pattern 2831 */ 2832 private String expandAffix(String pattern, StringBuffer buffer) { 2833 buffer.setLength(0); 2834 for (int i=0; i<pattern.length(); ) { 2835 char c = pattern.charAt(i++); 2836 if (c == QUOTE) { 2837 c = pattern.charAt(i++); 2838 switch (c) { 2839 case CURRENCY_SIGN: 2840 if (i<pattern.length() && 2841 pattern.charAt(i) == CURRENCY_SIGN) { 2842 ++i; 2843 buffer.append(symbols.getInternationalCurrencySymbol()); 2844 } else { 2845 buffer.append(symbols.getCurrencySymbol()); 2846 } 2847 continue; 2848 case PATTERN_PERCENT: 2849 c = symbols.getPercent(); 2850 break; 2851 case PATTERN_PER_MILLE: 2852 c = symbols.getPerMill(); 2853 break; 2854 case PATTERN_MINUS: 2855 c = symbols.getMinusSign(); 2856 break; 2857 } 2858 } 2859 buffer.append(c); 2860 } 2861 return buffer.toString(); 2862 } 2863 2864 /** 2865 * Expand an affix pattern into an array of FieldPositions describing 2866 * how the pattern would be expanded. 2867 * All characters in the 2868 * pattern are literal unless prefixed by QUOTE. The following characters 2869 * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE, 2870 * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE + 2871 * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217 2872 * currency code. Any other character after a QUOTE represents itself. 2873 * QUOTE must be followed by another character; QUOTE may not occur by 2874 * itself at the end of the pattern. 2875 * 2876 * @param pattern the non-null, possibly empty pattern 2877 * @return FieldPosition array of the resulting fields. 2878 */ 2879 private FieldPosition[] expandAffix(String pattern) { 2880 ArrayList<FieldPosition> positions = null; 2881 int stringIndex = 0; 2882 for (int i=0; i<pattern.length(); ) { 2883 char c = pattern.charAt(i++); 2884 if (c == QUOTE) { 2885 int field = -1; 2886 Format.Field fieldID = null; 2887 c = pattern.charAt(i++); 2888 switch (c) { 2889 case CURRENCY_SIGN: 2890 String string; 2891 if (i<pattern.length() && 2892 pattern.charAt(i) == CURRENCY_SIGN) { 2893 ++i; 2894 string = symbols.getInternationalCurrencySymbol(); 2895 } else { 2896 string = symbols.getCurrencySymbol(); 2897 } 2898 if (string.length() > 0) { 2899 if (positions == null) { 2900 positions = new ArrayList<>(2); 2901 } 2902 FieldPosition fp = new FieldPosition(Field.CURRENCY); 2903 fp.setBeginIndex(stringIndex); 2904 fp.setEndIndex(stringIndex + string.length()); 2905 positions.add(fp); 2906 stringIndex += string.length(); 2907 } 2908 continue; 2909 case PATTERN_PERCENT: 2910 c = symbols.getPercent(); 2911 field = -1; 2912 fieldID = Field.PERCENT; 2913 break; 2914 case PATTERN_PER_MILLE: 2915 c = symbols.getPerMill(); 2916 field = -1; 2917 fieldID = Field.PERMILLE; 2918 break; 2919 case PATTERN_MINUS: 2920 c = symbols.getMinusSign(); 2921 field = -1; 2922 fieldID = Field.SIGN; 2923 break; 2924 } 2925 if (fieldID != null) { 2926 if (positions == null) { 2927 positions = new ArrayList<>(2); 2928 } 2929 FieldPosition fp = new FieldPosition(fieldID, field); 2930 fp.setBeginIndex(stringIndex); 2931 fp.setEndIndex(stringIndex + 1); 2932 positions.add(fp); 2933 } 2934 } 2935 stringIndex++; 2936 } 2937 if (positions != null) { 2938 return positions.toArray(EmptyFieldPositionArray); 2939 } 2940 return EmptyFieldPositionArray; 2941 } 2942 2943 /** 2944 * Appends an affix pattern to the given StringBuffer, quoting special 2945 * characters as needed. Uses the internal affix pattern, if that exists, 2946 * or the literal affix, if the internal affix pattern is null. The 2947 * appended string will generate the same affix pattern (or literal affix) 2948 * when passed to toPattern(). 2949 * 2950 * @param buffer the affix string is appended to this 2951 * @param affixPattern a pattern such as posPrefixPattern; may be null 2952 * @param expAffix a corresponding expanded affix, such as positivePrefix. 2953 * Ignored unless affixPattern is null. If affixPattern is null, then 2954 * expAffix is appended as a literal affix. 2955 * @param localized true if the appended pattern should contain localized 2956 * pattern characters; otherwise, non-localized pattern chars are appended 2957 */ 2958 private void appendAffix(StringBuffer buffer, String affixPattern, 2959 String expAffix, boolean localized) { 2960 if (affixPattern == null) { 2961 appendAffix(buffer, expAffix, localized); 2962 } else { 2963 int i; 2964 for (int pos=0; pos<affixPattern.length(); pos=i) { 2965 i = affixPattern.indexOf(QUOTE, pos); 2966 if (i < 0) { 2967 appendAffix(buffer, affixPattern.substring(pos), localized); 2968 break; 2969 } 2970 if (i > pos) { 2971 appendAffix(buffer, affixPattern.substring(pos, i), localized); 2972 } 2973 char c = affixPattern.charAt(++i); 2974 ++i; 2975 if (c == QUOTE) { 2976 buffer.append(c); 2977 // Fall through and append another QUOTE below 2978 } else if (c == CURRENCY_SIGN && 2979 i<affixPattern.length() && 2980 affixPattern.charAt(i) == CURRENCY_SIGN) { 2981 ++i; 2982 buffer.append(c); 2983 // Fall through and append another CURRENCY_SIGN below 2984 } else if (localized) { 2985 switch (c) { 2986 case PATTERN_PERCENT: 2987 c = symbols.getPercent(); 2988 break; 2989 case PATTERN_PER_MILLE: 2990 c = symbols.getPerMill(); 2991 break; 2992 case PATTERN_MINUS: 2993 c = symbols.getMinusSign(); 2994 break; 2995 } 2996 } 2997 buffer.append(c); 2998 } 2999 } 3000 } 3001 3002 /** 3003 * Append an affix to the given StringBuffer, using quotes if 3004 * there are special characters. Single quotes themselves must be 3005 * escaped in either case. 3006 */ 3007 private void appendAffix(StringBuffer buffer, String affix, boolean localized) { 3008 boolean needQuote; 3009 if (localized) { 3010 needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0 3011 || affix.indexOf(symbols.getGroupingSeparator()) >= 0 3012 || affix.indexOf(symbols.getDecimalSeparator()) >= 0 3013 || affix.indexOf(symbols.getPercent()) >= 0 3014 || affix.indexOf(symbols.getPerMill()) >= 0 3015 || affix.indexOf(symbols.getDigit()) >= 0 3016 || affix.indexOf(symbols.getPatternSeparator()) >= 0 3017 || affix.indexOf(symbols.getMinusSign()) >= 0 3018 || affix.indexOf(CURRENCY_SIGN) >= 0; 3019 } else { 3020 needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0 3021 || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0 3022 || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0 3023 || affix.indexOf(PATTERN_PERCENT) >= 0 3024 || affix.indexOf(PATTERN_PER_MILLE) >= 0 3025 || affix.indexOf(PATTERN_DIGIT) >= 0 3026 || affix.indexOf(PATTERN_SEPARATOR) >= 0 3027 || affix.indexOf(PATTERN_MINUS) >= 0 3028 || affix.indexOf(CURRENCY_SIGN) >= 0; 3029 } 3030 if (needQuote) buffer.append(‘‘‘); 3031 if (affix.indexOf(‘‘‘) < 0) buffer.append(affix); 3032 else { 3033 for (int j=0; j<affix.length(); ++j) { 3034 char c = affix.charAt(j); 3035 buffer.append(c); 3036 if (c == ‘‘‘) buffer.append(c); 3037 } 3038 } 3039 if (needQuote) buffer.append(‘‘‘); 3040 } 3041 3042 /** 3043 * Does the real work of generating a pattern. */ 3044 private String toPattern(boolean localized) { 3045 StringBuffer result = new StringBuffer(); 3046 for (int j = 1; j >= 0; --j) { 3047 if (j == 1) 3048 appendAffix(result, posPrefixPattern, positivePrefix, localized); 3049 else appendAffix(result, negPrefixPattern, negativePrefix, localized); 3050 int i; 3051 int digitCount = useExponentialNotation 3052 ? getMaximumIntegerDigits() 3053 : Math.max(groupingSize, getMinimumIntegerDigits())+1; 3054 for (i = digitCount; i > 0; --i) { 3055 if (i != digitCount && isGroupingUsed() && groupingSize != 0 && 3056 i % groupingSize == 0) { 3057 result.append(localized ? symbols.getGroupingSeparator() : 3058 PATTERN_GROUPING_SEPARATOR); 3059 } 3060 result.append(i <= getMinimumIntegerDigits() 3061 ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT) 3062 : (localized ? symbols.getDigit() : PATTERN_DIGIT)); 3063 } 3064 if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown) 3065 result.append(localized ? symbols.getDecimalSeparator() : 3066 PATTERN_DECIMAL_SEPARATOR); 3067 for (i = 0; i < getMaximumFractionDigits(); ++i) { 3068 if (i < getMinimumFractionDigits()) { 3069 result.append(localized ? symbols.getZeroDigit() : 3070 PATTERN_ZERO_DIGIT); 3071 } else { 3072 result.append(localized ? symbols.getDigit() : 3073 PATTERN_DIGIT); 3074 } 3075 } 3076 if (useExponentialNotation) 3077 { 3078 result.append(localized ? symbols.getExponentSeparator() : 3079 PATTERN_EXPONENT); 3080 for (i=0; i<minExponentDigits; ++i) 3081 result.append(localized ? symbols.getZeroDigit() : 3082 PATTERN_ZERO_DIGIT); 3083 } 3084 if (j == 1) { 3085 appendAffix(result, posSuffixPattern, positiveSuffix, localized); 3086 if ((negSuffixPattern == posSuffixPattern && // n == p == null 3087 negativeSuffix.equals(positiveSuffix)) 3088 || (negSuffixPattern != null && 3089 negSuffixPattern.equals(posSuffixPattern))) { 3090 if ((negPrefixPattern != null && posPrefixPattern != null && 3091 negPrefixPattern.equals("‘-" + posPrefixPattern)) || 3092 (negPrefixPattern == posPrefixPattern && // n == p == null 3093 negativePrefix.equals(symbols.getMinusSign() + positivePrefix))) 3094 break; 3095 } 3096 result.append(localized ? symbols.getPatternSeparator() : 3097 PATTERN_SEPARATOR); 3098 } else appendAffix(result, negSuffixPattern, negativeSuffix, localized); 3099 } 3100 return result.toString(); 3101 } 3102 3103 /** 3104 * Apply the given pattern to this Format object. A pattern is a 3105 * short-hand specification for the various formatting properties. 3106 * These properties can also be changed individually through the 3107 * various setter methods. 3108 * <p> 3109 * There is no limit to integer digits set 3110 * by this routine, since that is the typical end-user desire; 3111 * use setMaximumInteger if you want to set a real value. 3112 * For negative numbers, use a second pattern, separated by a semicolon 3113 * <P>Example <code>"#,#00.0#"</code> → 1,234.56 3114 * <P>This means a minimum of 2 integer digits, 1 fraction digit, and 3115 * a maximum of 2 fraction digits. 3116 * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in 3117 * parentheses. 3118 * <p>In negative patterns, the minimum and maximum counts are ignored; 3119 * these are presumed to be set in the positive pattern. 3120 * 3121 * @param pattern a new pattern 3122 * @exception NullPointerException if <code>pattern</code> is null 3123 * @exception IllegalArgumentException if the given pattern is invalid. 3124 */ 3125 public void applyPattern(String pattern) { 3126 applyPattern(pattern, false); 3127 } 3128 3129 /** 3130 * Apply the given pattern to this Format object. The pattern 3131 * is assumed to be in a localized notation. A pattern is a 3132 * short-hand specification for the various formatting properties. 3133 * These properties can also be changed individually through the 3134 * various setter methods. 3135 * <p> 3136 * There is no limit to integer digits set 3137 * by this routine, since that is the typical end-user desire; 3138 * use setMaximumInteger if you want to set a real value. 3139 * For negative numbers, use a second pattern, separated by a semicolon 3140 * <P>Example <code>"#,#00.0#"</code> → 1,234.56 3141 * <P>This means a minimum of 2 integer digits, 1 fraction digit, and 3142 * a maximum of 2 fraction digits. 3143 * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in 3144 * parentheses. 3145 * <p>In negative patterns, the minimum and maximum counts are ignored; 3146 * these are presumed to be set in the positive pattern. 3147 * 3148 * @param pattern a new pattern 3149 * @exception NullPointerException if <code>pattern</code> is null 3150 * @exception IllegalArgumentException if the given pattern is invalid. 3151 */ 3152 public void applyLocalizedPattern(String pattern) { 3153 applyPattern(pattern, true); 3154 } 3155 3156 /** 3157 * Does the real work of applying a pattern. 3158 */ 3159 private void applyPattern(String pattern, boolean localized) { 3160 char zeroDigit = PATTERN_ZERO_DIGIT; 3161 char groupingSeparator = PATTERN_GROUPING_SEPARATOR; 3162 char decimalSeparator = PATTERN_DECIMAL_SEPARATOR; 3163 char percent = PATTERN_PERCENT; 3164 char perMill = PATTERN_PER_MILLE; 3165 char digit = PATTERN_DIGIT; 3166 char separator = PATTERN_SEPARATOR; 3167 String exponent = PATTERN_EXPONENT; 3168 char minus = PATTERN_MINUS; 3169 if (localized) { 3170 zeroDigit = symbols.getZeroDigit(); 3171 groupingSeparator = symbols.getGroupingSeparator(); 3172 decimalSeparator = symbols.getDecimalSeparator(); 3173 percent = symbols.getPercent(); 3174 perMill = symbols.getPerMill(); 3175 digit = symbols.getDigit(); 3176 separator = symbols.getPatternSeparator(); 3177 exponent = symbols.getExponentSeparator(); 3178 minus = symbols.getMinusSign(); 3179 } 3180 boolean gotNegative = false; 3181 decimalSeparatorAlwaysShown = false; 3182 isCurrencyFormat = false; 3183 useExponentialNotation = false; 3184 3185 // Two variables are used to record the subrange of the pattern 3186 // occupied by phase 1. This is used during the processing of the 3187 // second pattern (the one representing negative numbers) to ensure 3188 // that no deviation exists in phase 1 between the two patterns. 3189 int phaseOneStart = 0; 3190 int phaseOneLength = 0; 3191 3192 int start = 0; 3193 for (int j = 1; j >= 0 && start < pattern.length(); --j) { 3194 boolean inQuote = false; 3195 StringBuffer prefix = new StringBuffer(); 3196 StringBuffer suffix = new StringBuffer(); 3197 int decimalPos = -1; 3198 int multiplier = 1; 3199 int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0; 3200 byte groupingCount = -1; 3201 3202 // The phase ranges from 0 to 2. Phase 0 is the prefix. Phase 1 is 3203 // the section of the pattern with digits, decimal separator, 3204 // grouping characters. Phase 2 is the suffix. In phases 0 and 2, 3205 // percent, per mille, and currency symbols are recognized and 3206 // translated. The separation of the characters into phases is 3207 // strictly enforced; if phase 1 characters are to appear in the 3208 // suffix, for example, they must be quoted. 3209 int phase = 0; 3210 3211 // The affix is either the prefix or the suffix. 3212 StringBuffer affix = prefix; 3213 3214 for (int pos = start; pos < pattern.length(); ++pos) { 3215 char ch = pattern.charAt(pos); 3216 switch (phase) { 3217 case 0: 3218 case 2: 3219 // Process the prefix / suffix characters 3220 if (inQuote) { 3221 // A quote within quotes indicates either the closing 3222 // quote or two quotes, which is a quote literal. That 3223 // is, we have the second quote in ‘do‘ or ‘don‘‘t‘. 3224 if (ch == QUOTE) { 3225 if ((pos+1) < pattern.length() && 3226 pattern.charAt(pos+1) == QUOTE) { 3227 ++pos; 3228 affix.append("‘‘"); // ‘don‘‘t‘ 3229 } else { 3230 inQuote = false; // ‘do‘ 3231 } 3232 continue; 3233 } 3234 } else { 3235 // Process unquoted characters seen in prefix or suffix 3236 // phase. 3237 if (ch == digit || 3238 ch == zeroDigit || 3239 ch == groupingSeparator || 3240 ch == decimalSeparator) { 3241 phase = 1; 3242 if (j == 1) { 3243 phaseOneStart = pos; 3244 } 3245 --pos; // Reprocess this character 3246 continue; 3247 } else if (ch == CURRENCY_SIGN) { 3248 // Use lookahead to determine if the currency sign 3249 // is doubled or not. 3250 boolean doubled = (pos + 1) < pattern.length() && 3251 pattern.charAt(pos + 1) == CURRENCY_SIGN; 3252 if (doubled) { // Skip over the doubled character 3253 ++pos; 3254 } 3255 isCurrencyFormat = true; 3256 affix.append(doubled ? "‘u00A4u00A4" : "‘u00A4"); 3257 continue; 3258 } else if (ch == QUOTE) { 3259 // A quote outside quotes indicates either the 3260 // opening quote or two quotes, which is a quote 3261 // literal. That is, we have the first quote in ‘do‘ 3262 // or o‘‘clock. 3263 if (ch == QUOTE) { 3264 if ((pos+1) < pattern.length() && 3265 pattern.charAt(pos+1) == QUOTE) { 3266 ++pos; 3267 affix.append("‘‘"); // o‘‘clock 3268 } else { 3269 inQuote = true; // ‘do‘ 3270 } 3271 continue; 3272 } 3273 } else if (ch == separator) { 3274 // Don‘t allow separators before we see digit 3275 // characters of phase 1, and don‘t allow separators 3276 // in the second pattern (j == 0). 3277 if (phase == 0 || j == 0) { 3278 throw new IllegalArgumentException("Unquoted special character ‘" + 3279 ch + "‘ in pattern "" + pattern + ‘"‘); 3280 } 3281 start = pos + 1; 3282 pos = pattern.length(); 3283 continue; 3284 } 3285 3286 // Next handle characters which are appended directly. 3287 else if (ch == percent) { 3288 if (multiplier != 1) { 3289 throw new IllegalArgumentException("Too many percent/per mille characters in pattern "" + 3290 pattern + ‘"‘); 3291 } 3292 multiplier = 100; 3293 affix.append("‘%"); 3294 continue; 3295 } else if (ch == perMill) { 3296 if (multiplier != 1) { 3297 throw new IllegalArgumentException("Too many percent/per mille characters in pattern "" + 3298 pattern + ‘"‘); 3299 } 3300 multiplier = 1000; 3301 affix.append("‘u2030"); 3302 continue; 3303 } else if (ch == minus) { 3304 affix.append("‘-"); 3305 continue; 3306 } 3307 } 3308 // Note that if we are within quotes, or if this is an 3309 // unquoted, non-special character, then we usually fall 3310 // through to here. 3311 affix.append(ch); 3312 break; 3313 3314 case 1: 3315 // Phase one must be identical in the two sub-patterns. We 3316 // enforce this by doing a direct comparison. While 3317 // processing the first sub-pattern, we just record its 3318 // length. While processing the second, we compare 3319 // characters. 3320 if (j == 1) { 3321 ++phaseOneLength; 3322 } else { 3323 if (--phaseOneLength == 0) { 3324 phase = 2; 3325 affix = suffix; 3326 } 3327 continue; 3328 } 3329 3330 // Process the digits, decimal, and grouping characters. We 3331 // record five pieces of information. We expect the digits 3332 // to occur in the pattern ####0000.####, and we record the 3333 // number of left digits, zero (central) digits, and right 3334 // digits. The position of the last grouping character is 3335 // recorded (should be somewhere within the first two blocks 3336 // of characters), as is the position of the decimal point, 3337 // if any (should be in the zero digits). If there is no 3338 // decimal point, then there should be no right digits. 3339 if (ch == digit) { 3340 if (zeroDigitCount > 0) { 3341 ++digitRightCount; 3342 } else { 3343 ++digitLeftCount; 3344 } 3345 if (groupingCount >= 0 && decimalPos < 0) { 3346 ++groupingCount; 3347 } 3348 } else if (ch == zeroDigit) { 3349 if (digitRightCount > 0) { 3350 throw new IllegalArgumentException("Unexpected ‘0‘ in pattern "" + 3351 pattern + ‘"‘); 3352 } 3353 ++zeroDigitCount; 3354 if (groupingCount >= 0 && decimalPos < 0) { 3355 ++groupingCount; 3356 } 3357 } else if (ch == groupingSeparator) { 3358 groupingCount = 0; 3359 } else if (ch == decimalSeparator) { 3360 if (decimalPos >= 0) { 3361 throw new IllegalArgumentException("Multiple decimal separators in pattern "" + 3362 pattern + ‘"‘); 3363 } 3364 decimalPos = digitLeftCount + zeroDigitCount + digitRightCount; 3365 } else if (pattern.regionMatches(pos, exponent, 0, exponent.length())){ 3366 if (useExponentialNotation) { 3367 throw new IllegalArgumentException("Multiple exponential " + 3368 "symbols in pattern "" + pattern + ‘"‘); 3369 } 3370 useExponentialNotation = true; 3371 minExponentDigits = 0; 3372 3373 // Use lookahead to parse out the exponential part 3374 // of the pattern, then jump into phase 2. 3375 pos = pos+exponent.length(); 3376 while (pos < pattern.length() && 3377 pattern.charAt(pos) == zeroDigit) { 3378 ++minExponentDigits; 3379 ++phaseOneLength; 3380 ++pos; 3381 } 3382 3383 if ((digitLeftCount + zeroDigitCount) < 1 || 3384 minExponentDigits < 1) { 3385 throw new IllegalArgumentException("Malformed exponential " + 3386 "pattern "" + pattern + ‘"‘); 3387 } 3388 3389 // Transition to phase 2 3390 phase = 2; 3391 affix = suffix; 3392 --pos; 3393 continue; 3394 } else { 3395 phase = 2; 3396 affix = suffix; 3397 --pos; 3398 --phaseOneLength; 3399 continue; 3400 } 3401 break; 3402 } 3403 } 3404 3405 // Handle patterns with no ‘0‘ pattern character. These patterns 3406 // are legal, but must be interpreted. "##.###" -> "#0.###". 3407 // ".###" -> ".0##". 3408 /* We allow patterns of the form "####" to produce a zeroDigitCount 3409 * of zero (got that?); although this seems like it might make it 3410 * possible for format() to produce empty strings, format() checks 3411 * for this condition and outputs a zero digit in this situation. 3412 * Having a zeroDigitCount of zero yields a minimum integer digits 3413 * of zero, which allows proper round-trip patterns. That is, we 3414 * don‘t want "#" to become "#0" when toPattern() is called (even 3415 * though that‘s what it really is, semantically). 3416 */ 3417 if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) { 3418 // Handle "###.###" and "###." and ".###" 3419 int n = decimalPos; 3420 if (n == 0) { // Handle ".###" 3421 ++n; 3422 } 3423 digitRightCount = digitLeftCount - n; 3424 digitLeftCount = n - 1; 3425 zeroDigitCount = 1; 3426 } 3427 3428 // Do syntax checking on the digits. 3429 if ((decimalPos < 0 && digitRightCount > 0) || 3430 (decimalPos >= 0 && (decimalPos < digitLeftCount || 3431 decimalPos > (digitLeftCount + zeroDigitCount))) || 3432 groupingCount == 0 || inQuote) { 3433 throw new IllegalArgumentException("Malformed pattern "" + 3434 pattern + ‘"‘); 3435 } 3436 3437 if (j == 1) { 3438 posPrefixPattern = prefix.toString(); 3439 posSuffixPattern = suffix.toString(); 3440 negPrefixPattern = posPrefixPattern; // assume these for now 3441 negSuffixPattern = posSuffixPattern; 3442 int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount; 3443 /* The effectiveDecimalPos is the position the decimal is at or 3444 * would be at if there is no decimal. Note that if decimalPos<0, 3445 * then digitTotalCount == digitLeftCount + zeroDigitCount. 3446 */ 3447 int effectiveDecimalPos = decimalPos >= 0 ? 3448 decimalPos : digitTotalCount; 3449 setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount); 3450 setMaximumIntegerDigits(useExponentialNotation ? 3451 digitLeftCount + getMinimumIntegerDigits() : 3452 MAXIMUM_INTEGER_DIGITS); 3453 setMaximumFractionDigits(decimalPos >= 0 ? 3454 (digitTotalCount - decimalPos) : 0); 3455 setMinimumFractionDigits(decimalPos >= 0 ? 3456 (digitLeftCount + zeroDigitCount - decimalPos) : 0); 3457 setGroupingUsed(groupingCount > 0); 3458 this.groupingSize = (groupingCount > 0) ? groupingCount : 0; 3459 this.multiplier = multiplier; 3460 setDecimalSeparatorAlwaysShown(decimalPos == 0 || 3461 decimalPos == digitTotalCount); 3462 } else { 3463 negPrefixPattern = prefix.toString(); 3464 negSuffixPattern = suffix.toString(); 3465 gotNegative = true; 3466 } 3467 } 3468 3469 if (pattern.length() == 0) { 3470 posPrefixPattern = posSuffixPattern = ""; 3471 setMinimumIntegerDigits(0); 3472 setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS); 3473 setMinimumFractionDigits(0); 3474 setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS); 3475 } 3476 3477 // If there was no negative pattern, or if the negative pattern is 3478 // identical to the positive pattern, then prepend the minus sign to 3479 // the positive pattern to form the negative pattern. 3480 if (!gotNegative || 3481 (negPrefixPattern.equals(posPrefixPattern) 3482 && negSuffixPattern.equals(posSuffixPattern))) { 3483 negSuffixPattern = posSuffixPattern; 3484 negPrefixPattern = "‘-" + posPrefixPattern; 3485 } 3486 3487 expandAffixes(); 3488 } 3489 3490 /** 3491 * Sets the maximum number of digits allowed in the integer portion of a 3492 * number. 3493 * For formatting numbers other than <code>BigInteger</code> and 3494 * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and 3495 * 309 is used. Negative input values are replaced with 0. 3496 * @see NumberFormat#setMaximumIntegerDigits 3497 */ 3498 @Override 3499 public void setMaximumIntegerDigits(int newValue) { 3500 maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS); 3501 super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 3502 DOUBLE_INTEGER_DIGITS : maximumIntegerDigits); 3503 if (minimumIntegerDigits > maximumIntegerDigits) { 3504 minimumIntegerDigits = maximumIntegerDigits; 3505 super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 3506 DOUBLE_INTEGER_DIGITS : minimumIntegerDigits); 3507 } 3508 fastPathCheckNeeded = true; 3509 } 3510 3511 /** 3512 * Sets the minimum number of digits allowed in the integer portion of a 3513 * number. 3514 * For formatting numbers other than <code>BigInteger</code> and 3515 * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and 3516 * 309 is used. Negative input values are replaced with 0. 3517 * @see NumberFormat#setMinimumIntegerDigits 3518 */ 3519 @Override 3520 public void setMinimumIntegerDigits(int newValue) { 3521 minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS); 3522 super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 3523 DOUBLE_INTEGER_DIGITS : minimumIntegerDigits); 3524 if (minimumIntegerDigits > maximumIntegerDigits) { 3525 maximumIntegerDigits = minimumIntegerDigits; 3526 super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ? 3527 DOUBLE_INTEGER_DIGITS : maximumIntegerDigits); 3528 } 3529 fastPathCheckNeeded = true; 3530 } 3531 3532 /** 3533 * Sets the maximum number of digits allowed in the fraction portion of a 3534 * number. 3535 * For formatting numbers other than <code>BigInteger</code> and 3536 * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and 3537 * 340 is used. Negative input values are replaced with 0. 3538 * @see NumberFormat#setMaximumFractionDigits 3539 */ 3540 @Override 3541 public void setMaximumFractionDigits(int newValue) { 3542 maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS); 3543 super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 3544 DOUBLE_FRACTION_DIGITS : maximumFractionDigits); 3545 if (minimumFractionDigits > maximumFractionDigits) { 3546 minimumFractionDigits = maximumFractionDigits; 3547 super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 3548 DOUBLE_FRACTION_DIGITS : minimumFractionDigits); 3549 } 3550 fastPathCheckNeeded = true; 3551 } 3552 3553 /** 3554 * Sets the minimum number of digits allowed in the fraction portion of a 3555 * number. 3556 * For formatting numbers other than <code>BigInteger</code> and 3557 * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and 3558 * 340 is used. Negative input values are replaced with 0. 3559 * @see NumberFormat#setMinimumFractionDigits 3560 */ 3561 @Override 3562 public void setMinimumFractionDigits(int newValue) { 3563 minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS); 3564 super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 3565 DOUBLE_FRACTION_DIGITS : minimumFractionDigits); 3566 if (minimumFractionDigits > maximumFractionDigits) { 3567 maximumFractionDigits = minimumFractionDigits; 3568 super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ? 3569 DOUBLE_FRACTION_DIGITS : maximumFractionDigits); 3570 } 3571 fastPathCheckNeeded = true; 3572 } 3573 3574 /** 3575 * Gets the maximum number of digits allowed in the integer portion of a 3576 * number. 3577 * For formatting numbers other than <code>BigInteger</code> and 3578 * <code>BigDecimal</code> objects, the lower of the return value and 3579 * 309 is used. 3580 * @see #setMaximumIntegerDigits 3581 */ 3582 @Override 3583 public int getMaximumIntegerDigits() { 3584 return maximumIntegerDigits; 3585 } 3586 3587 /** 3588 * Gets the minimum number of digits allowed in the integer portion of a 3589 * number. 3590 * For formatting numbers other than <code>BigInteger</code> and 3591 * <code>BigDecimal</code> objects, the lower of the return value and 3592 * 309 is used. 3593 * @see #setMinimumIntegerDigits 3594 */ 3595 @Override 3596 public int getMinimumIntegerDigits() { 3597 return minimumIntegerDigits; 3598 } 3599 3600 /** 3601 * Gets the maximum number of digits allowed in the fraction portion of a 3602 * number. 3603 * For formatting numbers other than <code>BigInteger</code> and 3604 * <code>BigDecimal</code> objects, the lower of the return value and 3605 * 340 is used. 3606 * @see #setMaximumFractionDigits 3607 */ 3608 @Override 3609 public int getMaximumFractionDigits() { 3610 return maximumFractionDigits; 3611 } 3612 3613 /** 3614 * Gets the minimum number of digits allowed in the fraction portion of a 3615 * number. 3616 * For formatting numbers other than <code>BigInteger</code> and 3617 * <code>BigDecimal</code> objects, the lower of the return value and 3618 * 340 is used. 3619 * @see #setMinimumFractionDigits 3620 */ 3621 @Override 3622 public int getMinimumFractionDigits() { 3623 return minimumFractionDigits; 3624 } 3625 3626 /** 3627 * Gets the currency used by this decimal format when formatting 3628 * currency values. 3629 * The currency is obtained by calling 3630 * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency} 3631 * on this number format‘s symbols. 3632 * 3633 * @return the currency used by this decimal format, or <code>null</code> 3634 * @since 1.4 3635 */ 3636 @Override 3637 public Currency getCurrency() { 3638 return symbols.getCurrency(); 3639 } 3640 3641 /** 3642 * Sets the currency used by this number format when formatting 3643 * currency values. This does not update the minimum or maximum 3644 * number of fraction digits used by the number format. 3645 * The currency is set by calling 3646 * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency} 3647 * on this number format‘s symbols. 3648 * 3649 * @param currency the new currency to be used by this decimal format 3650 * @exception NullPointerException if <code>currency</code> is null 3651 * @since 1.4 3652 */ 3653 @Override 3654 public void setCurrency(Currency currency) { 3655 if (currency != symbols.getCurrency()) { 3656 symbols.setCurrency(currency); 3657 if (isCurrencyFormat) { 3658 expandAffixes(); 3659 } 3660 } 3661 fastPathCheckNeeded = true; 3662 } 3663 3664 /** 3665 * Gets the {@link java.math.RoundingMode} used in this DecimalFormat. 3666 * 3667 * @return The <code>RoundingMode</code> used for this DecimalFormat. 3668 * @see #setRoundingMode(RoundingMode) 3669 * @since 1.6 3670 */ 3671 @Override 3672 public RoundingMode getRoundingMode() { 3673 return roundingMode; 3674 } 3675 3676 /** 3677 * Sets the {@link java.math.RoundingMode} used in this DecimalFormat. 3678 * 3679 * @param roundingMode The <code>RoundingMode</code> to be used 3680 * @see #getRoundingMode() 3681 * @exception NullPointerException if <code>roundingMode</code> is null. 3682 * @since 1.6 3683 */ 3684 @Override 3685 public void setRoundingMode(RoundingMode roundingMode) { 3686 if (roundingMode == null) { 3687 throw new NullPointerException(); 3688 } 3689 3690 this.roundingMode = roundingMode; 3691 digitList.setRoundingMode(roundingMode); 3692 fastPathCheckNeeded = true; 3693 } 3694 3695 /** 3696 * Reads the default serializable fields from the stream and performs 3697 * validations and adjustments for older serialized versions. The 3698 * validations and adjustments are: 3699 * <ol> 3700 * <li> 3701 * Verify that the superclass‘s digit count fields correctly reflect 3702 * the limits imposed on formatting numbers other than 3703 * <code>BigInteger</code> and <code>BigDecimal</code> objects. These 3704 * limits are stored in the superclass for serialization compatibility 3705 * with older versions, while the limits for <code>BigInteger</code> and 3706 * <code>BigDecimal</code> objects are kept in this class. 3707 * If, in the superclass, the minimum or maximum integer digit count is 3708 * larger than <code>DOUBLE_INTEGER_DIGITS</code> or if the minimum or 3709 * maximum fraction digit count is larger than 3710 * <code>DOUBLE_FRACTION_DIGITS</code>, then the stream data is invalid 3711 * and this method throws an <code>InvalidObjectException</code>. 3712 * <li> 3713 * If <code>serialVersionOnStream</code> is less than 4, initialize 3714 * <code>roundingMode</code> to {@link java.math.RoundingMode#HALF_EVEN 3715 * RoundingMode.HALF_EVEN}. This field is new with version 4. 3716 * <li> 3717 * If <code>serialVersionOnStream</code> is less than 3, then call 3718 * the setters for the minimum and maximum integer and fraction digits with 3719 * the values of the corresponding superclass getters to initialize the 3720 * fields in this class. The fields in this class are new with version 3. 3721 * <li> 3722 * If <code>serialVersionOnStream</code> is less than 1, indicating that 3723 * the stream was written by JDK 1.1, initialize 3724 * <code>useExponentialNotation</code> 3725 * to false, since it was not present in JDK 1.1. 3726 * <li> 3727 * Set <code>serialVersionOnStream</code> to the maximum allowed value so 3728 * that default serialization will work properly if this object is streamed 3729 * out again. 3730 * </ol> 3731 * 3732 * <p>Stream versions older than 2 will not have the affix pattern variables 3733 * <code>posPrefixPattern</code> etc. As a result, they will be initialized 3734 * to <code>null</code>, which means the affix strings will be taken as 3735 * literal values. This is exactly what we want, since that corresponds to 3736 * the pre-version-2 behavior. 3737 */ 3738 private void readObject(ObjectInputStream stream) 3739 throws IOException, ClassNotFoundException 3740 { 3741 stream.defaultReadObject(); 3742 digitList = new DigitList(); 3743 3744 // We force complete fast-path reinitialization when the instance is 3745 // deserialized. See clone() comment on fastPathCheckNeeded. 3746 fastPathCheckNeeded = true; 3747 isFastPath = false; 3748 fastPathData = null; 3749 3750 if (serialVersionOnStream < 4) { 3751 setRoundingMode(RoundingMode.HALF_EVEN); 3752 } else { 3753 setRoundingMode(getRoundingMode()); 3754 } 3755 3756 // We only need to check the maximum counts because NumberFormat 3757 // .readObject has already ensured that the maximum is greater than the 3758 // minimum count. 3759 if (super.getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS || 3760 super.getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) { 3761 throw new InvalidObjectException("Digit count out of range"); 3762 } 3763 if (serialVersionOnStream < 3) { 3764 setMaximumIntegerDigits(super.getMaximumIntegerDigits()); 3765 setMinimumIntegerDigits(super.getMinimumIntegerDigits()); 3766 setMaximumFractionDigits(super.getMaximumFractionDigits()); 3767 setMinimumFractionDigits(super.getMinimumFractionDigits()); 3768 } 3769 if (serialVersionOnStream < 1) { 3770 // Didn‘t have exponential fields 3771 useExponentialNotation = false; 3772 } 3773 serialVersionOnStream = currentSerialVersion; 3774 } 3775 3776 //---------------------------------------------------------------------- 3777 // INSTANCE VARIABLES 3778 //---------------------------------------------------------------------- 3779 3780 private transient DigitList digitList = new DigitList(); 3781 3782 /** 3783 * The symbol used as a prefix when formatting positive numbers, e.g. "+". 3784 * 3785 * @serial 3786 * @see #getPositivePrefix 3787 */ 3788 private String positivePrefix = ""; 3789 3790 /** 3791 * The symbol used as a suffix when formatting positive numbers. 3792 * This is often an empty string. 3793 * 3794 * @serial 3795 * @see #getPositiveSuffix 3796 */ 3797 private String positiveSuffix = ""; 3798 3799 /** 3800 * The symbol used as a prefix when formatting negative numbers, e.g. "-". 3801 * 3802 * @serial 3803 * @see #getNegativePrefix 3804 */ 3805 private String negativePrefix = "-"; 3806 3807 /** 3808 * The symbol used as a suffix when formatting negative numbers. 3809 * This is often an empty string. 3810 * 3811 * @serial 3812 * @see #getNegativeSuffix 3813 */ 3814 private String negativeSuffix = ""; 3815 3816 /** 3817 * The prefix pattern for non-negative numbers. This variable corresponds 3818 * to <code>positivePrefix</code>. 3819 * 3820 * <p>This pattern is expanded by the method <code>expandAffix()</code> to 3821 * <code>positivePrefix</code> to update the latter to reflect changes in 3822 * <code>symbols</code>. If this variable is <code>null</code> then 3823 * <code>positivePrefix</code> is taken as a literal value that does not 3824 * change when <code>symbols</code> changes. This variable is always 3825 * <code>null</code> for <code>DecimalFormat</code> objects older than 3826 * stream version 2 restored from stream. 3827 * 3828 * @serial 3829 * @since 1.3 3830 */ 3831 private String posPrefixPattern; 3832 3833 /** 3834 * The suffix pattern for non-negative numbers. This variable corresponds 3835 * to <code>positiveSuffix</code>. This variable is analogous to 3836 * <code>posPrefixPattern</code>; see that variable for further 3837 * documentation. 3838 * 3839 * @serial 3840 * @since 1.3 3841 */ 3842 private String posSuffixPattern; 3843 3844 /** 3845 * The prefix pattern for negative numbers. This variable corresponds 3846 * to <code>negativePrefix</code>. This variable is analogous to 3847 * <code>posPrefixPattern</code>; see that variable for further 3848 * documentation. 3849 * 3850 * @serial 3851 * @since 1.3 3852 */ 3853 private String negPrefixPattern; 3854 3855 /** 3856 * The suffix pattern for negative numbers. This variable corresponds 3857 * to <code>negativeSuffix</code>. This variable is analogous to 3858 * <code>posPrefixPattern</code>; see that variable for further 3859 * documentation. 3860 * 3861 * @serial 3862 * @since 1.3 3863 */ 3864 private String negSuffixPattern; 3865 3866 /** 3867 * The multiplier for use in percent, per mille, etc. 3868 * 3869 * @serial 3870 * @see #getMultiplier 3871 */ 3872 private int multiplier = 1; 3873 3874 /** 3875 * The number of digits between grouping separators in the integer 3876 * portion of a number. Must be greater than 0 if 3877 * <code>NumberFormat.groupingUsed</code> is true. 3878 * 3879 * @serial 3880 * @see #getGroupingSize 3881 * @see java.text.NumberFormat#isGroupingUsed 3882 */ 3883 private byte groupingSize = 3; // invariant, > 0 if useThousands 3884 3885 /** 3886 * If true, forces the decimal separator to always appear in a formatted 3887 * number, even if the fractional part of the number is zero. 3888 * 3889 * @serial 3890 * @see #isDecimalSeparatorAlwaysShown 3891 */ 3892 private boolean decimalSeparatorAlwaysShown = false; 3893 3894 /** 3895 * If true, parse returns BigDecimal wherever possible. 3896 * 3897 * @serial 3898 * @see #isParseBigDecimal 3899 * @since 1.5 3900 */ 3901 private boolean parseBigDecimal = false; 3902 3903 3904 /** 3905 * True if this object represents a currency format. This determines 3906 * whether the monetary decimal separator is used instead of the normal one. 3907 */ 3908 private transient boolean isCurrencyFormat = false; 3909 3910 /** 3911 * The <code>DecimalFormatSymbols</code> object used by this format. 3912 * It contains the symbols used to format numbers, e.g. the grouping separator, 3913 * decimal separator, and so on. 3914 * 3915 * @serial 3916 * @see #setDecimalFormatSymbols 3917 * @see java.text.DecimalFormatSymbols 3918 */ 3919 private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols(); 3920 3921 /** 3922 * True to force the use of exponential (i.e. scientific) notation when formatting 3923 * numbers. 3924 * 3925 * @serial 3926 * @since 1.2 3927 */ 3928 private boolean useExponentialNotation; // Newly persistent in the Java 2 platform v.1.2 3929 3930 /** 3931 * FieldPositions describing the positive prefix String. This is 3932 * lazily created. Use <code>getPositivePrefixFieldPositions</code> 3933 * when needed. 3934 */ 3935 private transient FieldPosition[] positivePrefixFieldPositions; 3936 3937 /** 3938 * FieldPositions describing the positive suffix String. This is 3939 * lazily created. Use <code>getPositiveSuffixFieldPositions</code> 3940 * when needed. 3941 */ 3942 private transient FieldPosition[] positiveSuffixFieldPositions; 3943 3944 /** 3945 * FieldPositions describing the negative prefix String. This is 3946 * lazily created. Use <code>getNegativePrefixFieldPositions</code> 3947 * when needed. 3948 */ 3949 private transient FieldPosition[] negativePrefixFieldPositions; 3950 3951 /** 3952 * FieldPositions describing the negative suffix String. This is 3953 * lazily created. Use <code>getNegativeSuffixFieldPositions</code> 3954 * when needed. 3955 */ 3956 private transient FieldPosition[] negativeSuffixFieldPositions; 3957 3958 /** 3959 * The minimum number of digits used to display the exponent when a number is 3960 * formatted in exponential notation. This field is ignored if 3961 * <code>useExponentialNotation</code> is not true. 3962 * 3963 * @serial 3964 * @since 1.2 3965 */ 3966 private byte minExponentDigits; // Newly persistent in the Java 2 platform v.1.2 3967 3968 /** 3969 * The maximum number of digits allowed in the integer portion of a 3970 * <code>BigInteger</code> or <code>BigDecimal</code> number. 3971 * <code>maximumIntegerDigits</code> must be greater than or equal to 3972 * <code>minimumIntegerDigits</code>. 3973 * 3974 * @serial 3975 * @see #getMaximumIntegerDigits 3976 * @since 1.5 3977 */ 3978 private int maximumIntegerDigits = super.getMaximumIntegerDigits(); 3979 3980 /** 3981 * The minimum number of digits allowed in the integer portion of a 3982 * <code>BigInteger</code> or <code>BigDecimal</code> number. 3983 * <code>minimumIntegerDigits</code> must be less than or equal to 3984 * <code>maximumIntegerDigits</code>. 3985 * 3986 * @serial 3987 * @see #getMinimumIntegerDigits 3988 * @since 1.5 3989 */ 3990 private int minimumIntegerDigits = super.getMinimumIntegerDigits(); 3991 3992 /** 3993 * The maximum number of digits allowed in the fractional portion of a 3994 * <code>BigInteger</code> or <code>BigDecimal</code> number. 3995 * <code>maximumFractionDigits</code> must be greater than or equal to 3996 * <code>minimumFractionDigits</code>. 3997 * 3998 * @serial 3999 * @see #getMaximumFractionDigits 4000 * @since 1.5 4001 */ 4002 private int maximumFractionDigits = super.getMaximumFractionDigits(); 4003 4004 /** 4005 * The minimum number of digits allowed in the fractional portion of a 4006 * <code>BigInteger</code> or <code>BigDecimal</code> number. 4007 * <code>minimumFractionDigits</code> must be less than or equal to 4008 * <code>maximumFractionDigits</code>. 4009 * 4010 * @serial 4011 * @see #getMinimumFractionDigits 4012 * @since 1.5 4013 */ 4014 private int minimumFractionDigits = super.getMinimumFractionDigits(); 4015 4016 /** 4017 * The {@link java.math.RoundingMode} used in this DecimalFormat. 4018 * 4019 * @serial 4020 * @since 1.6 4021 */ 4022 private RoundingMode roundingMode = RoundingMode.HALF_EVEN; 4023 4024 // ------ DecimalFormat fields for fast-path for double algorithm ------ 4025 4026 /** 4027 * Helper inner utility class for storing the data used in the fast-path 4028 * algorithm. Almost all fields related to fast-path are encapsulated in 4029 * this class. 4030 * 4031 * Any {@code DecimalFormat} instance has a {@code fastPathData} 4032 * reference field that is null unless both the properties of the instance 4033 * are such that the instance is in the "fast-path" state, and a format call 4034 * has been done at least once while in this state. 4035 * 4036 * Almost all fields are related to the "fast-path" state only and don‘t 4037 * change until one of the instance properties is changed. 4038 * 4039 * {@code firstUsedIndex} and {@code lastFreeIndex} are the only 4040 * two fields that are used and modified while inside a call to 4041 * {@code fastDoubleFormat}. 4042 * 4043 */ 4044 private static class FastPathData { 4045 // --- Temporary fields used in fast-path, shared by several methods. 4046 4047 /** The first unused index at the end of the formatted result. */ 4048 int lastFreeIndex; 4049 4050 /** The first used index at the beginning of the formatted result */ 4051 int firstUsedIndex; 4052 4053 // --- State fields related to fast-path status. Changes due to a 4054 // property change only. Set by checkAndSetFastPathStatus() only. 4055 4056 /** Difference between locale zero and default zero representation. */ 4057 int zeroDelta; 4058 4059 /** Locale char for grouping separator. */ 4060 char groupingChar; 4061 4062 /** Fixed index position of last integral digit of formatted result */ 4063 int integralLastIndex; 4064 4065 /** Fixed index position of first fractional digit of formatted result */ 4066 int fractionalFirstIndex; 4067 4068 /** Fractional constants depending on decimal|currency state */ 4069 double fractionalScaleFactor; 4070 int fractionalMaxIntBound; 4071 4072 4073 /** The char array buffer that will contain the formatted result */ 4074 char[] fastPathContainer; 4075 4076 /** Suffixes recorded as char array for efficiency. */ 4077 char[] charsPositivePrefix; 4078 char[] charsNegativePrefix; 4079 char[] charsPositiveSuffix; 4080 char[] charsNegativeSuffix; 4081 boolean positiveAffixesRequired = true; 4082 boolean negativeAffixesRequired = true; 4083 } 4084 4085 /** The format fast-path status of the instance. Logical state. */ 4086 private transient boolean isFastPath = false; 4087 4088 /** Flag stating need of check and reinit fast-path status on next format call. */ 4089 private transient boolean fastPathCheckNeeded = true; 4090 4091 /** DecimalFormat reference to its FastPathData */ 4092 private transient FastPathData fastPathData; 4093 4094 4095 //---------------------------------------------------------------------- 4096 4097 static final int currentSerialVersion = 4; 4098 4099 /** 4100 * The internal serial version which says which version was written. 4101 * Possible values are: 4102 * <ul> 4103 * <li><b>0</b> (default): versions before the Java 2 platform v1.2 4104 * <li><b>1</b>: version for 1.2, which includes the two new fields 4105 * <code>useExponentialNotation</code> and 4106 * <code>minExponentDigits</code>. 4107 * <li><b>2</b>: version for 1.3 and later, which adds four new fields: 4108 * <code>posPrefixPattern</code>, <code>posSuffixPattern</code>, 4109 * <code>negPrefixPattern</code>, and <code>negSuffixPattern</code>. 4110 * <li><b>3</b>: version for 1.5 and later, which adds five new fields: 4111 * <code>maximumIntegerDigits</code>, 4112 * <code>minimumIntegerDigits</code>, 4113 * <code>maximumFractionDigits</code>, 4114 * <code>minimumFractionDigits</code>, and 4115 * <code>parseBigDecimal</code>. 4116 * <li><b>4</b>: version for 1.6 and later, which adds one new field: 4117 * <code>roundingMode</code>. 4118 * </ul> 4119 * @since 1.2 4120 * @serial 4121 */ 4122 private int serialVersionOnStream = currentSerialVersion; 4123 4124 //---------------------------------------------------------------------- 4125 // CONSTANTS 4126 //---------------------------------------------------------------------- 4127 4128 // ------ Fast-Path for double Constants ------ 4129 4130 /** Maximum valid integer value for applying fast-path algorithm */ 4131 private static final double MAX_INT_AS_DOUBLE = (double) Integer.MAX_VALUE; 4132 4133 /** 4134 * The digit arrays used in the fast-path methods for collecting digits. 4135 * Using 3 constants arrays of chars ensures a very fast collection of digits 4136 */ 4137 private static class DigitArrays { 4138 static final char[] DigitOnes1000 = new char[1000]; 4139 static final char[] DigitTens1000 = new char[1000]; 4140 static final char[] DigitHundreds1000 = new char[1000]; 4141 4142 // initialize on demand holder class idiom for arrays of digits 4143 static { 4144 int tenIndex = 0; 4145 int hundredIndex = 0; 4146 char digitOne = ‘0‘; 4147 char digitTen = ‘0‘; 4148 char digitHundred = ‘0‘; 4149 for (int i = 0; i < 1000; i++ ) { 4150 4151 DigitOnes1000[i] = digitOne; 4152 if (digitOne == ‘9‘) 4153 digitOne = ‘0‘; 4154 else 4155 digitOne++; 4156 4157 DigitTens1000[i] = digitTen; 4158 if (i == (tenIndex + 9)) { 4159 tenIndex += 10; 4160 if (digitTen == ‘9‘) 4161 digitTen = ‘0‘; 4162 else 4163 digitTen++; 4164 } 4165 4166 DigitHundreds1000[i] = digitHundred; 4167 if (i == (hundredIndex + 99)) { 4168 digitHundred++; 4169 hundredIndex += 100; 4170 } 4171 } 4172 } 4173 } 4174 // ------ Fast-Path for double Constants end ------ 4175 4176 // Constants for characters used in programmatic (unlocalized) patterns. 4177 private static final char PATTERN_ZERO_DIGIT = ‘0‘; 4178 private static final char PATTERN_GROUPING_SEPARATOR = ‘,‘; 4179 private static final char PATTERN_DECIMAL_SEPARATOR = ‘.‘; 4180 private static final char PATTERN_PER_MILLE = ‘u2030‘; 4181 private static final char PATTERN_PERCENT = ‘%‘; 4182 private static final char PATTERN_DIGIT = ‘#‘; 4183 private static final char PATTERN_SEPARATOR = ‘;‘; 4184 private static final String PATTERN_EXPONENT = "E"; 4185 private static final char PATTERN_MINUS = ‘-‘; 4186 4187 /** 4188 * The CURRENCY_SIGN is the standard Unicode symbol for currency. It 4189 * is used in patterns and substituted with either the currency symbol, 4190 * or if it is doubled, with the international currency symbol. If the 4191 * CURRENCY_SIGN is seen in a pattern, then the decimal separator is 4192 * replaced with the monetary decimal separator. 4193 * 4194 * The CURRENCY_SIGN is not localized. 4195 */ 4196 private static final char CURRENCY_SIGN = ‘u00A4‘; 4197 4198 private static final char QUOTE = ‘‘‘; 4199 4200 private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0]; 4201 4202 // Upper limit on integer and fraction digits for a Java double 4203 static final int DOUBLE_INTEGER_DIGITS = 309; 4204 static final int DOUBLE_FRACTION_DIGITS = 340; 4205 4206 // Upper limit on integer and fraction digits for BigDecimal and BigInteger 4207 static final int MAXIMUM_INTEGER_DIGITS = Integer.MAX_VALUE; 4208 static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE; 4209 4210 // Proclaim JDK 1.1 serial compatibility. 4211 static final long serialVersionUID = 864413376551465018L; 4212 }
以上是关于DecimalFormat详解的主要内容,如果未能解决你的问题,请参考以下文章
java 使用DecimalFormat进行数字的格式化实例详解
14.VisualVM使用详解15.VisualVM堆查看器使用的内存不足19.class文件--文件结构--魔数20.文件结构--常量池21.文件结构访问标志(2个字节)22.类加载机制概(代码片段