NumKit.java
package space.sunqian.fs.base.number;
import space.sunqian.annotation.Nonnull;
import space.sunqian.fs.Fs;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
* Utilities kit for number related.
*
* @author sunqian
*/
public class NumKit {
/**
* Default format pattern: "#.00".
*/
public static final @Nonnull String DEFAULT_PATTERN = "#.00";
/**
* Converts the given string to the specified number type. Supported number types are:
* <ul>
* <li>{@code byte}, {@link Byte}</li>
* <li>{@code short}, {@link Short}</li>
* <li>{@code char}, {@link Character} (Converts to {@link Integer} first, then to {@link Character})</li>
* <li>{@code int}, {@link Integer}</li>
* <li>{@code long}, {@link Long}</li>
* <li>{@code float}, {@link Float}</li>
* <li>{@code double}, {@link Double}</li>
* <li>{@link BigInteger}</li>
* <li>{@link BigDecimal}</li>
* </ul>
*
* @param str the given string
* @param numType the specified number type
* @param <T> the number type
* @return the converted number object
* @throws NumException if any error occurs during the conversion
*/
public static <T> @Nonnull T toNumber(
@Nonnull CharSequence str, Class<T> numType
) throws NumException {
try {
if (byte.class.equals(numType) || Byte.class.equals(numType)) {
return Fs.as(Byte.parseByte(str.toString()));
}
if (short.class.equals(numType) || Short.class.equals(numType)) {
return Fs.as(Short.parseShort(str.toString()));
}
if (char.class.equals(numType) || Character.class.equals(numType)) {
int i = Integer.parseInt(str.toString());
char c = (char) i;
return Fs.as(c);
}
if (int.class.equals(numType) || Integer.class.equals(numType)) {
return Fs.as(Integer.parseInt(str.toString()));
}
if (long.class.equals(numType) || Long.class.equals(numType)) {
return Fs.as(Long.parseLong(str.toString()));
}
if (float.class.equals(numType) || Float.class.equals(numType)) {
return Fs.as(Float.parseFloat(str.toString()));
}
if (double.class.equals(numType) || Double.class.equals(numType)) {
return Fs.as(Double.parseDouble(str.toString()));
}
if (BigInteger.class.equals(numType)) {
return Fs.as(new BigInteger(str.toString()));
}
if (BigDecimal.class.equals(numType)) {
return Fs.as(new BigDecimal(str.toString()));
}
} catch (Exception e) {
throw new NumException(e);
}
throw new NumException("Failed to convert " + str + " to " + numType + ".");
}
/**
* Converts the given number to the specified other number type. Supported other number types are:
* <ul>
* <li>{@code byte}, {@link Byte}</li>
* <li>{@code short}, {@link Short}</li>
* <li>{@code char}, {@link Character} (Converts to {@link Integer} first, then to {@link Character})</li>
* <li>{@code int}, {@link Integer}</li>
* <li>{@code long}, {@link Long}</li>
* <li>{@code float}, {@link Float}</li>
* <li>{@code double}, {@link Double}</li>
* <li>{@link BigInteger}</li>
* <li>{@link BigDecimal}</li>
* </ul>
*
* @param num the given number
* @param numType the specified other number type
* @param <T> the number type
* @return the converted number object
* @throws NumException if any error occurs during the conversion
*/
public static <T> @Nonnull T toNumber(
@Nonnull Number num, Class<T> numType
) throws NumException {
try {
if (numType.isAssignableFrom(num.getClass())) {
return numType.cast(num);
}
if (byte.class.equals(numType) || Byte.class.equals(numType)) {
return Fs.as(num.byteValue());
}
if (short.class.equals(numType) || Short.class.equals(numType)) {
return Fs.as(num.shortValue());
}
if (char.class.equals(numType) || Character.class.equals(numType)) {
int i = num.intValue();
char c = (char) i;
return Fs.as(c);
}
if (int.class.equals(numType) || Integer.class.equals(numType)) {
return Fs.as(num.intValue());
}
if (long.class.equals(numType) || Long.class.equals(numType)) {
return Fs.as(num.longValue());
}
if (float.class.equals(numType) || Float.class.equals(numType)) {
return Fs.as(num.floatValue());
}
if (double.class.equals(numType) || Double.class.equals(numType)) {
return Fs.as(num.doubleValue());
}
if (BigInteger.class.equals(numType)) {
if (num instanceof BigDecimal) {
@SuppressWarnings("PatternVariableCanBeUsed")
BigDecimal decimal = (BigDecimal) num;
return Fs.as(decimal.toBigInteger());
}
return Fs.as(new BigInteger(num.toString()));
}
if (BigDecimal.class.equals(numType)) {
if (num instanceof BigInteger) {
@SuppressWarnings("PatternVariableCanBeUsed")
BigInteger integer = (BigInteger) num;
return Fs.as(new BigDecimal(integer));
}
return Fs.as(new BigDecimal(num.toString()));
}
} catch (Exception e) {
throw new NumException(e);
}
throw new NumException("Failed to convert " + num + " to type: " + numType + ".");
}
/**
* Returns a {@link Number} object parsed from the given string. The actual type of the object may be
* {@link Integer}, {@link Long}, {@link BigInteger} or {@link BigDecimal}.
*
* @param cs the given string
* @return a {@link Number} object parsed from the given string
* @throws NumException if any error occurs during the parsing
*/
public static @Nonnull Number toNumber(@Nonnull CharSequence cs) throws NumException {
try {
return toNumber0(cs);
} catch (Exception e) {
throw new NumException(e);
}
}
private static @Nonnull Number toNumber0(@Nonnull CharSequence cs) throws NumberFormatException {
String str = cs.toString();
if (str.contains(".") || str.contains("e") || str.contains("E")) {
return new BigDecimal(str);
}
int len = str.length();
if (str.startsWith("-") || str.startsWith("+")) {
len--;
}
if (len <= 9) {
return Integer.parseInt(str);
}
if (len <= 18) {
return Long.parseLong(str);
}
return new BigInteger(str);
}
private NumKit() {
}
}