com.sunchenbin.store.feilong.core.lang.NumberUtil.java Source code

Java tutorial

Introduction

Here is the source code for com.sunchenbin.store.feilong.core.lang.NumberUtil.java

Source

/*
 * Copyright (C) 2008 feilong
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.sunchenbin.store.feilong.core.lang;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;

import com.sunchenbin.store.feilong.core.bean.ConvertUtil;
import com.sunchenbin.store.feilong.core.text.NumberFormatUtil;
import com.sunchenbin.store.feilong.core.util.Validator;

/**
 * ?{@link Integer},{@link Long},{@link BigDecimal}?.
 * 
 * <h3>{@link RoundingMode#HALF_UP} {@link Math#round(double)}:</h3>
 * 
 * <blockquote>
 * <p style="color:red">
 * ?{@link RoundingMode#HALF_UP} -2.5 ??-3, {@link Math#round(double) Math.round(-2.5)} -2
 * </p>
 * </blockquote>
 * 
 * <h3>{@link Double}{@link BigDecimal}:</h3>
 * 
 * <blockquote>
 * <p>
 *  double ? BigDecimal,?? BigDecimal.valueOf(double),?new BigDecimal(double),?? JDK API
 * </p>
 * <ol>
 * <li>new BigDecimal(0.1) {@code ==>} 0.1000000000000000055511151231257827021181583404541015625</li>
 * <li>BigDecimal.valueOf(0.1) {@code ==>} 0.1</li>
 * </ol>
 * <p>
 * Effective Java??,floatdouble???,? {@link java.math.BigDecimal}
 * </p>
 * </blockquote>
 * 
 * <h3><a name="RoundingMode">JAVA 8??:</a></h3>
 * 
 * <blockquote>
 * <table border="1" cellspacing="0" cellpadding="4">
 * <tr style="background-color:#ccccff">
 * <th align="left"></th>
 * <th align="left"></th>
 * </tr>
 * <tr valign="top">
 * <td>{@link RoundingMode#UP}</td>
 * <td>??. ????,?????0??.</td>
 * </tr>
 * <tr valign="top" style="background-color:#eeeeff">
 * <td>{@link RoundingMode#DOWN}</td>
 * <td>???,????,???,??.</td>
 * </tr>
 * <tr valign="top">
 * <td>{@link RoundingMode#CEILING}</td>
 * <td>??? ??? ???.<br>
 * ,?ROUND_UP,<br>
 * ,?ROUND_DOWN.<br>
 * <span style="color:red">Math.round()?.</span></td>
 * </tr>
 * <tr valign="top" style="background-color:#eeeeff">
 * <td>{@link RoundingMode#FLOOR}</td>
 * <td>??? ??? ???.<br>
 * ,?ROUND_DOWN<br>
 * ,?ROUND_UP.</td>
 * </tr>
 * <tr valign="top">
 * <td>{@link RoundingMode#HALF_UP}</td>
 * <td>?,?.<br>
 * ?(5).<span style="color:red">??</span>.</td>
 * </tr>
 * <tr valign="top" style="background-color:#eeeeff">
 * <td>{@link RoundingMode#HALF_DOWN}</td>
 * <td>?,?(5?). 5??.</td>
 * </tr>
 * <tr valign="top">
 * <td>{@link RoundingMode#HALF_EVEN}</td>
 * <td>?,?. <br>
 * ?;?,??,?,??. <br>
 * ???1?,???: <br>
 * {@code 1.15 return 1.2} {@code 1.25 return 1.2}</td>
 * </tr>
 * <tr valign="top" style="background-color:#eeeeff">
 * <td>{@link RoundingMode#UNNECESSARY}</td>
 * <td>?</td>
 * </tr>
 * </table>
 * </blockquote>
 *
 * @author feilong
 * @version 1.4.0 201583 ?3:06:20
 * @see Integer
 * @see Long
 * @see BigDecimal
 * @see Number
 * @see NumberPattern
 * @see RoundingMode
 * @see org.apache.commons.lang3.math.NumberUtils
 * @since 1.4.0
 */
public final class NumberUtil {

    /** Don't let anyone instantiate this class. */
    private NumberUtil() {
        //AssertionError?. ?????. ???.
        //see Effective Java 2nd
        throw new AssertionError("No " + getClass().getName() + " instances for you!");
    }

    /**
     * ? {@link RoundingMode#HALF_UP},?,?.
     * 
     * <p style="color:red">
     * ?{@link RoundingMode#HALF_UP} -2.5 ??-3, Math.round(-2.5) -2
     * </p>
     * 
     * @param number
     *            number,?,?number
     * @return ?{@link RoundingMode#HALF_UP},?,?<br>
     *          isNotNullOrEmpty(number)null
     * @see <a href="#RoundingMode">JAVA 8??</a>
     */
    public static BigDecimal toNoScale(Serializable number) {
        RoundingMode roundingMode = RoundingMode.HALF_UP;
        return toNoScale(number, roundingMode);
    }

    /**
     * To no scale.
     * 
     * @param number
     *            number,?,?number
     * @param roundingMode
     *            ? {@link RoundingMode}
     * @return {@link RoundingMode},?,?<br>
     *          isNotNullOrEmpty(number)null {@link RoundingMode},?,?
     * @see <a href="#RoundingMode">JAVA 8??</a>
     * @since 1.0.7
     */
    public static BigDecimal toNoScale(Serializable number, RoundingMode roundingMode) {
        if (Validator.isNullOrEmpty(number)) {
            return null;
        }
        //int?long?double?stringBigDecimal.double?,
        //BigDecimal,String??.
        BigDecimal bigDecimal = ConvertUtil.toBigDecimal(number);
        return setScale(bigDecimal, 0, roundingMode);
    }

    // ***********************************************************************************

    // [start]Divide

    /**
     *  one/two,? ?,???toNoScale?.
     * <p>
     * two 0,one<br>
     * ?one/two,??.
     * 
     * @param one
     *            
     * @param two
     *            ,?BigDecimal??
     * @return two 0,one<br>
     *         ?one/two,? ?
     */
    public static BigDecimal getDivideNoScaleValue(BigDecimal one, Serializable two) {
        return getDivideValue(one, two, 0);
    }

    /**
     * ,? {@link NumberPattern#PERCENT_WITH_NOPOINT}.
     *
     * @param current
     *            ??
     * @param total
     *            ?
     * @return 50% 56% 58%???
     * @see NumberPattern
     * @since 1.0.7
     */
    public static String getProgress(Number current, Number total) {
        String numberPattern = NumberPattern.PERCENT_WITH_NOPOINT;
        return getProgress(current, total, numberPattern);
    }

    /**
     * .
     * 
     * <pre>
     * {@code
     *   Example 1:  
     *      NumberUtil.getProgress(5, 5, "##%")
     *      return 100%
     *   
     *   Example 2:
     *      NumberUtil.getProgress(2, 3, "#0.0%")
     *      return 66.7%
     * }
     * </pre>
     *
     * @param current
     *            ??
     * @param total
     *            ?
     * @param numberPattern
     *            the number pattern {@link NumberPattern}
     * @return ?numberPattern  50.5%,100%.....
     * @see NumberPattern
     * @since 1.0.7
     */
    public static String getProgress(Number current, Number total, String numberPattern) {
        if (null == current) {
            throw new NullPointerException("current is null");
        }
        if (null == total) {
            throw new NullPointerException("total is null");
        }

        if (current.intValue() <= 0) {
            throw new IllegalArgumentException("current can not <=0");
        }
        if (total.intValue() <= 0) {
            throw new IllegalArgumentException("total can not <=0");
        }

        if (current.doubleValue() > total.doubleValue()) {
            throw new IllegalArgumentException("current can not > total");
        }
        // XXX
        int scale = 8;
        BigDecimal bigDecimalCurrent = ConvertUtil.toBigDecimal(current);
        BigDecimal divideValue = getDivideValue(bigDecimalCurrent, total, scale);
        return toString(divideValue, numberPattern);
    }

    /**
     *  one/two,? {@link RoundingMode#HALF_UP},??.
     * 
     * <p>
     * two0,one<br>
     * ?one/two,?,??.
     * </p>
     * 
     * @param one
     *            
     * @param two
     *            ,?BigDecimal??
     * @param scale
     *            ? BigDecimal ,??
     * @return two 0,one<br>
     *         ?one/two,? {@link RoundingMode#HALF_UP},??
     * @see <a href="#RoundingMode">JAVA 8??</a>
     * @see java.math.RoundingMode#HALF_UP
     * @see java.math.BigDecimal#ROUND_HALF_UP
     */
    public static BigDecimal getDivideValue(BigDecimal one, Serializable two, int scale) {
        RoundingMode roundingMode = RoundingMode.HALF_UP;
        return getDivideValue(one, two, scale, roundingMode);
    }

    /**
     *  one/two,?,??.
     * 
     * <p>
     * two 0,one<br>
     * ?one/two,?,??.
     * </p>
     * 
     * <p>
     * <b>?:</b> <span style="color:red">?one.divide(two),?? exception:Non-terminating decimal expansion; no exact representable decimal
     * result</span><br>
     * scaleroundingMode,?????.
     * </p>
     *
     * @param one
     *            
     * @param two
     *            ,?BigDecimal??
     * @param scale
     *            ? BigDecimal ,??
     * @param roundingMode
     *            ? {@link RoundingMode}
     * @return two 0,one<br>
     *         ?one/two,??? {@link RoundingMode},??
     * @see <a href="#RoundingMode">JAVA 8??</a>
     * @since 1.0.7
     */
    public static BigDecimal getDivideValue(BigDecimal one, Serializable two, int scale,
            RoundingMode roundingMode) {

        if (Validator.isNullOrEmpty(roundingMode)) {
            throw new NullPointerException("the roundingMode is null or empty!");
        }
        String zero = "0";
        if (!isSpecificNumber(two, zero)) {
            // ?one.divide(two) 
            // ?? exception:Non-terminating decimal expansion; no exact representable decimal result
            // scaleroundingMode,?????.
            BigDecimal divisor = ConvertUtil.toBigDecimal(two);
            return one.divide(divisor, scale, roundingMode);
        }
        return one;
    }

    // [end]

    // [start]Multiply

    /**
     * .
     * 
     * @param one
     *            
     * @param two
     *            
     * @param scale
     *            ,??,?
     * @return  <br>
     *         if isNotNullOrEmpty(two) return one
     * @see #getMultiplyValue(BigDecimal, Serializable)
     * @see #setScale(BigDecimal, int)
     */
    public static BigDecimal getMultiplyValue(BigDecimal one, Serializable two, int scale) {
        BigDecimal result = getMultiplyValue(one, two);
        return setScale(result, scale);
    }

    /**
     *  multiply value.
     * 
     * <p>
     * scale: (this.scale() + multiplicand.scale()).
     * </p>
     *
     * @param one
     *            
     * @param two
     *            
     * @return  <br>
     *         if isNotNullOrEmpty(two) return one
     * @see java.math.BigDecimal#multiply(BigDecimal)
     * @since 1.0.8
     */
    public static BigDecimal getMultiplyValue(BigDecimal one, Serializable two) {
        if (Validator.isNullOrEmpty(two)) {
            return one;
        }

        BigDecimal multiplicand = ConvertUtil.toBigDecimal(two);
        return one.multiply(multiplicand);
    }

    /**
     *  multiply value.
     * 
     * <p>
     * scale: (this.scale() + multiplicand.scale()).
     * </p>
     * 
     * @param one
     *            
     * @param two
     *            
     * @return  <br>
     *         if isNotNullOrEmpty(two) return one
     * @see #getMultiplyValue(BigDecimal, Serializable)
     * @since 1.2.1
     */
    public static BigDecimal getMultiplyValue(Number one, Serializable two) {
        return getMultiplyValue(ConvertUtil.toBigDecimal(one), two);
    }

    // [end]

    // [start]Add

    /**
     * ,null.
     * 
     * @param one
     *            
     * @param two
     *            
     * @return <ul>
     *         <li> null,null</li>
     *         <li>null,?null,,?BigDecimal </li>
     *         <li>?null,null,</li>
     *         <li>(?), +</li>
     *         </ul>
     * @since 1.0
     */
    public static BigDecimal /* <T> T */ getAddValue(Number one, Number two) {
        //  null,null
        if (Validator.isNullOrEmpty(one) && Validator.isNullOrEmpty(two)) {
            return null;
        }
        // ?null,null,
        if (!Validator.isNullOrEmpty(one) && Validator.isNullOrEmpty(two)) {
            // ObjectUtil.toT(value, class1)
            return ConvertUtil.toBigDecimal(one);
        }

        BigDecimal augend = ConvertUtil.toBigDecimal(two);
        // null,?null,,?BigDecimal 
        if (Validator.isNullOrEmpty(one) && !Validator.isNullOrEmpty(two)) {
            return augend;
        }

        // (?), +
        return ConvertUtil.toBigDecimal(one).add(augend);
    }

    /**
     * ?(null).
     *
     * @param numbers
     *            the numbers
     * @return the  value
     * @since 1.2.1
     */
    public static BigDecimal getAddValue(Number... numbers) {
        BigDecimal returnValue = BigDecimal.ZERO;
        for (Number number : numbers) {
            if (Validator.isNotNullOrEmpty(number)) {
                BigDecimal bigDecimal = ConvertUtil.toBigDecimal(number);
                returnValue = returnValue.add(bigDecimal);
            }
        }
        return returnValue;
    }

    // [end]

    /**
     * ?? ??? 0.0,0.5,1.0,1.5,2.0,2.5....
     * 
     * <p>
     *  
     * </p>
     *
     * @param value
     *            
     * @return 0.0,0.5,1.0,1.5,2.0,2.5.......
     */
    public static String toPointFive(Number value) {
        if (Validator.isNullOrEmpty(value)) {
            throw new NullPointerException("value can't be null/empty!");
        }
        long avgRankLong = Math.round(Double.parseDouble(value.toString()) * 2);

        BigDecimal avgBigDecimal = BigDecimal.valueOf((double) (avgRankLong) / 2);
        return setScale(avgBigDecimal, 1).toString();
    }

    /**
     * ?, {@link NumberFormatUtil#format(Number, String)}  .
     * 
     * <h3>:</h3>
     * 
     * <blockquote>
     * 
     * <pre>
     * {@code
     *  
     *  ?,??, 0.24?24%
     *  NumberUtil.toString(0.24f, NumberPattern.PERCENT_WITH_NOPOINT)
     *  
     *  ?,??, 0.24?24.00%
     *  NumberUtil.toString(0.24f, NumberPattern.PERCENT_WITH_2POINT)
     *  }
     * </pre>
     * 
     * </blockquote>
     * 
     * @param value
     *            
     * @param pattern
     *             {@link NumberPattern}
     * @return ??
     * 
     * @see NumberFormatUtil#format(Number, String)
     */
    public static String toString(Number value, String pattern) {
        return NumberFormatUtil.format(value, pattern);
    }

    // *****************************************************************************************************
    /**
     * int??16.
     * 
     * @param i
     *            int
     * @return int??16
     */
    public static String intToHexString(int i) {
        return Integer.toHexString(i);
    }

    /**
     * 16?int.
     * 
     * @param hexString
     *            16
     * @return int
     */
    public static int hexStringToInt(String hexString) {
        return Integer.parseInt(hexString, 16);
    }

    /**
     * Object  value,?.
     * 
     * <p>
     * value ?BigDecimal,specificNumber ?BigDecimal ,BigDecimal compareTo,<br>
     * 0 ,true.
     * </p>
     * 
     * @param value
     *            Object  value, Number  String
     * @param specificNumber
     *            
     * @return value ?BigDecimal,specificNumber ?BigDecimal ,BigDecimal compareTo,<br>
     *         0 ,true
     */
    public static boolean isSpecificNumber(Serializable value, String specificNumber) {
        if (Validator.isNullOrEmpty(value)) {
            return false;
        }

        String valueString = value.toString();
        // Number /String
        if (value instanceof Number || value instanceof String) {
            BigDecimal bigDecimal = ConvertUtil.toBigDecimal(valueString);
            int i = bigDecimal.compareTo(ConvertUtil.toBigDecimal(specificNumber));
            return i == 0;
        }
        return false;
    }

    /**
     * ? ??? {@link RoundingMode#HALF_UP} ??.
     * 
     * <p>
     * ?>=0.5? ??<br>
     * </p>
     * 
     * <p style="color:red">
     * ?{@link RoundingMode#HALF_UP} -2.5 ??-3, Math.round(-2.5) -2
     * </p>
     * 
     * @param number
     *            number
     * @param scale
     *            ??
     * @return the big decimal
     * @see <a href="#RoundingMode">JAVA 8??</a>
     * @see java.math.RoundingMode#HALF_UP
     * @see java.math.BigDecimal#ROUND_HALF_UP
     */
    private static BigDecimal setScale(BigDecimal number, int scale) {
        RoundingMode roundingMode = RoundingMode.HALF_UP;
        return setScale(number, scale, roundingMode);
    }

    /**
     * .
     * 
     * @param number
     *            number
     * @param scale
     *            ??
     * @param roundingMode
     *            ? {@link RoundingMode} ?: {@link <a href="#RoundingMode">JAVA 8??</a>}
     * @return the big decimal
     * @see <a href="#RoundingMode">JAVA 8??</a>
     */
    private static BigDecimal setScale(BigDecimal number, int scale, RoundingMode roundingMode) {
        return number.setScale(scale, roundingMode);
    }
}