实战java中资金计算的要点-BigDecimal

本文详细介绍了在Java中处理财务计算的最佳实践,强调避免使用float和double类型,并推荐使用java.math.BigDecimal来确保高精度的计算结果。同时提供了数据库设计、Hibernate属性定义及常见运算方法的实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先明确的是:Java中的浮点数类型的floatdouble是不能够用来进行资金的运算。

 

在《Effective Java》中也提到这个原则:floatdouble只能用来做科学计算或者是工程计算,在商业计算中我们要用java.math.BigDecimal

 

怎样在实际中应用呢,其实也不难。简单提几点:

1.  数据库表的设计

资金字段的数据类型一般定义为number类型,长度可根据需要而定。

2. hibernatepo的属性的数据类型的定义

       有两种选择,建议用double,float会有精度丢失的问题。hibernate映射工具自动生成的.hbm.xml中,默认也是double类型。

3.程序中资金的运算

       必须使用java.math.BigDecimal,而不能使用float或者double。建议写个工具类,提供些常用的方法供加减等运算使用。

 

有篇不错的文章,大家可以参考:http://www.j-kanban.com/bbs/redirect.php?fid=59&tid=6876&goto=nextoldset

 

实例参考:

 

public class BaseCalculate {
	
	private static final int DEF_DIV_SCALE = 10;

	/**
	 * 提供精确的加法运算 
	 * @param v1 被加数
	 * @param v2 加数
	 * @return 两个参数的和
	 */
	public static double add(double v1, double v2) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.add(b2).doubleValue();
	}
	
	/**
	 * 提供精确的减法运算 
	 * @param v1 被减数
	 * @param v2 减数
	 * @return 两个参数的差
	 */
	public static double substract(double v1, double v2) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.subtract(b2).doubleValue();
	}
	
	/**
	 * 提供精确的乘法运算
	 * @param v1 被乘数
	 * @param v2 乘数
	 * @return 两个参数的积
	 */
	public static double multiply(double v1, double v2) {
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.multiply(b2).doubleValue();
	}

	/**
	 * 提供(相对)精确的除法运算,当发生除不尽的情况时,
	 * 精确到小数点以后10位,以后的数字四舍五入.
	 * @param v1 被除数
	 * @param v2 除数
	 * @return 两个参数的商
	 */
	public static double divide(double v1, double v2) {
		return divide(v1, v2, DEF_DIV_SCALE);
	}

	/**
	 * 提供(相对)精确的除法运算.
	 * 当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入.
	 * 
	 * @param v1 被除数
	 * @param v2 除数
	 * @param scale 表示需要精确到小数点以后几位
	 * @return 两个参数的商
	 */
	public static double divide(double v1, double v2, int scale) {
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		
		BigDecimal b1 = new BigDecimal(Double.toString(v1));
		BigDecimal b2 = new BigDecimal(Double.toString(v2));
		return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	/**
	 * 提供精确的小数位四舍五入处理
	 * @param v 需要四舍五入的数字
	 * @param scale 小数点后保留几位
	 * @return 四舍五入后的结果
	 */
	public static double round(double v, int scale) {
		if (scale < 0) {
			throw new IllegalArgumentException("The scale must be a positive integer or zero");
		}
		
		BigDecimal b = new BigDecimal(Double.toString(v));
		BigDecimal one = new BigDecimal("1");
		return b.divide(one, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
	}

	
	 public static void main(String[] args) {
		 //直接使用浮点数进行计算,得到的结果是有问题的
		 System.out.println(0.01 + 0.05);
		 
		 //使用了BigDecimal类进行计算后,可以做到精确计算
		 System.out.println(BaseCalculate.add(0.0000000000005, 0.00000001));
	}
}

 

 

<think>嗯,用户需要一些关于Java异常处理的面试题目,特别是偏重实际操作和应用场景的部分。之前用户提到过SpringBoot的面试题,现在转向Java异常处理,看来是在准备技术面试的不同模块。用户可能正在系统性地整理Java面试题库,而且更关注能动手验证的知识点。结合引用的资料,我发现引用[3]提到"try-catch处理要遵循的原则"和"finally为什么总是能执行"这类原理+实践的问题特别符合需求。从引用[4][5]看,受检异常和非受检异常的区别是必考点,但用户需要的是具体场景下的代码实现问题。比如引用[2]虽然给了异常处理答案,但缺乏实际操作演示,这正是需要加强的部分。准备设计5类问题:自定义异常类编写(展示继承关系)、异常传递机制(方法调用链的实战)、资源关闭的正确写法(对比错误示例)、异常重试机制(使用Spring的@Retryable)、空指针处理技巧(Optional的实践)。每个问题都要包含可运行的代码块和故障模拟。特别要注意引用[5]强调的异常发生处理原则,所以会在调试案例中加入try-finally资源泄露的反例。性能部分则要突出引用[3]提到的"try-catch为什么消耗性能",用JDK新特性作为优化方案。最后生成的相关问题需要覆盖分布式场景(RPC调用异常)和监控维度(日志采集),这样既结合生产环境又衔接了用户上次问的SpringBoot监控端点知识。</think> 以下是针对Java异常处理的实战型面试题目,聚焦代码实现、场景分析和生产调优,附带解答要点和代码示例: --- ### **一、自定义异常开发** 1. **场景实现** *需求:实现转账业务的自定义异常`InsufficientBalanceException`,包含错误金额字段* ```java public class InsufficientBalanceException extends RuntimeException { private final BigDecimal requiredAmount; public InsufficientBalanceException(BigDecimal requiredAmount) { super("余额不足,还需: " + requiredAmount); this.requiredAmount = requiredAmount; } public BigDecimal getRequiredAmount() { return requiredAmount; } } ``` **考点**:自定义异常的继承选择(RuntimeException避免强制捕获)、业务信息封装[^5]。 --- ### **二、异常传递机制** 2. **异常处理链实战** *问题:如下方法调用链中,如果methodC()抛出SQLException,methodA()该如何处理?* ```java // 伪代码 void methodA() { try { methodB(); } catch (BusinessException e) { // 应在此捕获哪些异常? } } void methodB() throws IOException { methodC(); // 可能抛出SQLException } void methodC() throws SQLException { ... } ``` **解答要点**: - 需在methodB声明中添加`throws SQLException` - methodA捕获`BusinessException`后应添加: ```java if (e.getCause() instanceof SQLException) { // 处理数据库异常根源 } ``` **考点**:异常包装(`throw new BusinessException(e)`)和根本原因追溯[^3] --- ### **三、资源关闭实践** 3. **Try-with-Resources调试** *观察以下代码,指出资源关闭缺陷:* ```java void readFile() { BufferedReader br = new BufferedReader(new FileReader("test.txt")); try { System.out.println(br.readLine()); } finally { if (br != null) br.close(); // 存在隐患 } } ``` **优化方案**: ```java try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) { System.out.println(br.readLine()); } ``` **考点**: - JDK7+的try-with-resources自动关闭原理 - 原始finally块可能遗漏`FileReader`的关闭[^5] --- ### **四、异常性能优化** 4. **异常栈构造开销分析** *场景:高频调用方法中可能抛出异常,如何优化性能?* **解决方案**: ```java // 预创建无栈异常 private static final NoDataException CACHED_EXCEPTION = new NoDataException(); static { CACHED_EXCEPTION.setStackTrace(new StackTraceElement[0]); // 清除栈追踪 } public void highFrequencyMethod() { if (data == null) throw CACHED_EXCEPTION; } ``` **原理**:异常实例复用避免重复构建栈轨迹(需确保线程安全)[^3] --- ### **五、空指针防护实践** 5. **Optional实战应用** *重构以下代码,避免多层null检查:* ```java public String getCity(User user) { if (user != null) { Address address = user.getAddress(); if (address != null) { return address.getCity(); } } return "Unknown"; } ``` **优化方案**: ```java public String getCity(User user) { return Optional.ofNullable(user) .map(User::getAddress) .map(Address::getCity) .orElse("Unknown"); } ``` **考点**:Optional的链式调用与`orElse()`的默认值处理[^4] --- ### **相关面试问题扩展** 1. **Spring事务异常回滚机制** *`@Transactional`何时根据异常回滚?如何让自定义异常触发回滚?* **要点**:默认对RuntimeException回滚,需用`@Transactional(rollbackFor = CustomException.class)`定制[^3] 2. **分布式系统异常处理** *RPC调用中,服务端抛出异常客户端如何获取完整错误信息?* **方案**:异常序列化(如实现`Serializable`)、定义统一错误码体系 3. **日志与异常联动** *catch块中仅记录日志不处理异常,会产生什么风险?* **反模式**:日志淹没真正问题、异常被吞没导致流程继续异常执行[^2] --- > **注**:以上代码示例均需关注实际执行效果,面试时可要求解释底层原理或现场调试修正错误。 > [^1]: 异常面试题基础概念验证 > [^2]: 日志与异常联动风险 > [^3]: 异常性能调优与封装原则 > [^4]: 空指针防护最佳实践 > [^5]: 自定义异常业务场景设计
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值