@@ -44,6 +44,11 @@ private static Map<String, String> getSettings(String query) {
4444 }
4545
4646 private static Function <Number , String > createDisplayFunction (String formatQuery ) {
47+ if (formatQuery .isEmpty ()) {
48+ ThreadLocal <DecimalFormat > threadLocalFormat = ThreadLocal .withInitial (() -> new DecimalFormat ("#.##" ));
49+ return n -> threadLocalFormat .get ().format (n );
50+ }
51+
4752 if (formatQuery .startsWith (FORMAT_QUERY_SHORTEN )) {
4853 String config = formatQuery .substring (FORMAT_QUERY_SHORTEN .length ());
4954 NavigableMap <Double , String > suffixMap = new TreeMap <>();
@@ -158,48 +163,46 @@ private static Function<Number, String> createDisplayFunction(String formatQuery
158163 if (formatQuery .startsWith (FORMAT_QUERY_DECIMAL )) {
159164 Map <String , String > settings = getSettings (formatQuery .substring (FORMAT_QUERY_DECIMAL .length ()));
160165
161- DecimalFormatSymbols symbols = new DecimalFormatSymbols ();
162- DecimalFormat decimalFormat = new DecimalFormat ();
163- decimalFormat .setRoundingMode (RoundingMode .HALF_EVEN );
164-
165- Optional .ofNullable (settings .get ("decimalSeparator" ))
166- .map (s -> s .charAt (0 ))
167- .ifPresent (symbols ::setDecimalSeparator );
168- Optional .ofNullable (settings .get ("groupingSeparator" ))
169- .map (s -> s .charAt (0 ))
170- .ifPresent (c -> {
171- symbols .setGroupingSeparator (c );
172- decimalFormat .setGroupingUsed (true );
173- });
174- Optional .ofNullable (settings .get ("groupingSize" ))
166+ final Optional <Character > decimalSeparatorOpt = Optional .ofNullable (settings .get ("decimalSeparator" ))
167+ .map (s -> s .charAt (0 ));
168+ final Optional <Character > groupingSeparatorOpt = Optional .ofNullable (settings .get ("groupingSeparator" ))
169+ .map (s -> s .charAt (0 ));
170+ final Optional <Integer > groupingSizeOpt = Optional .ofNullable (settings .get ("groupingSize" ))
175171 .flatMap (s -> {
176172 try {
177173 return Optional .of (Integer .parseInt (s ));
178174 } catch (NumberFormatException e ) {
179175 return Optional .empty ();
180176 }
181- })
182- .map (Number ::intValue )
183- .ifPresent (decimalFormat ::setGroupingSize );
184- Optional .ofNullable (settings .get ("maximumFractionDigits" ))
177+ });
178+ final Optional <Integer > maximumFractionDigitsOpt = Optional .ofNullable (settings .get ("maximumFractionDigits" ))
185179 .flatMap (s -> {
186180 try {
187181 return Optional .of (Integer .parseInt (s ));
188182 } catch (NumberFormatException e ) {
189183 return Optional .empty ();
190184 }
191- })
192- .map (Number ::intValue )
193- .ifPresent (decimalFormat ::setMaximumFractionDigits );
194-
195- decimalFormat .setDecimalFormatSymbols (symbols );
185+ });
196186
197- return n -> ((DecimalFormat ) decimalFormat .clone ()).format (n );
187+ ThreadLocal <DecimalFormat > threadLocalFormat = ThreadLocal .withInitial (() -> {
188+ DecimalFormatSymbols sym = new DecimalFormatSymbols ();
189+ decimalSeparatorOpt .ifPresent (sym ::setDecimalSeparator );
190+ groupingSeparatorOpt .ifPresent (sym ::setGroupingSeparator );
191+ DecimalFormat fmt = new DecimalFormat ();
192+ fmt .setRoundingMode (RoundingMode .HALF_EVEN );
193+ groupingSeparatorOpt .ifPresent (c -> fmt .setGroupingUsed (true ));
194+ groupingSizeOpt .ifPresent (fmt ::setGroupingSize );
195+ maximumFractionDigitsOpt .ifPresent (fmt ::setMaximumFractionDigits );
196+ fmt .setDecimalFormatSymbols (sym );
197+ return fmt ;
198+ });
199+ return n -> threadLocalFormat .get ().format (n );
198200 }
199201
200202 try {
201- DecimalFormat decimalFormat = new DecimalFormat (formatQuery );
202- return n -> ((DecimalFormat ) decimalFormat .clone ()).format (n );
203+ new DecimalFormat (formatQuery ); // validate the pattern eagerly
204+ ThreadLocal <DecimalFormat > threadLocalFormat = ThreadLocal .withInitial (() -> new DecimalFormat (formatQuery ));
205+ return n -> threadLocalFormat .get ().format (n );
203206 } catch (IllegalArgumentException e ) {
204207 return n -> "INVALID_FORMAT" ;
205208 }
@@ -213,11 +216,6 @@ private static Function<Number, String> createDisplayFunction(String formatQuery
213216 return getDisplayNullValue ();
214217 }
215218
216- if (formatQuery .isEmpty ()) {
217- DecimalFormat decimalFormat = new DecimalFormat ("#.##" );
218- return decimalFormat .format (value );
219- }
220-
221219 if (formatQuery .equals ("raw" )) {
222220 return String .valueOf (value );
223221 }
0 commit comments