本文纲要
1 ) BigDecimal高精度计算
- 为什么需要
BigDecimal BigDecimal的构造方法- 四则运算
- 除法与舍入模式
2 ) 基本数据类型包装类——Integer
- 包装类概述
Integer对象的创建- 自动装箱与自动拆箱
- 类型转换:
int与String互转 - 案例:字符串数字解析
BigDecimal 高精度计算
项目模块结构
mybigdecimal/
├── MyBigDecimalDemo.java // 初始精度丢失演示
├── MyBigDecimalDemo2.java // 构造方法演示
├── MyBigDecimalDemo3.java // 四则运算(精确计算)
└── MyBigDecimalDemo4.java // 除法舍入模式演示
1 ) 为什么需要BigDecimal
在 Java 中直接对小数进行运算可能会出现精度丢失的问题。例如输出 10.0 / 3.0 的结果,并不是我们期望的无限循环小数 3.333...,而是一个带有额外位数的结果。这是因为计算机底层会将十进制小数转换为二进制进行计算,再转回十进制,这种转换过程对于小数会引入微小的误差。虽然误差很小,但在金融、证券等对精度要求极高的场景中是不可接受的。BigDecimal 类正是为解决这类问题而存在。
package com.wb.demo;
public class MyBigDecimalDemo {
public static void main(String[] args) {
System.out.println(10.0 / 3.0); // 输出可能为 3.3333333333333335
}
}
2 ) BigDecimal的构造方法
创建 BigDecimal 对象时,建议使用参数为字符串的构造方法,以避免 double 数值本身带来的精度问题。直接传入 double 值(如 new BigDecimal(10.0))会保留底层的二进制误差,而传入字符串则能精确表示。
package com.wb.demo;
import java.math.BigDecimal;
public class MyBigDecimalDemo2 {
public static void main(String[] args) {
BigDecimal bd1 = new BigDecimal(10.0); // double构造
BigDecimal bd2 = new BigDecimal("0.3"); // String构造
System.out.println(bd1); // 输出 10
System.out.println(bd2); // 输出 0.3
}
}
从输出可以看到,对于整数部分 10.0,BigDecimal 会自动去除末尾的零,直接显示 10。
3 ) 四则运算
BigDecimal 的加减乘除运算必须通过调用方法来完成,不能直接使用运算符。
方法分别为:
add(BigDecimal augend)→ 加法subtract(BigDecimal subtrahend)→ 减法multiply(BigDecimal multiplicand)→ 乘法divide(BigDecimal divisor)→ 除法
重要提示:为了保证精确运算,必须使用字符串构造创建 BigDecimal 对象。若使用 double 构造,结果依然会包含误差。
package com.wb.demo;
import java.math.BigDecimal;
public class MyBigDecimalDemo3 {
//如果想要进行精确运算,那么请使用字符串的构造
public static void main(String[] args) {
// 错误示范:使用double构造依然不精确
// BigDecimal bd1 = new BigDecimal(0.1);
// BigDecimal bd2 = new BigDecimal(0.2);
// System.out.println(0.1 + 0.2); // 0.30000000000000004
BigDecimal bd1 = new BigDecimal("0.1");
BigDecimal bd2 = new BigDecimal("0.2");
// 加法
BigDecimal add = bd1.add(bd2);
System.out.println("和为" + add); // 0.3
// 减法
BigDecimal subtract = bd1.subtract(bd2);
System.out.println("差为" + subtract); // -0.1
// 乘法
BigDecimal multiply = bd1.multiply(bd2);
System.out.println("积为" + multiply); // 0.02
// 除法
BigDecimal divide = bd1.divide(bd2);
System.out.println("商为" + divide); // 0.5
}
}
4 ) 除法与舍入模式
当两个数除不尽时,直接调用 divide(BigDecimal divisor) 会抛出 ArithmeticException,因为 BigDecimal 不知道如何处理无限小数。
此时必须使用重载的 divide 方法,指定保留的小数位数和舍入模式。
方法签名:public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
divisor:另一个BigDecimal对象scale:小数点后精确到多少位roundingMode:舍入模式,常用的常量有:BigDecimal.ROUND_UP→ 进一法(向上取)BigDecimal.ROUND_FLOOR→ 去尾法(向下取)BigDecimal.ROUNDHALFUP→ 四舍五入
package com.wb.demo;
import java.math.BigDecimal;
public class MyBigDecimalDemo4 {
public static void main(String[] args) {
BigDecimal bd1 = new BigDecimal("0.3");
BigDecimal bd2 = new BigDecimal("4"); // 0.3 / 4 = 0.075
// 不带舍入模式的除法——当除不尽时会抛出异常,此处会报错
/* BigDecimal divide = bd1.divide(bd2);
System.out.println(divide); */
// 参数一:参与运算的另一个对象
// 参数二:表示小数点后精确到多少位
// 参数三:舍入模式
// 进一法 BigDecimal.ROUND_UP
// 去尾法 BigDecimal.ROUND_FLOOR
// 四舍五入 BigDecimal.ROUNDHALFUP
BigDecimal divide = bd1.divide(bd2, 2, BigDecimal.ROUNDHALFUP);
System.out.println(divide); // 输出 0.08
}
}
若换用 BigDecimal.ROUND_FLOOR,输出为 0.07。
若换用 BigDecimal.ROUND_UP,输出为 0.08。
基本数据类型包装类——Integer
项目模块结构
myinteger/
├── MyIntegerDemo1.java // Integer常量获取int范围
├── MyIntegerDemo2.java // 获取Integer对象(过时构造与valueOf)
├── MyIntegerDemo3.java // 自动装箱拆箱
├── MyIntegerDemo4.java // 类型转换
└── MyIntegerDemo5.java // 字符串数字解析案例
1 ) 包装类概述
Java 为 8 种基本数据类型提供了对应的包装类,目的是将基本类型包装成对象,从而可以在对象中定义各种操作数据的方法。
常见的包装类及对应关系如下:
byte→Byteshort→Shortint→Integerlong→Longfloat→Floatdouble→Doublechar→Characterboolean→Boolean
大多数包装类只需将基本类型首字母大写,但 int 和 char 较为特殊,分别是 Integer 和 Character。
例如,通过 Integer 类可以直接获取 int 类型的最大值和最小值:
package com.wb.myinteger;
public class MyIntegerDemo1 {
public static void main(String[] args) {
//需求:我要判断一个整数是否在 int 范围内?
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648
}
}
2 ) Integer对象的创建
创建 Integer 对象有几种方式,早期的构造方法已经过时,推荐使用静态方法 Integer.valueOf(int i) 或 Integer.valueOf(String s)。它们均返回 Integer 实例。
package com.wb.myinteger;
public class MyIntegerDemo2 {
public static void main(String[] args) {
// 构造方法(均已过时)
Integer i1 = new Integer(100);
Integer i2 = new Integer("100");
System.out.println(i1); // 100
System.out.println(i2); // 100
// 静态方法 valueOf(推荐)
Integer i3 = Integer.valueOf(200);
Integer i4 = Integer.valueOf("200");
System.out.println(i3); // 200
System.out.println(i4); // 200
}
}
3 ) 自动装箱与自动拆箱
从 JDK 1.5 开始,Java 提供了自动装箱和自动拆箱机制,让基本类型与包装类之间的转换更加简洁。
装箱:将基本数据类型转换为对应的包装类对象。底层自动调用 valueOf 方法。
拆箱:将包装类对象转换为对应的基本数据类型。
示例代码及解读:
package com.wb.myinteger;
public class MyIntegerDemo3 {
public static void main(String[] args) {
// 自动装箱:int → Integer
Integer i1 = 100; // 底层执行 Integer i1 = Integer.valueOf(100);
System.out.println(i1);
// 自动拆箱:Integer → int
int i2 = i1; // 底层执行 int i2 = i1.intValue();
System.out.println(i2);
// 综合案例
Integer i3 = 100; // 自动装箱
i3 += 200; // 等价于 i3 = i3 + 200;
// 过程:
// 1) i3 自动拆箱为 int 值 100
// 2) 100 + 200 = 300
// 3) 将 int 300 自动装箱为 Integer 对象赋值给 i3
System.out.println(i3); // 300
// 细节:若包装类对象为 null,拆箱时会抛出 NullPointerException
Integer i4 = null;
if (i4 != null) {
i4 += 200;
System.out.println(i4);
}
// 如果 i4 为 null,执行 i4 += 200 会引发 NullPointerException,
// 因此建议在使用前做非空判断。
}
}
4 ) 类型转换:int与String互转
在实际开发中,经常需要将字符串数字转换为 int 参与计算,或将 int 转换为字符串进行拼接或展示。
String → int:使用 Integer.parseInt(String s) 静态方法。
String s1 = "100";
int i1 = 200;
int i2 = Integer.parseInt(s1); // 将字符串 "100" 转为 int 100
System.out.println(i2 + i1); // 300,而不是 "100200"
int → String:两种常用方式。
int i3 = 100;
// 方式一:拼接空字符串
String s2 = i3 + "";
System.out.println(s2 + 100); // 100100(字符串操作)
// 方式二:使用 String.valueOf(int)
String s3 = String.valueOf(i3);
System.out.println(s3 + 100); // 100100
完整演示:
package com.wb.myinteger;
public class MyIntegerDemo4 {
public static void main(String[] args) {
// String 转 int
String s1 = "100";
int i1 = 200;
System.out.println(s1 + i1); // 100200 —— 字符串拼接
int i2 = Integer.parseInt(s1);
System.out.println(i2 + i1); // 300 —— 整数加法
// int 转 String
int i3 = 100;
String s2 = i3 + ""; // 方式一
System.out.println(s2 + 100); // 100100
String s3 = String.valueOf(i3); // 方式二
System.out.println(s3 + 100); // 100100
}
}
5 ) 案例:字符串数字解析
需求:将字符串 "91 27 46 38 50" 中的每个数字提取出来,存入 int 数组并遍历输出。
解题步骤:
- 将字符串按空格分割为字符串数组;
- 创建等长的
int数组; - 遍历字符串数组,使用
Integer.parseInt()转换并存储; - 遍历
int数组输出结果。
package com.wb.myinteger;
public class MyIntegerDemo5 {
//需求:有一个字符串:“91 27 46 38 50”,把其中的每一个数存到int类型的数组中
public static void main(String[] args) {
String s = "91 27 46 38 50";
// 1. 获取字符串中的每一个数字,按空格切割
String[] strArr = s.split(" ");
// 2. 创建一个等长的int类型数组
int[] numberArr = new int[strArr.length];
// 3. 把strArr中的数据进行类型转换并存入int数组
for (int i = 0; i < strArr.length; i++) {
int number = Integer.parseInt(strArr[i]);
numberArr[i] = number;
}
// 4. 遍历int类型的数组并输出
for (int i = 0; i < numberArr.length; i++) {
System.out.println(numberArr[i]);
}
}
}
运行结果将依次打印:91、27、46、38、50。
总结
以上内容涵盖了 BigDecimal 高精度计算以及 Integer 包装类的核心用法,配合示例代码可以帮助快速上手
后续可在此基础上进一步学习其他包装类及 BigDecimal 更高级的舍入策略等
197

被折叠的 条评论
为什么被折叠?



