将 double 的小数部分去掉,只保留整数部分,如何处理小数部分(是四舍五入还是直接截断)以及如何处理超出 long 范围的值,是关键所在。

Java 主要提供了以下几种方法来实现 double 到 long 的转换,每种方法的行为都不同。
使用强制类型转换 (long)
这是最直接、最常用的方法,它会直接截断小数部分,也就是将 double 向零方向取整。
语法:
long value = (long) doubleValue;
特点:

- 行为: 截断小数部分。
- 示例:
(long) 10.9结果是10(long) 10.1结果是10(long) -10.9结果是-10(注意,是向零取整,而不是向下取整)
- 优点: 速度快,语法简单。
- 缺点: 不进行四舍五入,可能会造成数据精度的损失。
示例代码:
public class DoubleToLongCast {
public static void main(String[] args) {
double d1 = 123.456;
double d2 = 78.999;
double d3 = -99.8;
long l1 = (long) d1; // 截断小数部分
long l2 = (long) d2; // 截断小数部分
long l3 = (long) d3; // 截断小数部分
System.out.println("原始值: " + d1 + " -> 转换后: " + l1); // 输出: 原始值: 123.456 -> 转换后: 123
System.out.println("原始值: " + d2 + " -> 转换后: " + l2); // 输出: 原始值: 78.999 -> 转换后: 78
System.out.println("原始值: " + d3 + " -> 转换后: " + l3); // 输出: 原始值: -99.8 -> 转换后: -99
}
}
使用 Math.round() 方法
Math.round() 方法会根据小数部分进行四舍五入,然后返回一个 long 或 int 类型的结果。
语法:
long value = Math.round(doubleValue);
特点:

- 行为: 四舍五入到最接近的整数。
- 示例:
Math.round(10.4)结果是10Math.round(10.5)结果是11Math.round(-10.5)结果是-10(注意,Java 的round方法在.5的情况下会向“正无穷”方向取整)
- 优点: 符合常规的四舍五入规则,适用于需要精确到整数且对精度要求高的场景。
- 缺点: 比强制类型转换稍慢。
示例代码:
public class DoubleToLongRound {
public static void main(String[] args) {
double d1 = 123.456;
double d2 = 78.5;
double d3 = -99.5;
long l1 = Math.round(d1);
long l2 = Math.round(d2);
long l3 = Math.round(d3);
System.out.println("原始值: " + d1 + " -> 转换后: " + l1); // 输出: 原始值: 123.456 -> 转换后: 123
System.out.println("原始值: " + d2 + " -> 转换后: " + l2); // 输出: 原始值: 78.5 -> 转换后: 79
System.out.println("原始值: " + d3 + " -> 转换后: " + l3); // 输出: 原始值: -99.5 -> 转换后: -99
}
}
使用 Math.floor() 方法
Math.floor() 方法会向下取整,即返回小于或等于该 double 值的最大整数。
语法:
long value = (long) Math.floor(doubleValue);
注意:Math.floor() 返回的是 double 类型,所以仍然需要强制转换为 long。
特点:
- 行为: 向下取整。
- 示例:
Math.floor(10.9)结果是0,转换为long后是10Math.floor(10.1)结果是0,转换为long后是10Math.floor(-10.1)结果是-11.0,转换为long后是-11(注意,这是向下取整)
- 优点: 在需要向下取整的场景(如计算页数、分组等)非常有用。
- 缺点: 对于正数,效果和强制类型转换类似;但对于负数,结果完全不同。
示例代码:
public class DoubleToLongFloor {
public static void main(String[] args) {
double d1 = 10.9;
double d2 = -10.1;
long l1 = (long) Math.floor(d1);
long l2 = (long) Math.floor(d2);
System.out.println("原始值: " + d1 + " -> 转换后: " + l1); // 输出: 原始值: 10.9 -> 转换后: 10
System.out.println("原始值: " + d2 + " -> 转换后: " + l2); // 输出: 原始值: -10.1 -> 转换后: -11
}
}
使用 Math.ceil() 方法
Math.ceil() (ceiling) 方法会向上取整,即返回大于或等于该 double 值的最小整数。
语法:
long value = (long) Math.ceil(doubleValue);
同样,Math.ceil() 也返回 double 类型,需要强制转换。
特点:
- 行为: 向上取整。
- 示例:
Math.ceil(10.1)结果是0,转换为long后是11Math.ceil(10.9)结果是0,转换为long后是11Math.ceil(-10.9)结果是-10.0,转换为long后是-10
- 优点: 在需要向上取整的场景非常有用。
- 缺点: 和
floor一样,对于正负数的行为需要注意。
示例代码:
public class DoubleToLongCeil {
public static void main(String[] args) {
double d1 = 10.1;
double d2 = -10.9;
long l1 = (long) Math.ceil(d1);
long l2 = (long) Math.ceil(d2);
System.out.println("原始值: " + d1 + " -> 转换后: " + l1); // 输出: 原始值: 10.1 -> 转换后: 11
System.out.println("原始值: " + d2 + " -> 转换后: " + l2); // 输出: 原始值: -10.9 -> 转换后: -10
}
}
处理大数:超出 long 范围的情况
这是一个非常重要的注意事项。double 的表示范围远大于 long。double 的值超出了 long 的表示范围 (Long.MIN_VALUE 到 Long.MAX_VALUE),上述方法会得到意想不到的结果。
long 的范围是: -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807
当 double 的值超出这个范围时:
- 对于非常大的正数,强制转换和
Math.floor()会返回Long.MAX_VALUE。 - 对于非常小的负数,强制转换和
Math.ceil()会返回Long.MIN_VALUE。 Math.round()的行为也是类似的,它会返回Long.MAX_VALUE或Long.MIN_VALUE。
正确的做法是先进行范围检查:
public class DoubleToLongOverflow {
public static void main(String[] args) {
double tooBig = 1.0e308; // 一个远大于 Long.MAX_VALUE 的数
double tooSmall = -1.0e308; // 一个远小于 Long.MIN_VALUE 的数
// 错误的做法:直接转换,会得到 Long.MAX_VALUE 或 Long.MIN_VALUE
System.out.println("直接转换超大数: " + (long) tooBig); // 输出: 9223372036854775807 (Long.MAX_VALUE)
System.out.println("直接转换超小数: " + (long) tooSmall); // 输出: -9223372036854775808 (Long.MIN_VALUE)
// 正确的做法:先检查范围
if (tooBig > Long.MAX_VALUE) {
System.out.println("错误: 值 " + tooBig + " 超出 long 的最大范围。");
} else if (tooBig < Long.MIN_VALUE) {
System.out.println("错误: 值 " + tooBig + " 超出 long 的最小范围。");
} else {
long result = (long) tooBig;
System.out.println("安全转换结果: " + result);
}
}
}
总结与如何选择
| 方法 | 行为 | 适用场景 | 注意事项 |
|---|---|---|---|
(long) d |
直接截断小数部分 | 速度要求高,明确知道小数部分可以丢弃的场景(如从时间戳中提取秒数)。 | 不进行四舍五入,可能损失精度。 |
Math.round(d) |
四舍五入到最接近的整数 | 需要按照数学规则进行舍入的场景(如财务计算、统计)。 | 对于 .5 的情况,向正无穷方向取整。 |
Math.floor(d) |
向下取整 | 需要计算分组、页数等“向下”取整的场景。 | 返回 double,需强制转换,负数行为与截断不同。 |
Math.ceil(d) |
向上取整 | 需要计算向上取整的场景(如资源分配)。 | 返回 double,需强制转换,负数行为与截断不同。 |
| 范围检查 | - | 任何可能超出 long 范围的转换 |
必须进行,否则会得到错误的最大/最小值。 |
最佳实践建议:
- 首选明确你的需求:你想要截断、四舍五入、向下取整还是向上取整?根据需求选择最合适的
Math方法或强制类型转换。 - 始终考虑边界情况:如果输入的
double值可能非常大或非常小,务必先进行范围检查,以避免潜在的溢出错误。 - 注意精度问题:
double本身就存在精度问题,1 + 0.2并不精确等于3,在进行转换前,要确保double的值已经是你期望的值。
