杰瑞科技汇

Java double转int会丢失精度吗?

核心方法:强制类型转换 (Casting)

这是最直接、最常用的方法,在 Java 中,可以通过在变量前加上目标类型 (int) 来进行强制转换。

语法:

int intValue = (int) doubleValue;

工作原理: 这种转换会直接截断 (truncate) 小数部分,而不是进行四舍五入,也就是说,它会丢弃小数点后的所有数字,只保留整数部分。


示例与详解

示例 1:简单的截断

public class DoubleToIntExample {
    public static void main(String[] args) {
        double positiveDouble = 99.89;
        double negativeDouble = -99.89;
        // 强制类型转换,直接截断小数部分
        int positiveInt = (int) positiveDouble;
        int negativeInt = (int) negativeDouble;
        System.out.println("原始 double 值: " + positiveDouble);
        System.out.println("转换后的 int 值: " + positiveInt); // 输出 99
        System.out.println("原始 double 值: " + negativeDouble);
        System.out.println("转换后的 int 值: " + negativeInt); // 输出 -99
    }
}

输出:

原始 double 值: 99.89
转换后的 int 值: 99
原始 double 值: -99.89
转换后的 int 值: -99

可以看到,无论是正数还是负数,(int) 转换都直接抛弃了小数部分 .89


重要注意事项

精度丢失问题

double 是一个 64 位的浮点数,而 int 是一个 32 位的整数,当 double 的值超出了 int 的表示范围时,强制转换会导致溢出

int 的范围是: -2,147,483,6482,147,483,647

public class DoubleToIntOverflow {
    public static void main(String[] args) {
        double tooLargeDouble = 2.147483648E9; // 这个值比 Integer.MAX_VALUE 还大
        double tooSmallDouble = -2.147483649E9; // 这个值比 Integer.MIN_VALUE 还小
        System.out.println("原始 double 值: " + tooLargeDouble);
        System.out.println("Integer.MAX_VALUE: " + Integer.MAX_VALUE);
        int overflowedInt = (int) tooLargeDouble;
        System.out.println("转换后的 int 值: " + overflowedInt); // 输出一个完全错误的负数
        System.out.println("原始 double 值: " + tooSmallDouble);
        System.out.println("Integer.MIN_VALUE: " + Integer.MIN_VALUE);
        int underflowedInt = (int) tooSmallDouble;
        System.out.println("转换后的 int 值: " + underflowedInt); // 输出一个完全错误的正数
    }
}

输出:

原始 double 值: 2147483648.0
Integer.MAX_VALUE: 2147483647
转换后的 int 值: -2147483648  // 溢出后变成了最小值
原始 double 值: -2147483649.0
Integer.MIN_VALUE: -2147483648
转换后的 int 值: 2147483647   // 下溢后变成了最大值

在进行转换前,最好先检查 double 的值是否在 int 的范围内。


如何进行四舍五入?

如果你需要的是四舍五入而不是截断,应该使用 java.lang.Math 类中的方法。

  • Math.round(double d):

    • 返回 long 类型,是距离 d 最近的整数,如果是 .5,则向“正无穷”方向舍入(5 舍为 2-1.5 舍为 -1)。
    • 如果需要 int,还需要进行一次强制转换。
    double myDouble = 99.5;
    long roundedLong = Math.round(myDouble); // 结果是 100L
    int roundedInt = (int) Math.round(myDouble); // 结果是 100
  • Math.floor(double d):

    • 返回 double 类型,是不大于 d 的最大整数(向下取整)。
    • 需要再进行一次强制转换为 int
    double myDouble = 99.9;
    double flooredDouble = Math.floor(myDouble); // 结果是 99.0
    int flooredInt = (int) flooredDouble; // 结果是 99
  • Math.ceil(double d):

    • 返回 double 类型,是不小于 d 的最小整数(向上取整)。
    • 需要再进行一次强制转换为 int
    double myDouble = 99.1;
    double ceiledDouble = Math.ceil(myDouble); // 结果是 100.0
    int ceiledInt = (int) ceiledDouble; // 结果是 100

最佳实践与安全转换

为了处理潜在的溢出问题,并保持代码的健壮性,推荐使用以下方法:

手动检查范围

在转换前,使用 Integer 类的常量进行比较。

public class SafeConversion {
    public static void main(String[] args) {
        double value = 2.147483648E9; // 可能溢出的值
        // 检查是否在 int 范围内
        if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) {
            int intValue = (int) value;
            System.out.println("安全转换成功: " + intValue);
        } else {
            System.out.println("值超出 int 范围,无法安全转换。");
        }
    }
}

使用 Math.toIntExact() (Java 8+)

如果你先使用 Math.round() 进行了四舍五入,得到了一个 long 结果,并且想确保这个 long 值可以安全地转换为 intMath.toIntExact() 是最佳选择。

它会检查 long 值是否在 int 范围内,如果不在,会抛出 ArithmeticException 异常,这比静默地溢出要好得多。

public class SafeRounding {
    public static void main(String[] args) {
        double d1 = 123.45;
        double d2 = 2.147483648E9; // 这个数四舍五入后仍然会溢出
        // 正常情况
        long roundedLong1 = Math.round(d1); // 123L
        try {
            int result1 = Math.toIntExact(roundedLong1);
            System.out.println("安全转换结果1: " + result1); // 输出 123
        } catch (ArithmeticException e) {
            System.out.println("转换失败: " + e.getMessage());
        }
        // 会溢出的情况
        long roundedLong2 = Math.round(d2); // 2147483648L
        try {
            int result2 = Math.toIntExact(roundedLong2);
            System.out.println("安全转换结果2: " + result2);
        } catch (ArithmeticException e) {
            System.out.println("转换失败: " + e.getMessage()); // 输出转换失败: integer overflow
        }
    }
}

需求 方法 说明 返回类型 是否安全
直接截断小数 (int) doubleValue 直接丢弃小数部分,不是四舍五入。 int 不安全,可能溢出
四舍五入到整数 (int) Math.round(doubleValue) double 四舍五入为 long,再转 int int 不安全,四舍五入后的 long 可能溢出
向下取整 (int) Math.floor(doubleValue) 返回不大于该值的最大整数。 int 不安全,原始值可能溢出
向上取整 (int) Math.ceil(doubleValue) 返回不小于该值的最小整数。 int 不安全,原始值可能溢出
安全的四舍五入转换 Math.toIntExact(Math.round(doubleValue)) 先四舍五入,再检查是否在 int 范围内,否则抛异常。 int 安全,通过异常处理溢出
安全的截断转换 手动检查 if (d >= Integer.MIN_VALUE && d <= Integer.MAX_VALUE) 先检查范围,再进行转换。 int 安全,通过条件判断处理溢出

核心建议:

  1. 明确你的意图:你是想截断小数,还是想四舍五入?选择对应的函数。
  2. 始终考虑溢出:特别是当你的 double 值可能来自外部计算或用户输入时。
  3. 优先使用安全方法:对于关键业务逻辑,使用手动范围检查或 Math.toIntExact() 来避免静默的溢出错误,让问题能被及早发现和处理。
分享:
扫描分享到社交APP
上一篇
下一篇