package org.jetbrains.dekaf.util; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Nullable; import java.math.BigDecimal; import java.math.BigInteger; /** * @author Leonid Bushuev from JetBrains */ public abstract class Numbers { /** * Checks whether tow numbers have equal values (even they are instances of different classes). * * @param x the first number. * @param y the second number. * @return whether they're equal. */ public static boolean valuesAreEqual(@Nullable final Number x, @Nullable final Number y) { //noinspection NumberEquality if (x == y) return true; //noinspection SimplifiableIfStatement if (x == null || y == null) return false; return x.getClass() == y.getClass() ? x.equals(y) : x.toString().equals(y.toString()); } /** * Converts an arbitrary number to the specified class of Number. * @param <N> desired type of number. * @param numberClass desired class of number. * @param number the number to convert (nulls are possible). * @return the converted number. */ @SuppressWarnings("unchecked") @Contract(value = "_,!null -> !null; _,null -> null", pure = true) public static <N extends Number> N convertNumber(final Class<N> numberClass, final Number number) { if (number == null) return null; if (numberClass.isAssignableFrom(number.getClass())) return (N) number; if (numberClass == Byte.class || numberClass == byte.class) return (N) new Byte(number.byteValue()); if (numberClass == Short.class || numberClass == short.class) return (N) new Short(number.shortValue()); if (numberClass == Integer.class || numberClass == int.class) return (N) new Integer(number.intValue()); if (numberClass == Long.class || numberClass == long.class) return (N) new Long(number.longValue()); if (numberClass == Float.class || numberClass == float.class) return (N) new Float(number.floatValue()); if (numberClass == Double.class || numberClass == double.class) return (N) new Double(number.doubleValue()); if (numberClass == BigInteger.class) return (N) new BigInteger(number.toString()); if (numberClass == BigDecimal.class) return (N) new BigDecimal(number.toString()); String message = String.format("Unknown how to convert value (%s) of type %s to %s.", number.toString(), number.getClass().getCanonicalName(), numberClass.getCanonicalName()); throw new IllegalArgumentException(message); } @Contract(value = "!null -> !null; null -> null", pure = true) public static Number convertNumberSmartly(final BigDecimal decimal) { if (decimal == null) return null; if (decimal.equals(Numbers.DECIMAL_ZERO)) return BYTE_ZERO; final int precision = decimal.precision(); final int scale = decimal.scale(); Number num; if (scale == 0) { try { if (precision <= 19 && decimal.compareTo(Numbers.DECIMAL_MIN_LONG) >= 0 && decimal.compareTo(Numbers.DECIMAL_MAX_LONG) <= 0) { long v = decimal.longValueExact(); if (-128 <= v && v <= 127) num = (byte) v; else if (-32768 <= v && v <= 32767) num = (short) v; else if (Integer.MIN_VALUE <= v && v <= Integer.MAX_VALUE) num = (int) v; else num = v; } else { num = decimal.toBigIntegerExact(); } } catch (ArithmeticException ae) { num = decimal; } } else { if (precision <= 6) { num = decimal.floatValue(); } else if (precision <= 15) { num = decimal.doubleValue(); } else { num = decimal; } } return num; } public static int parseIntSafe(@Nullable final String str) { if (str == null) { return 0; } try { final String s = str.trim(); if (s.isEmpty()) return 0; if (s.charAt(0) == '+') return Integer.parseInt(s.substring(1)); return Integer.parseInt(s); } catch (NumberFormatException e) { return 0; } } public static long parseLongSafe(@Nullable final String str) { if (str == null) { return 0; } try { final String s = str.trim(); if (s.isEmpty()) return 0L; if (s.charAt(0) == '+') return Long.parseLong(s.substring(1)); return Long.parseLong(s); } catch (NumberFormatException e) { return 0; } } public static final Byte BYTE_ZERO = (byte) 0; public static final BigDecimal DECIMAL_ZERO = new BigDecimal(0); public static final BigDecimal DECIMAL_MIN_LONG = new BigDecimal(Long.MIN_VALUE); public static final BigDecimal DECIMAL_MAX_LONG = new BigDecimal(Long.MAX_VALUE); }