1
1
/*
2
- * Copyright (c) 2003, 2021 , Oracle and/or its affiliates. All rights reserved.
2
+ * Copyright (c) 2003, 2022 , Oracle and/or its affiliates. All rights reserved.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* This code is free software; you can redistribute it and/or modify it
2008
2008
* @since 1.5
2009
2009
*/
2010
2010
public final class Formatter implements Closeable , Flushable {
2011
+ // Caching DecimalFormatSymbols. Non-volatile to avoid thread slamming.
2012
+ private static DecimalFormatSymbols DFS = null ;
2013
+ private static DecimalFormatSymbols getDecimalFormatSymbols (Locale locale ) {
2014
+ // Capture local copy to avoid thread race.
2015
+ DecimalFormatSymbols dfs = DFS ;
2016
+ if (dfs != null && dfs .getLocale ().equals (locale )) {
2017
+ return dfs ;
2018
+ }
2019
+ // Fetch a new local instance of DecimalFormatSymbols. Note that DFS are mutable
2020
+ // and this instance is reserved for Formatter.
2021
+ dfs = DecimalFormatSymbols .getInstance (locale );
2022
+ // Non-volatile here is acceptable heuristic.
2023
+ DFS = dfs ;
2024
+ return dfs ;
2025
+ }
2026
+
2027
+ // Use zero from cached DecimalFormatSymbols.
2028
+ private static char getZero (Locale locale ) {
2029
+ return locale == null ? '0' : getDecimalFormatSymbols (locale ).getZeroDigit ();
2030
+ }
2031
+
2032
+ // Use decimal separator from cached DecimalFormatSymbols.
2033
+ private static char getDecimalSeparator (Locale locale ) {
2034
+ return locale == null ? '.' : getDecimalFormatSymbols (locale ).getDecimalSeparator ();
2035
+ }
2036
+
2037
+ // Use grouping separator from cached DecimalFormatSymbols.
2038
+ private static char getGroupingSeparator (Locale locale ) {
2039
+ return locale == null ? ',' : getDecimalFormatSymbols (locale ).getGroupingSeparator ();
2040
+ }
2041
+
2011
2042
private Appendable a ;
2012
2043
private final Locale l ;
2013
-
2014
2044
private IOException lastException ;
2015
2045
2016
- // Non-character value used to mark zero as uninitialized
2017
- private static final char ZERO_SENTINEL = '\uFFFE' ;
2018
- private char zero = ZERO_SENTINEL ;
2019
-
2020
2046
/**
2021
2047
* Returns a charset object for the given charset name.
2022
2048
* @throws NullPointerException is csn is null
@@ -2523,20 +2549,6 @@ public Formatter(OutputStream os, Charset charset, Locale l) {
2523
2549
this (l , new BufferedWriter (new OutputStreamWriter (os , charset )));
2524
2550
}
2525
2551
2526
- private char zero () {
2527
- char zero = this .zero ;
2528
- if (zero == ZERO_SENTINEL ) {
2529
- if ((l != null ) && !l .equals (Locale .US )) {
2530
- DecimalFormatSymbols dfs = DecimalFormatSymbols .getInstance (l );
2531
- zero = dfs .getZeroDigit ();
2532
- } else {
2533
- zero = '0' ;
2534
- }
2535
- this .zero = zero ;
2536
- }
2537
- return zero ;
2538
- }
2539
-
2540
2552
/**
2541
2553
* Returns the locale set by the construction of this formatter.
2542
2554
*
@@ -4498,14 +4510,6 @@ private void failConversion(char c, Object arg) {
4498
4510
throw new IllegalFormatConversionException (c , arg .getClass ());
4499
4511
}
4500
4512
4501
- private char getZero (Formatter fmt , Locale l ) {
4502
- if ((l != null ) && !l .equals (fmt .locale ())) {
4503
- DecimalFormatSymbols dfs = DecimalFormatSymbols .getInstance (l );
4504
- return dfs .getZeroDigit ();
4505
- }
4506
- return fmt .zero ();
4507
- }
4508
-
4509
4513
private StringBuilder localizedMagnitude (Formatter fmt , StringBuilder sb ,
4510
4514
long value , int flags , int width , Locale l ) {
4511
4515
return localizedMagnitude (fmt , sb , Long .toString (value , 10 ), 0 , flags , width , l );
@@ -4519,7 +4523,7 @@ private StringBuilder localizedMagnitude(Formatter fmt, StringBuilder sb,
4519
4523
}
4520
4524
int begin = sb .length ();
4521
4525
4522
- char zero = getZero (fmt , l );
4526
+ char zero = getZero (l );
4523
4527
4524
4528
// determine localized grouping separator and size
4525
4529
char grpSep = '\0' ;
@@ -4536,21 +4540,15 @@ private StringBuilder localizedMagnitude(Formatter fmt, StringBuilder sb,
4536
4540
}
4537
4541
4538
4542
if (dot < len ) {
4539
- if (l == null || l .equals (Locale .US )) {
4540
- decSep = '.' ;
4541
- } else {
4542
- DecimalFormatSymbols dfs = DecimalFormatSymbols .getInstance (l );
4543
- decSep = dfs .getDecimalSeparator ();
4544
- }
4543
+ decSep = getDecimalSeparator (l );
4545
4544
}
4546
4545
4547
4546
if (Flags .contains (f , Flags .GROUP )) {
4547
+ grpSep = getGroupingSeparator (l );
4548
+
4548
4549
if (l == null || l .equals (Locale .US )) {
4549
- grpSep = ',' ;
4550
4550
grpSize = 3 ;
4551
4551
} else {
4552
- DecimalFormatSymbols dfs = DecimalFormatSymbols .getInstance (l );
4553
- grpSep = dfs .getGroupingSeparator ();
4554
4552
DecimalFormat df = null ;
4555
4553
NumberFormat nf = NumberFormat .getNumberInstance (l );
4556
4554
if (nf instanceof DecimalFormat ) {
@@ -4567,7 +4565,7 @@ private StringBuilder localizedMagnitude(Formatter fmt, StringBuilder sb,
4567
4565
}
4568
4566
String [] all = adapter .getLocaleResources (l )
4569
4567
.getNumberPatterns ();
4570
- df = new DecimalFormat (all [0 ], dfs );
4568
+ df = new DecimalFormat (all [0 ], getDecimalFormatSymbols ( l ) );
4571
4569
}
4572
4570
grpSize = df .getGroupingSize ();
4573
4571
// Some locales do not use grouping (the number
@@ -4612,7 +4610,7 @@ private StringBuilder localizedMagnitude(Formatter fmt, StringBuilder sb,
4612
4610
// group separators is added for any locale.
4613
4611
private void localizedMagnitudeExp (Formatter fmt , StringBuilder sb , char [] value ,
4614
4612
final int offset , Locale l ) {
4615
- char zero = getZero (fmt , l );
4613
+ char zero = getZero (l );
4616
4614
4617
4615
int len = value .length ;
4618
4616
for (int j = offset ; j < len ; j ++) {
0 commit comments