double 是 IEEE 754 标准的 64 位浮点数,用于表示带有小数的数字,而 long 是 Java 的 64 位整数,用于表示没有小数的、完整的数字。
double 能表示的数值范围远大于 long,double 在表示大整数时可能会失去精度,直接转换必须遵循明确的规则。
核心方法与语法
Java 提供了两种主要的方法来进行转换,它们的舍入方式完全不同。
强制类型转换 (Casting) - 截断
这是最直接的方法,但它的行为常常是初学者容易混淆的地方。
语法:
long myLong = (long) myDouble;
行为: 这种方式会直接丢弃小数部分,而不是进行四舍五入,它本质上是向零截断。
示例:
public class DoubleToLongExample {
public static void main(String[] args) {
double positiveDouble = 123.45;
double negativeDouble = -123.45;
// 强制转换,直接丢弃小数部分
long positiveLong = (long) positiveDouble;
long negativeLong = (long) negativeDouble;
System.out.println("原始 double 值: " + positiveDouble);
System.out.println("强制转换后 long 值: " + positiveLong); // 输出 123
System.out.println("原始 double 值: " + negativeDouble);
System.out.println("强制转换后 long 值: " + negativeLong); // 输出 -123
}
}
输出:
原始 double 值: 123.45
强制转换后 long 值: 123
原始 double 值: -123.45
强制转换后 long 值: -123
重要提示:精度丢失
double 的值超出了 long 的表示范围(Long.MIN_VALUE 到 Long.MAX_VALUE),强制转换会得到一个不确定的值。Double.POSITIVE_INFINITY 转换为 long 会得到 Long.MIN_VALUE。
double tooBig = 1e300; // 比 Long.MAX_VALUE 大得多 System.out.println((long) tooBig); // 输出: -9223372036854775808 (即 Long.MIN_VALUE)
Math.round() 方法 - 四舍五入
如果你希望在进行转换前进行四舍五入,应该使用 Math.round() 方法。
语法:
long myLong = Math.round(myDouble);
行为:
Math.round() 会将 double 四舍五入到最接近的 long 值,它的工作原理是:
- 如果小数部分 >= 0.5,则向正无穷方向舍入。
- 如果小数部分 < 0.5,则向负无穷方向舍入(即向下取整)。
注意:
Math.round() 方法的返回值是 long 类型,但还有一个重载版本 Math.round(float),它返回 int 类型,确保你调用的是针对 double 的版本。
示例:
public class DoubleToLongRoundExample {
public static void main(String[] args) {
double d1 = 123.49;
double d2 = 123.50;
double d3 = -123.49;
double d4 = -123.50;
// 使用 Math.round() 进行四舍五入
long l1 = Math.round(d1);
long l2 = Math.round(d2);
long l3 = Math.round(d3);
long l4 = Math.round(d4);
System.out.println("原始 double: " + d1 + " -> 四舍五入后 long: " + l1); // 输出 123
System.out.println("原始 double: " + d2 + " -> 四舍五入后 long: " + l2); // 输出 124
System.out.println("原始 double: " + d3 + " -> 四舍五入后 long: " + l3); // 输出 -123
System.out.println("原始 double: " + d4 + " -> 四舍五入后 long: " + l4); // 输出 -124
}
}
输出:
原始 double: 123.49 -> 四舍五入后 long: 123
原始 double: 123.5 -> 四舍五入后 long: 124
原始 double: -123.49 -> 四舍五入后 long: -123
原始 double: -123.5 -> 四舍五入后 long: -124
如何选择?(何时使用哪种方法)
| 场景 | 推荐方法 | 原因 |
|---|---|---|
| 金融、财务计算 | 不要直接使用以上任何一种 | double 和 long 都不适合精确的货币计算,应使用 java.math.BigDecimal。 |
| 需要四舍五入 | Math.round() |
这是最符合数学直觉的舍入方式。 |
| 需要截断小数部分 | (long) 强制转换 |
从 99 中只取整数部分 123,这在计算页码、分页等场景中很常见。 |
| 处理超大数值 | 先检查范围 | 在转换前,检查 double 是否在 Long.MIN_VALUE 和 Long.MAX_VALUE 之间。 |
完整示例与最佳实践
下面是一个综合示例,展示了不同情况下的转换,并包含了范围检查。
public class DoubleToLongBestPractice {
public static void main(String[] args) {
double[] testDoubles = {
123.0,
123.999,
-456.001,
456.5,
-456.5,
1e20, // 一个非常大的数
1e-20 // 一个非常小的数
};
for (double d : testDoubles) {
System.out.println("--- 处理 double 值: " + d + " ---");
// 1. 强制转换 (截断)
long castedValue = (long) d;
System.out.println("强制转换 (截断): " + castedValue);
// 2. 使用 Math.round() (四舍五入)
long roundedValue = Math.round(d);
System.out.println("Math.round() (四舍五入): " + roundedValue);
// 3. 最佳实践:检查范围后再进行四舍五入
if (d >= Long.MIN_VALUE && d <= Long.MAX_VALUE) {
// 如果值在范围内,可以安全地使用 Math.round()
System.out.println("安全范围内,Math.round() 结果有效: " + roundedValue);
} else {
System.out.println("警告: double 值超出 long 范围,转换结果可能不正确!");
}
System.out.println();
}
}
}
| 方法 | 语法 | 舍入/截断方式 | 适用场景 |
|---|---|---|---|
| 强制类型转换 | (long) myDouble |
直接截断 (向零方向) | 只需要整数部分,不关心小数部分。 |
| Math.round() | Math.round(myDouble) |
四舍五入 (到最接近的整数) | 需要遵循标准的数学舍入规则。 |
double 到 long 的转换不是无损的,选择哪种方式完全取决于你的业务逻辑需求,对于需要高精度的场景,请务必使用 BigDecimal。
