Java tutorial
/* * 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.feilong.core.lang; import static java.math.RoundingMode.HALF_UP; import java.math.BigDecimal; import java.math.RoundingMode; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import com.feilong.core.NumberPattern; import com.feilong.core.text.NumberFormatUtil; import static com.feilong.core.bean.ConvertUtil.toBigDecimal; /** * ?{@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" summary=""> * <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 1.2} {@code 1.25 1.2}</td> * </tr> * <tr valign="top" style="background-color:#eeeeff"> * <td>{@link RoundingMode#UNNECESSARY}</td> * <td>?</td> * </tr> * </table> * </blockquote> * * @author <a href="http://feitianbenyue.iteye.com/">feilong</a> * @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!"); } // [start]Divide /** * <code>one/two</code>,?{@link RoundingMode#HALF_UP},?? <code>scale</code> . * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * NumberUtil.getDivideValue(0, 2, 0) = 0 * NumberUtil.getDivideValue(6, 4, 0) = 2 * NumberUtil.getDivideValue(10, 3, 2) = 3.33 * NumberUtil.getDivideValue(5, 3, 2) = 1.67 * </pre> * * </blockquote> * * @param one * * @param two * ,?{@link BigDecimal}?? * @param scale * ,??,?,see {@link java.math.BigDecimal#setScale(int, RoundingMode)} * @return <code>one</code> null, {@link NullPointerException}<br> * <code>two</code> null, {@link NullPointerException}<br> * <code>two</code> 0, {@link IllegalArgumentException}<br> * ???{@link BigDecimal} one/two,? {@link RoundingMode#HALF_UP},?? <code>scale</code> * @see <a href="#RoundingMode">JAVA 8??</a> * @see java.math.RoundingMode#HALF_UP * @see java.math.BigDecimal#ROUND_HALF_UP * @see #getDivideValue(Number, Number, int, RoundingMode) * @since 1.5.5 */ public static BigDecimal getDivideValue(Number one, Number two, int scale) { return getDivideValue(one, two, scale, HALF_UP); } /** * <code>one/two</code>,?? <code>roundingMode</code> ? ?? <code>scale</code>. * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * NumberUtil.getDivideValue(0, 2, 0,RoundingMode.HALF_UP) = 0 * NumberUtil.getDivideValue(6, 4, 0,RoundingMode.HALF_UP) = 2 * NumberUtil.getDivideValue(10, 3, 2,RoundingMode.HALF_UP) = 3.33 * NumberUtil.getDivideValue(5, 3, 2,RoundingMode.HALF_UP) = 1.67 * </pre> * * </blockquote> * * @param one * * @param two * ,?{@link BigDecimal}?? * @param scale * ,??,see {@link java.math.BigDecimal#setScale(int, RoundingMode)} * @param roundingMode * ? {@link RoundingMode} * @return <code>one</code> null, {@link NullPointerException}<br> * <code>two</code> null, {@link NullPointerException}<br> * <code>two</code> 0, {@link IllegalArgumentException}<br> * ???{@link BigDecimal} one/two,??? <code>roundingMode</code>,?? <code>scale</code> * @see <a href="#RoundingMode">JAVA 8??</a> * @see java.math.BigDecimal#divide(BigDecimal, int, RoundingMode) * @since 1.5.5 */ public static BigDecimal getDivideValue(Number one, Number two, int scale, RoundingMode roundingMode) { Validate.notNull(one, "one can't be null!"); Validate.notNull(two, "two can't be null!"); BigDecimal divisor = toBigDecimal(two); Validate.isTrue(!divisor.equals(new BigDecimal(0)), "two can't be zero!"); // ?one.divide(two),scaleroundingMode,?????. // ?? exception:Non-terminating decimal expansion; no exact representable decimal result return toBigDecimal(one).divide(divisor, scale, roundingMode); } // [end] // [start]Multiply /** * ,?{@link BigDecimal}. * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * NumberUtil.getMultiplyValue(5, 2, 5) = 10.00000 * NumberUtil.getMultiplyValue(new BigDecimal(6.25), 1.17, 5) = 7.31250 * </pre> * * </blockquote> * * @param one * * @param two * * @param scale * ,??,?,see {@link java.math.BigDecimal#setScale(int, RoundingMode)} * @return <code>one</code> null, {@link NullPointerException}<br> * <code>two</code> null, {@link NullPointerException}<br> * ? convert to {@link BigDecimal} and multiply each other * @see #setScale(BigDecimal, int) * @since 1.5.5 */ public static BigDecimal getMultiplyValue(Number one, Number two, int scale) { Validate.notNull(one, "one can't be null!"); Validate.notNull(two, "two can't be null!"); //: (this.scale() + multiplicand.scale()). BigDecimal multiplyValue = toBigDecimal(one).multiply(toBigDecimal(two)); return setScale(multiplyValue, scale); } // [end] // [start]Add /** * ?. * * <h3>:</h3> * * <blockquote> * * <pre class="code"> * NumberUtil.getAddValue(2, 4, 5) = 11 * NumberUtil.getAddValue(new BigDecimal(6), 5) = 11 * </pre> * * </blockquote> * * @param numbers * the numbers * @return <code>numbers</code> null, {@link NullPointerException}<br> * null, {@link IllegalArgumentException}<br> * ????{@link BigDecimal},? * @since 1.5.5 */ public static BigDecimal getAddValue(Number... numbers) { Validate.noNullElements(numbers, "numbers can't be null!"); BigDecimal sum = BigDecimal.ZERO; for (Number number : numbers) { sum = sum.add(toBigDecimal(number)); } return sum; } // [end] /** * ?? ??? 0.0,0.5,1.0,1.5,2.0,2.5.... * * <p> * * </p> * * @param value * * @return <code>value</code> null, {@link NullPointerException} */ public static String toPointFive(Number value) { Validate.notNull(value, "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> * * <pre class="code"> * //?,?? * NumberUtil.toString(0.24f, NumberPattern.PERCENT_WITH_NOPOINT) = 24% * * //?,?? * NumberUtil.toString(0.24f, NumberPattern.PERCENT_WITH_2POINT) = 24.00% * </pre> * * @param value * * @param numberPattern * {@link NumberPattern} * @return <code>value</code> null, {@link NullPointerException}<br> * <code>numberPattern</code> null, {@link NullPointerException}<br> * <code>numberPattern</code> blank, {@link IllegalArgumentException}<br> * , {@link StringUtils#EMPTY} * @see NumberFormatUtil#format(Number, String) */ public static String toString(Number value, String numberPattern) { return NumberFormatUtil.format(value, numberPattern); } // ***************************************************************************************************** /** * ,? {@link NumberPattern#PERCENT_WITH_NOPOINT}. * * <h3>:</h3> * <blockquote> * * <pre class="code"> * NumberUtil.getProgress(2, 3) = 67% * </pre> * * </blockquote> * * @param current * ?? * @param total * ? * @return <code>current</code> null, {@link NullPointerException}<br> * <code>total</code> null, {@link NullPointerException}<br> * {@code current<=0}, {@link IllegalArgumentException}<br> * {@code total<=0}, {@link IllegalArgumentException}<br> * {@code current>total}, {@link IllegalArgumentException}<br> * @see NumberPattern#PERCENT_WITH_NOPOINT * @see #getProgress(Number, Number, String) * @since 1.0.7 */ public static String getProgress(Number current, Number total) { return getProgress(current, total, NumberPattern.PERCENT_WITH_NOPOINT); } /** * . * * <pre class="code"> * NumberUtil.getProgress(5, 5, NumberPattern.PERCENT_WITH_NOPOINT) = 100% * NumberUtil.getProgress(2, 3, NumberPattern.PERCENT_WITH_1POINT) = 66.7% * </pre> * * @param current * ?? * @param total * ? * @param numberPattern * the number pattern {@link NumberPattern} * @return <code>current</code> null, {@link NullPointerException}<br> * <code>total</code> null, {@link NullPointerException}<br> * {@code current<=0}, {@link IllegalArgumentException}<br> * {@code total<=0}, {@link IllegalArgumentException}<br> * {@code current>total}, {@link IllegalArgumentException}<br> * @see NumberPattern * @see #getDivideValue(Number, Number, int) * @since 1.0.7 */ public static String getProgress(Number current, Number total, String numberPattern) { Validate.notNull(current, "current can't be null/empty!"); Validate.notNull(total, "total can't be null/empty!"); Validate.isTrue(current.intValue() > 0, "current can not <=0"); Validate.isTrue(total.intValue() > 0, "total can not <=0"); Validate.isTrue(current.doubleValue() <= total.doubleValue(), "current can not > total"); // XXX scale = 8? int scale = 8; BigDecimal bigDecimalCurrent = toBigDecimal(current); BigDecimal divideValue = getDivideValue(bigDecimalCurrent, total, scale); return toString(divideValue, numberPattern); } /** * ? {@link RoundingMode#HALF_UP},?,?. * * <p style="color:red"> * ?{@link RoundingMode#HALF_UP} -2.5 ??-3, {@link Math#round(double) Math.round(-2.5)} -2 * </p> * * @param value * the value * @return <code>value</code> null, {@link NullPointerException}<br> * @see <a href="#RoundingMode">JAVA 8??</a> * @see #toNoScale(Number, RoundingMode) */ public static BigDecimal toNoScale(Number value) { return toNoScale(value, HALF_UP); } /** * ?,?. * * <p style="color:red"> * ?:{@link RoundingMode#HALF_UP} -2.5 ??-3, {@link Math#round(double) Math.round(-2.5)} -2 * </p> * * @param value * the value * @param roundingMode * ? {@link RoundingMode} * @return <code>value</code> null, {@link NullPointerException}<br> * <code>roundingMode</code> null, {@link NullPointerException}<br> * @see <a href="#RoundingMode">JAVA 8??</a> * @since 1.5.5 */ public static BigDecimal toNoScale(Number value, RoundingMode roundingMode) { Validate.notNull(value, "value can't be null!"); Validate.notNull(roundingMode, "roundingMode can't be null!"); //int?long?double?stringBigDecimal. //double?,BigDecimal,String??. return setScale(toBigDecimal(value), 0, roundingMode); } //************************************************************************************************ /** * ? ??? {@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 value * number * @param scale * ,??,?,see {@link java.math.BigDecimal#setScale(int, RoundingMode)} * @return <code>value</code> null, {@link NullPointerException}<br> * @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 value, int scale) { return setScale(value, scale, HALF_UP); } /** * . * * @param value * number * @param scale * ,??,see {@link java.math.BigDecimal#setScale(int, RoundingMode)} * @param roundingMode * ? {@link RoundingMode} ?:<a href="#RoundingMode">JAVA 8??</a> * @return <code>value</code> null, {@link NullPointerException}<br> * <code>roundingMode</code>null, {@link NullPointerException} * @see <a href="#RoundingMode">JAVA 8??</a> */ private static BigDecimal setScale(BigDecimal value, int scale, RoundingMode roundingMode) { Validate.notNull(value, "value can't be null!"); Validate.notNull(roundingMode, "roundingMode can't be null!"); return value.setScale(scale, roundingMode); } }