Java中存储金额用什么数据类型-BigDecimal

文章目录

  • 1.引子
  • 2. 加减乘除
  • 3. 大小比较
  • 4. 小数位数及四舍五入规则
  • 5.金额工具类 AmountUtil

1.引子

很早之前, 记得一次面试, 面试官问存储金钱用什么数据类型? 当时只知道8种数据类型(boolean, byte, short, int, long, float, double, char)的我, 回答了double, 因为我觉得double是双精度类型, 最适合, 但是面试官告诉我应该用BigDecimal! 最近在做支付的项目, 才对这种数据类型有了更多的了解;

结果是:1915.1799,而不是 1915.18,出现失真的问题

解决办法(X):想办法把数据四舍五入然后存到数据库

出现问题:当多操作了几次后,直接到数据库检查金额是否正确的时候,失真问题依然存在,只不过存在于数据库而不是存在与程序。

原因:float和double都是浮点数, 都有取值范围,都有精度范围。浮点数与通常使用的小数不同,使用中,往往难以确定。常见的问题是定义了一个浮点数,经过一系列的计算,它本来应该等于某个确定值,但实际上并不是,金额必须是完全精确的计算,故不能使用double或者float

解决办法:

在程序中存储金额的数据类型用:java.math.BigDecimal,在数据库中存储金额的数据类型用:decimal

长度可以自定义,如10,小数点在项目中用的是2,保留2位小数。

此外还要注意的就是默认值,一定写成0.00,不要用默认的NULL,否则在进行加减排序等操作时,会带来转换的麻烦。

SQL: 'amount' DECIMAL(10, 2) DEFAULT 0.00 NOT NULL COMMENT '金额',

2. 加减乘除

两个 BigDecimal 的值不能用 +、-、*、/ 来进行加减乘除

public static void main(String[] args){
    BigDecimal x = new BigDecimal("1.3");
    BigDecimal y = new BigDecimal("2.5");
	// 加法 --> 3.8
	BigDecimal add = x.add(y);
	System.out.println(add);
	// 减法 --> -1.2
	BigDecimal subtract = x.subtract(y);
	System.out.println(subtract);
	// 乘法 --> 3.25
	BigDecimal multiply = x.multiply(y);
	System.out.println(multiply);
	// 除法 --> 0.5  ,RoundingMode.HALF_UP 四舍五入
	BigDecimal divide = x.divide(y, RoundingMode.HALF_UP);
	System.out.println(divide);
}

3. 大小比较

两个BigDecimal值比较使用compareTo方法,比较结果有-1,0,1,分别表示小于, 等于, 大于

对于0,使用BigDecimal.ZERO表示

BigDecimal num = new BigDecimal("-3");
if (num.compareTo(BigDecimal.ZERO) == -1) {
	System.out.println("num 小于 0")} else if  (num.compareTo(BigDecimal.ZERO) == 1) {
	System.out.println("num 大于 0")} else if  (num.compareTo(BigDecimal.ZERO) == 0) {
	System.out.println("num 等于 0")}

4. 小数位数及四舍五入规则

setScale方法的第一个参数是小数位数,这个示例是保留2位小数,后面是四舍五入规则

public static void main(String[] args){
    BigDecimal num = new BigDecimal("10.2621684798165165");
    System.out.println("原型 = " + num);
    System.out.println("直接删除多余的小数位 = " + num.setScale(2, BigDecimal.ROUND_DOWN));
    System.out.println("进位 = " + num.setScale(2, BigDecimal.ROUND_UP));
    System.out.println("四舍五入,碰到5位进位 = " + num.setScale(2, BigDecimal.ROUND_HALF_UP));
    System.out.println("四舍五入,碰到5位舍弃 = " + num.setScale(2, BigDecimal.ROUND_HALF_DOWN));
}

5.金额工具类 AmountUtil

import java.math.BigDecimal;
import java.text.DecimalFormat;

/**
 * 

* * @author coder * @since 2019-08-17 */ public class AmountUtil { public static DecimalFormat fnum = new DecimalFormat("##0.00000000000000000000"); /** * 格式化金额 * * @param valueStr * @return String */ public static String formatMoney(String valueStr) { if (valueStr == null || valueStr == "") { valueStr = "0.00"; } return fnum.format(new BigDecimal(valueStr)); } /** * 金额相加 * * @param valueStr 基础值 * @param addStr 被加数 * @return String */ public static String moneyAdd(String valueStr, String addStr) { BigDecimal value = new BigDecimal(valueStr); BigDecimal augend = new BigDecimal(addStr); return fnum.format(value.add(augend)); } /** * 金额相加 * * @param valueStr 基础值 * @param minusValueStr 被加数 * @return BigDecimal */ public static BigDecimal moneyAdd(BigDecimal valueStr, BigDecimal minusValueStr) { return valueStr.add(minusValueStr); } /** * 金额相减 * * @param valueStr 基础值 * @param minusValueStr 减数 * @return String */ public static String moneySub(String valueStr, String minusValueStr) { BigDecimal value = new BigDecimal(valueStr); BigDecimal subtrahend = new BigDecimal(minusValueStr); return fnum.format(value.subtract(subtrahend)); } /** * 金额相减 * * @param value 基础值 * @param subtrahend 减数 * @return BigDecimal */ public static BigDecimal moneySub(BigDecimal value, BigDecimal subtrahend) { return value.subtract(subtrahend); } /** * 金额相乘 * * @param valueStr 基础值 * @param minusValueStr 被乘数 * @return String */ public static String moneyMul(String valueStr, String minusValueStr) { BigDecimal value = new BigDecimal(valueStr); BigDecimal mulValue = new BigDecimal(minusValueStr); return fnum.format(value.multiply(mulValue)); } /** * 金额相乘 * * @param value 基础值 * @param mulValue 被乘数 * @return BigDecimal */ public static BigDecimal moneyMul(BigDecimal value, BigDecimal mulValue) { return value.multiply(mulValue); } /** * 金额相除
* 精确小位小数 * * @param valueStr 基础值 * @param minusValueStr 被乘数 * @return String */
public static String moneydiv(String valueStr, String minusValueStr) { BigDecimal value = new BigDecimal(valueStr); BigDecimal divideValue = new BigDecimal(minusValueStr); return fnum.format(value.divide(divideValue, 2, BigDecimal.ROUND_HALF_UP)); } /** * 金额相除
* 精确小位小数 * * @param value 基础值 * @param divideValue 被乘数 * @return BigDecimal */
public static BigDecimal moneydiv(BigDecimal value, BigDecimal divideValue) { return value.divide(divideValue, 2, BigDecimal.ROUND_HALF_UP); } /** * 值比较大小 *
如果valueStr大于等于compValueStr,则返回true,否则返回false * true 代表可用余额不足 * * @param valueStr (需要消费金额) * @param compValueStr (可使用金额) * @return boolean */
public static boolean moneyComp(String valueStr, String compValueStr) { BigDecimal value = new BigDecimal(valueStr); BigDecimal compValue = new BigDecimal(compValueStr); //0:等于 >0:大于 <0:小于 int result = value.compareTo(compValue); if (result >= 0) { return true; } else { return false; } } /** * 值比较大小 *
如果valueStr大于等于compValueStr,则返回true,否则返回false * true 代表可用余额不足 * * @param valueStr (需要消费金额) * @param compValueStr (可使用金额) * @return boolean */
public static boolean moneyComp(BigDecimal valueStr, BigDecimal compValueStr) { //0:等于 >0:大于 <0:小于 int result = valueStr.compareTo(compValueStr); if (result >= 0) { return true; } else { return false; } } /** * 金额乘以,省去小数点 * * @param valueStr 基础值 * @return String */ public static String moneyMulOfNotPoint(String valueStr, String divideStr) { BigDecimal value = new BigDecimal(valueStr); BigDecimal mulValue = new BigDecimal(divideStr); valueStr = fnum.format(value.multiply(mulValue)); return fnum.format(value.multiply(mulValue)).substring(0, valueStr.length() - 3); } /** * 给金额加逗号切割 * * @param str * @return String */ public static String addComma(String str) { try { String banNum = ""; if (str.contains(".")) { String[] arr = str.split("\\."); if (arr.length == 2) { str = arr[0]; banNum = "." + arr[1]; } } // 将传进数字反转 String reverseStr = new StringBuilder(str).reverse().toString(); String strTemp = ""; for (int i = 0; i < reverseStr.length(); i++) { if (i * 3 + 3 > reverseStr.length()) { strTemp += reverseStr.substring(i * 3, reverseStr.length()); break; } strTemp += reverseStr.substring(i * 3, i * 3 + 3) + ","; } // 将[789,456,] 中最后一个[,]去除 if (strTemp.endsWith(",")) { strTemp = strTemp.substring(0, strTemp.length() - 1); } // 将数字重新反转 String resultStr = new StringBuilder(strTemp).reverse().toString(); resultStr += banNum; return resultStr; } catch (Exception e) { return str; } } }

原文 https://blog.csdn.net/qq_41934604/article/details/104845727

你可能感兴趣的:(Java,java,开发语言,后端)