杰瑞科技汇

Java long转integer会丢失精度吗?

long 是一个 64 位整数,而 int 是一个 32 位整数。int 的表示范围是 -2,147,483,6482,147,483,647(即 -2^312^31 - 1)。long 类型的值超出了这个范围,直接转换会导致数据截断,即高位数据丢失,得到一个错误的、无意义的 int 值。

Java long转integer会丢失精度吗?-图1
(图片来源网络,侵删)

下面我将介绍几种转换方法,并重点讲解如何处理数据溢出的问题。


强制类型转换(不处理溢出)

这是最直接、最快速的方法,但也是最危险的方法,因为它不进行任何溢出检查。

语法:

int targetInt = (int) sourceLong;

示例代码:

Java long转integer会丢失精度吗?-图2
(图片来源网络,侵删)
public class LongToIntExample {
    public static void main(String[] args) {
        // 情况1:long 值在 int 范围内
        long longValue1 = 12345L;
        int intValue1 = (int) longValue1;
        System.out.println("long 值 " + longValue1 + " 转换为 int: " + intValue1); // 输出: 12345
        // 情况2:long 值超出 int 范围(会发生数据截断)
        long longValue2 = 2147483650L; // 比 Integer.MAX_VALUE (2147483647) 大
        int intValue2 = (int) longValue2;
        System.out.println("long 值 " + longValue2 + " 强制转换为 int: " + intValue2); 
        // 输出: -2147483646 (高位被截断,结果是一个负数)
        // 情况3:long 值远小于 int 范围(同样会发生数据截断)
        long longValue3 = -2147483650L; // 比 Integer.MIN_VALUE (-2147483648) 小
        int intValue3 = (int) longValue3;
        System.out.println("long 值 " + longValue3 + " 强制转换为 int: " + intValue3);
        // 输出: 2147483646 (高位被截断,结果是一个正数)
    }
}
  • 优点:性能高,语法简单。
  • 缺点不安全long 值超出 int 范围,会导致数据丢失,程序不会报错,但结果可能完全错误。
  • 适用场景:当你100%确定 long 的值永远不会超出 int 的表示范围时使用,这个 long 值本身就是从一个 int 变量转换过来的,或者它来自一个有明确范围限制的源。

使用 Math.toIntExact()(推荐,处理溢出)

如果你需要确保转换的安全性,即在转换前检查值是否在 int 范围内,可以使用 java.lang.Math 类中的 toIntExact() 方法。

语法:

int targetInt = Math.toIntExact(sourceLong);

行为:

  • long 值在 int 范围内,它会成功转换并返回结果。
  • long超出 int 范围,它会抛出一个 ArithmeticException 异常,通知你发生了算术溢出。

示例代码:

Java long转integer会丢失精度吗?-图3
(图片来源网络,侵删)
public class LongToIntSafeExample {
    public static void main(String[] args) {
        // 情况1:long 值在 int 范围内
        long longValue1 = 12345L;
        try {
            int intValue1 = Math.toIntExact(longValue1);
            System.out.println("long 值 " + longValue1 + " 安全转换为 int: " + intValue1); // 输出: 12345
        } catch (ArithmeticException e) {
            System.out.println("转换失败: " + e.getMessage());
        }
        // 情况2:long 值超出 int 范围(会抛出异常)
        long longValue2 = 2147483650L;
        try {
            int intValue2 = Math.toIntExact(longValue2);
            System.out.println("long 值 " + longValue2 + " 安全转换为 int: " + intValue2);
        } catch (ArithmeticException e) {
            // 程序会执行到这里
            System.out.println("转换失败: " + e.getMessage()); // 输出: 转换失败: integer overflow
        }
    }
}
  • 优点安全,能明确地捕获溢出错误,避免程序因错误的数据而继续运行。
  • 缺点:如果发生溢出,会抛出异常,需要使用 try-catch 块来处理,这会增加代码的复杂度。
  • 适用场景强烈推荐在大多数业务场景下使用,当你需要处理来自外部(如用户输入、文件读取、网络请求)的数据,或者无法完全确定 long 值的范围时,这是最安全的选择。

手动检查范围(处理溢出)

如果你不想使用 Math.toIntExact() 或者想自定义溢出后的处理逻辑(给一个默认值而不是抛出异常),可以手动进行范围检查。

逻辑:

  1. 判断 long 值是否大于 Integer.MAX_VALUE
  2. 判断 long 值是否小于 Integer.MIN_VALUE
  3. 如果在范围内,则进行强制转换;如果不在范围内,则执行自定义逻辑(如返回默认值、抛出自定义异常等)。

示例代码:

public class LongToIntManualCheckExample {
    public static void main(String[] args) {
        long longValue = 2147483650L;
        int intValue;
        // 手动检查范围
        if (longValue > Integer.MAX_VALUE || longValue < Integer.MIN_VALUE) {
            System.out.println("警告: long 值 " + longValue + " 超出 int 范围,将使用默认值 0");
            intValue = 0; // 自定义处理逻辑,例如返回默认值
        } else {
            intValue = (int) longValue;
        }
        System.out.println("最终得到的 int 值为: " + intValue); // 输出: 0
    }
}
  • 优点:灵活性高,可以根据业务需求自定义溢出后的处理方式。
  • 缺点:代码量比 Math.toIntExact() 多,需要自己编写检查逻辑。
  • 适用场景:当你需要特殊的溢出处理逻辑,而不是简单地抛出异常时。

总结与最佳实践

方法 语法 优点 缺点 适用场景
强制转换 (int) longValue 性能高,语法简单 不安全,数据溢出时静默截断 100%确定 long 值在 int 范围内
Math.toIntExact() Math.toIntExact(longValue) 安全,明确抛出溢出异常 需要处理 ArithmeticException 推荐,处理不确定范围的 long
手动检查 if/else 检查 灵活性高,可自定义处理逻辑 代码冗长,容易出错 需要特殊溢出处理逻辑的业务

核心建议:

  1. 优先使用 Math.toIntExact():在大多数情况下,这是最安全、最清晰的选择,它能帮助你及早发现潜在的数据问题。
  2. 仅在绝对安全时使用强制转换:代码中有一个 long 变量,但你非常清楚它的来源和范围永远不会导致溢出。
  3. 避免在关键业务逻辑中使用不安全的强制转换:否则,一个微小的数据变化就可能导致程序产生严重且难以排查的 Bug。
分享:
扫描分享到社交APP
上一篇
下一篇