- 1 1. Java 的 double 类型是什么?
- 2 1.1 double 是 “双精度浮点数”
- 3 1.2 double 能表示的实际范围示例
- 4 1.3 在 Java 中,十进制字面量默认是 double
- 5 1.4 常见的 double 使用场景
- 6 1.5 首先需要记住的要点
- 7 2. double 的范围与精度(显著数字指南)
- 8 2.1 double 能表示的数值范围
- 9 2.2 有效数字大约在 15 到 17 位之间
- 10 2.3 “高精度”并不等同于“精确的小数”
- 11 2.4 为什么有效数字很重要
- 12 2.5 基于范围和精度的正确认识
- 13 3. double 与 float 的区别(该选哪个?)
- 14 3.1 float 与 double 的基本区别
- 15 3.2 为什么 double 是 Java 的标准
- 16 3.3 何时应该使用 float
- 17 3.4 初学者的简易规则
- 18 3.5 为什么理解这种差异很重要
- 19 4. double 的基本用法(声明、计算、输出)
- 20 4.1 声明和赋值 double
- 21 4.2 四种基本算术运算
- 22 4.3 除法的关键注意点
- 23 4.4 打印计算结果
- 24 4.5 按固定小数位数打印
- 25 4.6 double 计算基础小结
- 26 5. 常见陷阱 #1:为何会出现精度错误
- 27 5.1 精度错误的经典示例
- 28 5.2 为什么会出现这种错误
- 29 5.3 始终假设可能出现误差
- 30 5.4 当误差通常无关紧要时
- 31 5.5 你应该如何处理精度误差
- 32 6. 常见陷阱 #2:使用 “==” 比较 double 值是危险的
- 33 6.1 使用 “==” 会发生什么
- 34 6.2 比较 double 值的黄金法则
- 35 6.3 使用 epsilon(容差)进行比较
- 36 6.4 如何选择 epsilon?
- 37 6.5 与 BigDecimal 的区别
- 38 6.6 比较规则小结
- 39 7. 常见陷阱 #3:整数除法产生零
- 40 7.1 为什么会出现整数除法
- 41 7.2 正确进行小数除法的方法
- 42 7.3 常见的真实场景错误
- 43 7.4 初学者应记住的规则
- 44 7.5 整数除法陷阱小结
- 45 8. 字符串与 double 之间的转换(实践中最常见)
- 46 8.1 将字符串转换为 double
- 47 8.2 Double.valueOf() 的区别
- 48 8.3 将 double 转换为字符串
- 49 8.4 显示时始终格式化字符串
- 50 8.5 字符串转换要点
- 51 9. Double 类中的特殊值(NaN / Infinity)
- 52 9.1 什么是 NaN(非数字)
- 53 9.2 什么是 Infinity?
- 54 9.3 如何检查 NaN 和 Infinity
- 55 9.4 为什么要及早检测
- 56 10. 使用 BigDecimal 进行金钱和精确计算
- 57 10.1 什么是 BigDecimal?
- 58 10.2 使用 BigDecimal 时的重要规则
- 59 10.3 在 double 与 BigDecimal 之间的选择
- 60 11. 小结:正确使用 Java double
- 61 12. 常见问题解答 (FAQ)
1. Java 的 double 类型是什么?
Java 的 double 类型是 用于处理十进制值的基本数据类型。与表示整数的 int 或 long 不同,double 用来表示 带小数点的数字,例如 “1.5”、 “3.14” 或 “0.01”。在 Java 中进行数值计算时,它是最常用的类型之一。
由于初学者常常在这一步卡住,首先了解 double 具有什么特性 非常重要。
1.1 double 是 “双精度浮点数”
double 是一种 双精度浮点数,使用 64 位(8 字节) 来表示数值。
正如 “浮点数” 这个词所暗示的,double 在内部将数值处理为 近似值。
因此,它具有以下特性:
- 能处理极其宽广的数值范围
- 能进行包含小数部分的计算
- 但无法精确表示每一个十进制值
“无法精确表示每一个十进制值” 的细节将在后面详细说明,但只要记住 double 不是万能的,后续内容就会容易得多。
1.2 double 能表示的实际范围示例
double 能表示的数值范围非常大。大致来说,它可以处理:
- 极小的数(例如 0.0000000001)
- 极大的数(约 10^300 级别)
- 日常使用的普通十进制数
例如,下面所有的值都可以存入 double:
double a = 3.14;
double b = 0.1;
double c = 123456789.987;
对于日常数值处理、物理量、统计数据以及坐标计算等 “近似正确就足够” 的场景,double 通常是标准选择。
1.3 在 Java 中,十进制字面量默认是 double
在 Java 中,当你写带小数点的数值字面量时,除非另有说明,它会被视为 double 类型,默认行为如下:
double x = 1.23; // OK
float y = 1.23; // コンパイルエラー
上例中,float y = 1.23; 会报错,因为 1.23 被解释为 double。
如果想让它被当作 float,必须显式地这样写:
float y = 1.23f;
这说明在 Java 中,double 是十进制计算的默认类型。
1.4 常见的 double 使用场景
double 常用于以下情况:
- 需要得到小数形式的除法结果
- 计算平均值、比例等
- 图形渲染与坐标运算
- 科学计算与统计处理
另一方面,double 并不适合 金钱计算或严格的十进制处理。这将在后面详细解释,作为在 double 与 BigDecimal 之间做选择的依据。
1.5 首先需要记住的要点
用初学者友好的方式总结到目前为止的学习内容:
double是十进制数的基本类型- 在内部,计算使用 近似值
- 在 Java 中,十进制字面量默认是
double - 当精度重要时必须格外小心
2. double 的范围与精度(显著数字指南)
学习 double 类型时,无法回避的一个话题是 “它能多精确地表示数字?”
本节将以初学者友好的方式,介绍 double 的数值范围、精度以及显著数字的概念。
2.1 double 能表示的数值范围
由于 double 使用 64 位来表示数值,它能够处理极其宽广的数值范围。
概念上,这个范围可以描述为:
- 极小的数:例如大约
4.9 × 10^-324 - 极大的数:例如大约
1.8 × 10^308
在日常编程中,你很少需要去考虑这些限制。
对于大多数实际用途,你可以把它视为处理几乎“无限接近”范围的情况。
2.2 有效数字大约在 15 到 17 位之间
理解 double 精度的关键概念是有效数字。
double 通常被认为能够准确存储约 15 到 17 位数字。
例如,考虑下面的数值:
double a = 123456789012345.0;
double b = 1234567890123456.0;
a(15 位)可以准确表示b(16 位以上)可能会把低位四舍五入
换句话说,随着数字位数的增加,细粒度的精度会逐渐丢失。
2.3 “高精度”并不等同于“精确的小数”
这里有一个常见的初学者误解。
double 具有高精度
→ 所以它可以精确处理小数
这并不总是正确。
double 确实是高精度类型,但这意味着:
“它可以在一定位数范围内作为近似值保持准确”,而不是“每个十进制值都是精确的”。
例如,考虑下面的计算:
double x = 0.1 + 0.2;
System.out.println(x);
很多人会期待得到 0.3,但实际上你可能会看到类似的结果:
0.30000000000000004
这不是 bug,而是 double 的工作方式。
原因在于 0.1 和 0.2 无法在二进制中精确表示。
2.4 为什么有效数字很重要
如果你不了解有效数字,可能会遇到以下问题:
- 结果略有偏差
- 使用
==比较时不匹配 - 在求和或求平均时误差累计
所有这些都源于 double 是一种处理近似值的类型。
另一方面,在“完美相等”不如“实际精度”重要的场景中,例如:
- 图形渲染
- 物理仿真
- 统计处理
double 是一个极佳的选择。
2.5 基于范围和精度的正确认识
总结如下:
double能表示极其宽广的数值范围- 它拥有约 15–17 位的有效数字
- 小数被视为 近似值 处理
- 在需要严格精度时要格外小心
3. double 与 float 的区别(该选哪个?)
在 Java 中处理小数时,double 与 float 几乎总是被比较。
两者都可以表示分数值,但在精度、使用场景和实用性上存在显著差异。
本节重点提供明确的决策标准,帮助初学者避免卡壳。
3.1 float 与 double 的基本区别
让我们把比较保持简洁:
| Type | Bits | Typical Precision | Main Use |
|---|---|---|---|
| float | 32-bit | About 6–7 digits | Lightweight / lower precision |
| double | 64-bit | About 15–17 digits | Standard / higher precision |
正如你所见,double 提供了显著更高的精度。
3.2 为什么 double 是 Java 的标准
在 Java 中,十进制字面量(如 1.23)默认被视为 double。
这主要是因为:
- 在现代 CPU 上,
double的性能开销通常可以忽略不计 - 由于精度不足导致的 bug 往往更为严重
double在典型代码中更易读且更安全
因此,在 Java 中的常用做法是:除非有充分理由,否则使用 double。
3.3 何时应该使用 float
那么 float 是不是毫无用处?
不——在特定情境下它可以发挥作用。
选择 float 的典型情况包括:
- 需要极度降低内存占用时
- 处理大规模数值数组(例如图像处理)时
- 在游戏或 3D 计算中,速度比精度更重要时
然而,对于业务应用或 Web 应用来说,
几乎没有充分的理由去使用 float。
3.4 初学者的简易规则
如果你不确定该选哪个,记住这条规则:
- 有疑问时,使用
double - 仅在内存/性能限制严格时才使用
float
尤其在学习阶段,通常更高效的做法是避免 float 特有的精度问题,而使用 double 来构建理解。
3.5 为什么理解这种差异很重要
了解这种差异有助于以下情形:
- 阅读他人代码时理解其意图
- 防止不必要的精度损失
- 在数值计算错误发生前予以避免
4. double 的基本用法(声明、计算、输出)
现在让我们通过实际代码确认 double 的基本用法。
如果你理解了“声明 → 计算 → 输出”的流程,那么基础已经掌握。
4.1 声明和赋值 double
声明 double 的方式与其他基本类型相同:
double x = 1.5;
double y = 2.0;
在赋值小数时,无需任何特殊后缀。
也可以赋予整数值,系统会自动转换为 double。
double a = 10; // Treated as 10.0
4.2 四种基本算术运算
使用 double 时,可以直接进行加、减、乘、除运算:
double a = 5.0;
double b = 2.0;
double sum = a + b; // addition
double diff = a - b; // subtraction
double product = a * b; // multiplication
double quotient = a / b; // division
所有结果同样是 double,因此可以自然地处理小数结果。
4.3 除法的关键注意点
关键在于,除法只有在至少一侧是 double 时才会进行小数计算。
double result1 = 1 / 2; // result is 0.0
double result2 = 1 / 2.0; // result is 0.5
1 / 2 两侧都是整数,因此会先进行整数除法。
为避免这种情况,可采取以下任一做法:
- 将其中一个操作数设为
double - 使用显式强制类型转换
double result = (double) 1 / 2;
4.4 打印计算结果
可以直接使用 System.out.println() 打印 double 值:
double value = 3.14159;
System.out.println(value);
但直接打印可能会显示比预期更多的位数。
4.5 按固定小数位数打印
如果想要更整洁的输出,printf 很方便:
double value = 3.14159;
System.out.printf("%.2f%n", value);
这会将数值打印为小数点后保留两位。
%.2f:小数点后保留 2 位%n:换行
对于面向用户的显示,建议始终控制显示的位数。
4.6 double 计算基础小结
本节的关键要点:
double天然支持小数计算- 注意整数之间的除法
- 打印结果时控制显示的位数
5. 常见陷阱 #1:为何会出现精度错误
使用 double 时最先遇到的困惑之一是:
“结果与我的预期不符。”
这不是 Java 的 bug,而是 double 类型的核心属性。
5.1 精度错误的经典示例
来看一个广为人知的例子:
double x = 0.1 + 0.2;
System.out.println(x);
很多人会期待得到 0.3,但实际可能看到:
0.30000000000000004
看到后,你可能会想“哪里出错了”或“这是不是 bug?”
但这实际上是 double 的正确结果。
5.2 为什么会出现这种错误
原因在于 double 使用 二进制 来表示数字。
人类使用十进制,而计算机内部使用二进制。
关键问题在于:
- 许多十进制小数无法用有限的二进制位表示
- 因此系统只能存储最接近的近似值
0.1 和 0.2 在二进制中是无限循环的,所以它们被存储为“非常接近”但并不等于精确十进制值的近似数。
将这些近似值相加会得到类似 0.30000000000000004 的结果。
5.3 始终假设可能出现误差
最重要的心态是:
使用 double 时,精度误差是不可避免的
误差在以下情况中特别明显:
- 多次重复加法/减法
- 牵涉除法的计算
- 当你需要严格到很多小数位的正确性时
简而言之,double 并不是为“完美精确的十进制数”而设计的。
5.4 当误差通常无关紧要时
另一方面,很多情况下精度误差很少成为实际问题。
例如:
- 绘图和动画
- 传感器数值和统计数据
- 科学计算
- 游戏和仿真
在这些领域,重要的不是绝对相等,而是能够以现实的精度进行计算。
这正是 double 发光发热的地方。
5.5 你应该如何处理精度误差
试图彻底消除误差往往会破坏你的设计。
相反,请遵循以下原则:
- 接受“误差可能会发生”
- 使用合适的比较/判断方法
- 当误差不可接受时,采用不同的方案
6. 常见陷阱 #2:使用 “==” 比较 double 值是危险的
在了解了精度误差之后,几乎每个人都会遇到的下一个问题是:
“为什么比较结果不像预期那样?”
一个非常常见的初学者错误是使用 == 来比较 double 值。
6.1 使用 “==” 会发生什么
考虑下面的代码:
double a = 0.1 + 0.2;
double b = 0.3;
System.out.println(a == b);
直观上,你可能会期待得到 true,但结果可能是 false。
这正是前面解释的精度误差导致的。
a接近0.30000000000000004b是另一种近似,表示0.3
由于这些值在位层面上并不完全相同,== 将它们报告为不同的值。
6.2 比较 double 值的黄金法则
有一条根本规则你必须时刻记住:
绝不要对 double 值进行精确相等比较
== 运算符检查的是内部表示是否完全相同,而不是值是否“足够接近”。
这使得它不适用于浮点数。

6.3 使用 epsilon(容差)进行比较
在比较 double 值时,你应该为“多接近算作相等”定义一个阈值。
这个阈值称为 epsilon(容差)。
double a = 0.1 + 0.2;
double b = 0.3;
double epsilon = 1e-9;
if (Math.abs(a - b) < epsilon) {
System.out.println("Approximately equal");
}
这种做法检查的是:
- 绝对差值是否足够小
- 这些值在实际用途上是否可以视为相等
6.4 如何选择 epsilon?
一个常见的初学者问题是:
“epsilon 应该设多大?”
思路很简单。基于以下因素来决定:
- 你处理的数值的量级
- 你能够容忍的误差大小
常用的经验法则包括:
1e-9:适用于多数通用计算1e-12:非常严格1e-6:适合显示或粗略估计
没有唯一正确的数值。
根据你的使用场景来选择。
6.5 与 BigDecimal 的区别
稍作前瞻,注意两者在理念上的差异:
double:在容忍小误差的前提下工作BigDecimal:设计上不允许误差
如果比较过程让你觉得“太复杂”,这可能意味着 double 并不是该任务的合适选择。
6.6 比较规则小结
- 不要使用
== - 使用绝对差值进行比较
- 根据上下文选择 epsilon
- 若需要严格精度,请使用其他类型
7. 常见陷阱 #3:整数除法产生零
即使使用 double,你仍可能看到结果意外地变成 0。
这是一种最常见的初学者错误之一。
原因很简单:计算是使用整数进行的。
7.1 为什么会出现整数除法
(后续内容请自行补充)
在 Java 中,操作数的类型决定了计算的执行方式。
考虑以下代码:
double result = 1 / 2;
System.out.println(result);
输出为:
0.0
因为 1 和 2 都是 int,Java 首先执行整数除法,得到 0,随后再转换为 double。
7.2 正确进行小数除法的方法
避免整数除法很简单。
让至少一个操作数为 double。
double result1 = 1 / 2.0;
double result2 = 1.0 / 2;
double result3 = (double) 1 / 2;
所有这些都会产生:
0.5
7.3 常见的真实场景错误
这种代码在实际应用中经常出现:
int total = 5;
int count = 2;
double average = total / count;
虽然看起来正确,但结果是 2.0。
计算平均值的正确方式是:
double average = (double) total / count;
7.4 初学者应记住的规则
- 在除法运算中始终注意类型
- 整数 ÷ 整数会产生整数
- 将结果接收为
double并不足够
7.5 整数除法陷阱小结
- 成因在于操作数类型和求值顺序
- 从计算开始就使用
double - 对平均值和比例要格外小心
8. 字符串与 double 之间的转换(实践中最常见)
在实际应用中,你很少会硬编码 double 值。
更常见的是,需要将字符串(String)转换为数字。
典型的例子包括:
- 表单输入值
- CSV 或 JSON 文件
- 配置文件
- API 响应
本节将说明在 String 与 double 之间安全转换的方法。
8.1 将字符串转换为 double
8.1.1 Double.parseDouble()
最常用且最基础的方法:
String text = "3.14";
double value = Double.parseDouble(text);
如果字符串是有效的数字,转换会成功。
8.1.2 处理无效字符串
如果字符串不是数字,会抛出异常:
String text = "abc";
double value = Double.parseDouble(text); // throws exception
这会抛出 NumberFormatException。
在实际使用中,始终使用 try-catch:
try {
double value = Double.parseDouble(text);
} catch (NumberFormatException e) {
// error handling
}
8.2 Double.valueOf() 的区别
Double.valueOf() 是另一种将字符串转换为数值的方法。
Double value = Double.valueOf("3.14");
两者的区别在于:
parseDouble→ 返回基本类型doublevalueOf→ 返回Double包装对象
对于普通的数值计算,parseDouble 已足够。
在处理诸如 List<Double> 的集合时,通常使用 valueOf。
8.3 将 double 转换为字符串
将 double 转换为字符串也非常常见。
double value = 3.14;
String text = String.valueOf(value);
另一种广泛使用的方式是:
String text = Double.toString(value);
这两种方式都很安全。可根据编码风格或项目约定进行选择。
8.4 显示时始终格式化字符串
在向用户展示数字时,
始终使用格式化输出。
double value = 3.14159;
String text = String.format("%.2f", value);
这会将数值格式化为保留两位小数。
8.5 字符串转换要点
- 始终预料到无效输入并进行异常处理
- 将内部计算与显示格式分离
- 显示数值时始终控制小数位数
下一节将解释特殊的 double 值:NaN 和 Infinity。
如果不了解它们,调试数值问题将非常困难。
9. Double 类中的特殊值(NaN / Infinity)
double 类型包含特殊值,它们不是普通数字。
了解它们对于编写健壮的程序至关重要。
9.1 什么是 NaN(非数字)
NaN 表示未定义的数值结果。
它出现在诸如以下的计算中:
double value = 0.0 / 0.0;
System.out.println(value);
输出为:
NaN
9.2 什么是 Infinity?
当除法结果溢出时,Java 会产生 Infinity。
double value = 1.0 / 0.0;
System.out.println(value);
输出为:
Infinity
如果分子为负数,结果为 -Infinity。
9.3 如何检查 NaN 和 Infinity
这些值不能可靠地使用 == 进行检查。
请始终使用专用的方法:
double value = 0.0 / 0.0;
if (Double.isNaN(value)) {
System.out.println("Value is NaN");
}
if (Double.isInfinite(value)) {
System.out.println("Value is infinite");
}
9.4 为什么要及早检测
如果 NaN 或 Infinity 在计算中传播,可能导致:
- 所有后续结果都变为 NaN
- UI 中显示无效数值
- 应用逻辑出现错误
尽可能早地检测异常值。
10. 使用 BigDecimal 进行金钱和精确计算
正如前面所示,double 非常方便,
但 它无法完全避免精度误差。
因此,它不适用于:
- 金钱计算
- 积分或余额管理
- 严格的四舍五入要求
10.1 什么是 BigDecimal?
BigDecimal 是一个在 十进制基数下精确处理小数 的类。
它的设计目的是避免精度损失。
BigDecimal a = new BigDecimal("0.1");
BigDecimal b = new BigDecimal("0.2");
BigDecimal result = a.add(b);
System.out.println(result); // 0.3
10.2 使用 BigDecimal 时的重要规则
直接从 double 创建 BigDecimal 会把精度误差带进去。
new BigDecimal(0.1); // Not recommended
始终 从字符串创建,例如:
new BigDecimal("0.1"); // Correct
10.3 在 double 与 BigDecimal 之间的选择
- 性能和简洁 →
double - 精度至上 →
BigDecimal
不要强行把所有东西都塞进同一种类型。
根据用途进行选择。
11. 小结:正确使用 Java double
让我们总结本文的要点:
double是 Java 的基础十进制类型- 精度误差是规范的一部分
- 比较时使用容差
- 注意整数除法
- 需要精确计算时使用
BigDecimal
一旦了解了 double 的工作原理,数值编程就不再那么令人生畏。
12. 常见问题解答 (FAQ)
Q1. Java double 的有效位数是多少?
大约 15–17 位有效数字。小数值以近似方式处理。
Q2. 应该使用 double 还是 float?
在大多数情况下使用 double,除非有充分理由选择 float。
Q3. 用 double 处理金钱是否不妥?
是的。不推荐这样做。请使用 BigDecimal 进行安全的金钱计算。
Q4. 可以用 “==” 来比较 double 值吗?
不能。请使用容差(epsilon)进行比较。
Q5. 应该如何处理 NaN 和 Infinity?
使用 Double.isNaN() 和 Double.isInfinite() 及早检测,并显式处理它们。

