Skip to content

Commit 6b8aadb

Browse files
committed
✨ feat: add numeric4j unify functions #4
1 parent 347aaa8 commit 6b8aadb

1 file changed

Lines changed: 323 additions & 1 deletion

File tree

Lines changed: 323 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,326 @@
11
package org.unify4j.common;
22

3+
import java.math.BigDecimal;
4+
import java.math.BigInteger;
5+
import java.text.DecimalFormat;
6+
import java.text.NumberFormat;
7+
import java.util.Locale;
8+
39
public class Numeric4j {
4-
}
10+
public static final BigInteger BIG_INT_LONG_MIN = BigInteger.valueOf(Long.MIN_VALUE);
11+
public static final BigInteger BIG_INT_LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE);
12+
public static final BigDecimal BIG_DEC_DOUBLE_MIN = BigDecimal.valueOf(-Double.MAX_VALUE);
13+
public static final BigDecimal BIG_DEC_DOUBLE_MAX = BigDecimal.valueOf(Double.MAX_VALUE);
14+
15+
/**
16+
* Formats a given amount as currency according to the specified locale.
17+
*
18+
* @param amount The amount to be formatted.
19+
* @param locale The locale to be used for currency formatting.
20+
* @return A string representing the formatted currency.
21+
*/
22+
public static String currency(double amount, Locale locale) {
23+
NumberFormat instance = NumberFormat.getCurrencyInstance(locale);
24+
return instance.format(amount);
25+
}
26+
27+
/**
28+
* Formats a given amount as currency using specified language and country codes.
29+
*
30+
* @param amount The amount to be formatted.
31+
* @param language The language code for the locale.
32+
* @param country The country code for the locale.
33+
* @return A string representing the formatted currency.
34+
*/
35+
public static String currency(double amount, String language, String country) {
36+
Locale locale;
37+
if (String4j.isAnyEmpty(language, country)) {
38+
locale = Locale.getDefault();
39+
} else {
40+
locale = new Locale(language, country);
41+
}
42+
return currency(amount, locale);
43+
}
44+
45+
/**
46+
* Formats a given amount as currency according to the specified locale and grouping usage.
47+
*
48+
* @param amount The amount to be formatted.
49+
* @param locale The locale to be used for currency formatting.
50+
* @param isGroup Whether to use grouping separators.
51+
* @return A string representing the formatted currency.
52+
*/
53+
public static String currency(Double amount, Locale locale, boolean isGroup) {
54+
String text = "";
55+
if (Object4j.allNotNull(amount, locale)) {
56+
NumberFormat instance = NumberFormat.getCurrencyInstance(locale);
57+
instance.setGroupingUsed(isGroup);
58+
text = instance.format(amount);
59+
}
60+
return text;
61+
}
62+
63+
/**
64+
* Formats a given amount as currency according to the specified locale and grouping usage.
65+
*
66+
* @param amount The amount to be formatted.
67+
* @param locale The locale to be used for integer formatting.
68+
* @param isGroup Whether to use grouping separators.
69+
* @return A string representing the formatted currency.
70+
*/
71+
public static String currency(Long amount, Locale locale, boolean isGroup) {
72+
String text = "";
73+
if (Object4j.allNotNull(amount, locale)) {
74+
NumberFormat instance = NumberFormat.getIntegerInstance(locale);
75+
instance.setGroupingUsed(isGroup);
76+
text = instance.format(amount);
77+
}
78+
return text;
79+
}
80+
81+
/**
82+
* Formats a given amount as currency according to the specified precision, pattern, and locale.
83+
*
84+
* @param amount The amount to be formatted.
85+
* @param precision The number of decimal places to display.
86+
* @param pattern The pattern to be applied for formatting.
87+
* @param locale The locale to be used for currency formatting.
88+
* @return A string representing the formatted currency.
89+
*/
90+
public static String currency(double amount, int precision, String pattern, Locale locale) {
91+
NumberFormat instance = NumberFormat.getCurrencyInstance(locale);
92+
DecimalFormat format = (DecimalFormat) instance;
93+
format.setMinimumFractionDigits(precision);
94+
format.setMaximumFractionDigits(precision);
95+
format.setDecimalSeparatorAlwaysShown(true);
96+
format.applyPattern(pattern);
97+
return format.format(amount);
98+
}
99+
100+
/**
101+
* Formats a given amount as currency according to the specified precision and locale.
102+
*
103+
* @param amount The amount to be formatted.
104+
* @param precision The number of decimal places to display.
105+
* @param locale The locale to be used for currency formatting.
106+
* @return A string representing the formatted currency.
107+
*/
108+
public static String currency(double amount, int precision, Locale locale) {
109+
NumberFormat instance = NumberFormat.getCurrencyInstance(locale);
110+
instance.setMinimumFractionDigits(precision);
111+
instance.setMaximumFractionDigits(precision);
112+
return instance.format(amount);
113+
}
114+
115+
/**
116+
* Calculate the minimum value from an array of values.
117+
*
118+
* @param values Array of values.
119+
* @return minimum value of the provided set.
120+
*/
121+
public static long minimum(long... values) {
122+
final int len = values.length;
123+
long current = values[0];
124+
for (int i = 1; i < len; i++) {
125+
current = Math.min(values[i], current);
126+
}
127+
return current;
128+
}
129+
130+
/**
131+
* Calculate the minimum value from an array of values.
132+
*
133+
* @param values Array of values.
134+
* @return minimum value of the provided set.
135+
*/
136+
public static long maximum(long... values) {
137+
final int len = values.length;
138+
long current = values[0];
139+
for (int i = 1; i < len; i++) {
140+
current = Math.max(values[i], current);
141+
}
142+
return current;
143+
}
144+
145+
/**
146+
* Calculate the minimum value from an array of values.
147+
*
148+
* @param values Array of values.
149+
* @return minimum value of the provided set.
150+
*/
151+
public static double minimum(double... values) {
152+
final int len = values.length;
153+
double current = values[0];
154+
for (int i = 1; i < len; i++) {
155+
current = Math.min(values[i], current);
156+
}
157+
return current;
158+
}
159+
160+
/**
161+
* Calculate the minimum value from an array of values.
162+
*
163+
* @param values Array of values.
164+
* @return minimum value of the provided set.
165+
*/
166+
public static double maximum(double... values) {
167+
final int len = values.length;
168+
double current = values[0];
169+
for (int i = 1; i < len; i++) {
170+
current = Math.max(values[i], current);
171+
}
172+
return current;
173+
}
174+
175+
/**
176+
* Calculate the minimum value from an array of values.
177+
*
178+
* @param values Array of values.
179+
* @return minimum value of the provided set.
180+
*/
181+
public static BigInteger minimum(BigInteger... values) {
182+
final int len = values.length;
183+
if (len == 1) {
184+
if (values[0] == null) {
185+
throw new IllegalArgumentException("Cannot passed null BigInteger entry to minimum()");
186+
}
187+
return values[0];
188+
}
189+
BigInteger current = values[0];
190+
for (int i = 1; i < len; i++) {
191+
if (values[i] == null) {
192+
throw new IllegalArgumentException("Cannot passed null BigInteger entry to minimum()");
193+
}
194+
current = values[i].min(current);
195+
}
196+
return current;
197+
}
198+
199+
/**
200+
* Calculate the minimum value from an array of values.
201+
*
202+
* @param values Array of values.
203+
* @return minimum value of the provided set.
204+
*/
205+
public static BigInteger maximum(BigInteger... values) {
206+
final int len = values.length;
207+
if (len == 1) {
208+
if (values[0] == null) {
209+
throw new IllegalArgumentException("Cannot passed null BigInteger entry to maximum()");
210+
}
211+
return values[0];
212+
}
213+
BigInteger current = values[0];
214+
for (int i = 1; i < len; i++) {
215+
if (values[i] == null) {
216+
throw new IllegalArgumentException("Cannot passed null BigInteger entry to maximum()");
217+
}
218+
current = values[i].max(current);
219+
}
220+
return current;
221+
}
222+
223+
/**
224+
* Calculate the minimum value from an array of values.
225+
*
226+
* @param values Array of values.
227+
* @return minimum value of the provided set.
228+
*/
229+
public static BigDecimal minimum(BigDecimal... values) {
230+
final int len = values.length;
231+
if (len == 1) {
232+
if (values[0] == null) {
233+
throw new IllegalArgumentException("Cannot passed null BigDecimal entry to minimum()");
234+
}
235+
return values[0];
236+
}
237+
BigDecimal current = values[0];
238+
for (int i = 1; i < len; i++) {
239+
if (values[i] == null) {
240+
throw new IllegalArgumentException("Cannot passed null BigDecimal entry to minimum()");
241+
}
242+
current = values[i].min(current);
243+
}
244+
return current;
245+
}
246+
247+
/**
248+
* Calculate the maximum value from an array of values.
249+
*
250+
* @param values Array of values.
251+
* @return maximum value of the provided set.
252+
*/
253+
public static BigDecimal maximum(BigDecimal... values) {
254+
final int len = values.length;
255+
if (len == 1) {
256+
if (values[0] == null) {
257+
throw new IllegalArgumentException("Cannot pass null BigDecimal entry to maximum()");
258+
}
259+
return values[0];
260+
}
261+
BigDecimal current = values[0];
262+
for (int i = 1; i < len; i++) {
263+
if (values[i] == null) {
264+
throw new IllegalArgumentException("Cannot pass null BigDecimal entry to maximum()");
265+
}
266+
current = values[i].max(current);
267+
}
268+
return current;
269+
}
270+
271+
/**
272+
* Parse the passed in String as a numeric value and return the minimal data type between Long, Double,
273+
* BigDecimal, or BigInteger. Useful for processing values from JSON files.
274+
*
275+
* @param numStr String to parse.
276+
* @return Long, BigInteger, Double, or BigDecimal depending on the value. If the value is and integer and
277+
* between the range of Long min/max, a Long is returned. If the value is an integer and outside this range, a
278+
* BigInteger is returned. If the value is a decimal but within the confines of a Double, then a Double is
279+
* returned, otherwise a BigDecimal is returned.
280+
*/
281+
public static Number tryNumeric(String numStr) {
282+
boolean isNegative = numStr.startsWith("-"); // Handle and preserve negative signs correctly while removing leading zeros
283+
if (isNegative || numStr.startsWith("+")) {
284+
char sign = numStr.charAt(0);
285+
numStr = sign + numStr.substring(1).replaceFirst("^0+", "");
286+
} else {
287+
numStr = numStr.replaceFirst("^0+", "");
288+
}
289+
boolean hasDecimalPoint = false;
290+
boolean hasExponent = false;
291+
int mantissaSize = 0;
292+
StringBuilder exponentValue = new StringBuilder();
293+
int len = numStr.length();
294+
for (int i = 0; i < len; i++) {
295+
char c = numStr.charAt(i);
296+
if (c == '.') {
297+
hasDecimalPoint = true;
298+
} else if (c == 'e' || c == 'E') {
299+
hasExponent = true;
300+
} else if (c >= '0' && c <= '9') {
301+
if (!hasExponent) {
302+
mantissaSize++; // Count digits in the mantissa only
303+
} else {
304+
exponentValue.append(c);
305+
}
306+
}
307+
}
308+
if (hasDecimalPoint || hasExponent) {
309+
if (mantissaSize < 17 && (exponentValue.length() == 0 || Math.abs(Integer.parseInt(exponentValue.toString())) < 308)) {
310+
return Double.parseDouble(numStr);
311+
} else {
312+
return new BigDecimal(numStr);
313+
}
314+
} else {
315+
if (numStr.length() < 19) {
316+
return Long.parseLong(numStr);
317+
}
318+
BigInteger bigInt = new BigInteger(numStr);
319+
if (bigInt.compareTo(BIG_INT_LONG_MIN) >= 0 && bigInt.compareTo(BIG_INT_LONG_MAX) <= 0) {
320+
return bigInt.longValue(); // Correctly convert BigInteger back to Long if within range
321+
} else {
322+
return bigInt;
323+
}
324+
}
325+
}
326+
}

0 commit comments

Comments
 (0)