Java语言中,Long与long是开发过程中经常接触的一组数据类型。虽然二者都用于表示整数类型,但它们在数据结构、内存占用、默认值以及空值处理方面存在明显区别。尤其是在数据库操作、接口参数传递、实体类设计等场景中,如果没有正确处理Long和long之间的转换,很容易出现空指针异常等问题。
理解Long与long的区别,并掌握安全转换方式,是Java开发中避免隐藏Bug的重要基础。
Long与long的基本区别
long是Java中的基本数据类型(Primitive Type),而Long是Java提供的包装类型(Wrapper Class),属于对象类型。
二者最大的区别如下:
| 对比项 | long | Long |
|---|---|---|
| 类型 | 基本数据类型 | 包装类 |
| 默认值 | 0 | null |
| 是否可以为空 | 不支持 | 支持 |
| 是否属于对象 | 否 | 是 |
| 是否可以调用方法 | 否 | 可以 |
| 泛型支持 | 不支持 | 支持 |
例如:
Javalong number = 100L; Long objectNumber = 100L;
long直接存储数值,而Long实际上是一个对象引用,内部封装了一个long类型的数据。
在实际开发中,如果字段可能不存在或者数据库字段允许为空,通常建议使用Long,而不是long。
例如:
Javapublic class User { private Long id; private String username; }
如果数据库中的id没有赋值,Long可以表示为null:
Javauser.setId(null);
而使用long:
Javaprivate long id;
即使没有初始化,也会自动赋值为0,无法区分“没有值”和“真实值为0”。
Long转换为long的方法
Long转换为long属于对象类型向基本类型转换,也称为拆箱(Unboxing)。
自动拆箱
Java支持自动拆箱,可以直接赋值:
JavaLong value = 100L; long result = value;
编译器会自动转换为:
Javalong result = value.longValue();
这种方式代码简单,但存在一个隐藏风险。
如果Long对象为null:
JavaLong value = null; long result = value;
运行时会抛出:
java.lang.NullPointerException
原因是Java尝试调用:
Javavalue.longValue();
而null对象无法调用方法。
使用longValue()显式转换
Long提供了longValue()方法:
JavaLong value = 200L; long result = value.longValue();
这种写法更加明确,但仍然不能处理null:
JavaLong value = null; long result = value.longValue();
依然会出现空指针异常。
因此,在实际项目中不建议直接调用longValue()处理未知来源的数据。
long转换为Long的方法
long转换为Long属于自动装箱(Boxing)。
自动装箱
Java可以自动完成转换:
Javalong number = 300L; Long result = number;
等价于:
JavaLong result = Long.valueOf(number);
自动装箱通常不会产生问题,因为long一定存在值。
使用Long.valueOf()
推荐显式转换:
Javalong number = 500L; Long result = Long.valueOf(number);
相比直接new Long:
JavaLong result = new Long(number);
valueOf()更加推荐,因为Java可以对部分Long对象进行缓存优化。
Long转long时的空值处理
Long最大的风险就是null转换问题。
例如:
Javapublic long getUserId(Long id) { return id; }
如果调用:
JavagetUserId(null);
程序会直接抛出NullPointerException。
因此,需要进行空值判断。
方法一:使用if判断
最基础的处理方式:
Javapublic long convert(Long value) { if (value != null) { return value; } return 0L; }
调用:
JavaLong number = null; long result = convert(number);
结果:
0
这种方式逻辑清晰,适合业务规则明确的场景。
方法二:使用三元表达式
代码更加简洁:
JavaLong value = null; long result = value != null ? value : 0L;
如果value存在,则返回实际值,否则返回默认值。
常用于实体对象转换:
Javalong count = user.getCount() != null ? user.getCount() : 0L;
方法三:使用Optional处理null
Java 8之后,可以使用Optional:
JavaLong value = null; long result = Optional.ofNullable(value) .orElse(0L);
如果Long为空,则返回0。
在复杂对象链式调用中,Optional可提高代码安全性:
Javalong id = Optional.ofNullable(user) .map(User::getId) .orElse(0L);
可以避免多层null判断。
方法四:使用Apache Commons工具类
Apache Commons Lang提供了NumberUtils工具:
Javalong result = NumberUtils.toLong(null);
返回:
0
也可以指定默认值:
Javalong result = NumberUtils.toLong(null, -1L);
返回:
-1
在大型项目中,这类工具方法可以减少重复代码。
数据库场景中的Long与long选择
数据库开发中,Long和long的选择非常重要。
例如:
Java@Entity public class Order { private Long id; private Long userId; }
通常推荐使用Long。
原因包括:
1. 数据库字段可能为空
数据库查询结果可能不存在:
SQLselect user_id from order_table;
如果字段允许NULL:
NULL
无法映射到long。
2. ORM框架需要区分状态
例如MyBatis、Hibernate等框架中:
JavaLong id;
可以表示:
-
未赋值
-
已赋值
-
数据不存在
而:
Javalong id;
只能表示:
-
0
-
非0数字
无法表达空状态。
3. 主键字段推荐Long
实际项目中常见:
Javaprivate Long id;
原因是数据库自增ID通常需要区分:
-
新对象
-
已保存对象
例如:
JavaUser user = new User(); user.getId();
如果id为null,说明对象尚未入库。
Long比较时的注意事项
Long属于对象类型,不能简单使用==比较。
错误方式:
JavaLong a = 100L; Long b = 100L; System.out.println(a == b);
虽然部分情况下结果可能为true,但这是因为Long缓存机制导致的。
推荐使用:
Javaa.equals(b);
例如:
JavaLong a = 1000L; Long b = 1000L; System.out.println(a.equals(b));
结果:
true
如果考虑null情况:
JavaObjects.equals(a, b);
更加安全:
Javaboolean result = Objects.equals(a, b);
当其中一个值为null时,也不会出现异常。
Long与long转换中的常见错误
错误一:直接拆箱导致空指针
代码:
JavaLong count = null; long total = count;
问题:
NullPointerException
解决:
Javalong total = count == null ? 0L : count;
错误二:实体类全部使用long
例如:
Javaclass Product { private long price; }
问题:
数据库NULL无法映射。
建议:
Javaprivate Long price;
错误三:使用==比较Long
错误:
JavaLong a = 1000L; Long b = 1000L; if(a == b){ }
应该:
Javaif(Objects.equals(a,b)){ }
Java项目中的最佳实践
在实际开发中,可以遵循以下原则:
1. 数据库字段优先使用Long
特别是:
-
主键ID
-
外键ID
-
可为空字段
-
接口返回字段
例如:
Javaprivate Long userId;
2. 方法参数根据业务决定
如果参数必须存在:
Javapublic void update(long id)
如果参数允许为空:
Javapublic void update(Long id)
3. 转换时始终考虑null
不要:
Javalong value = object.getValue();
推荐:
Javalong value = Objects.requireNonNullElse( object.getValue(), 0L );
Java 9以后可以使用这种方式。
4. 使用包装类处理业务数据
业务层推荐:
JavaLong amount;
计算阶段转换:
Javalong total = amount == null ? 0L : amount;
这样可以兼顾数据表达能力和计算效率。
总结
Java中的Long与long虽然都表示长整型数据,但二者在使用场景上存在明显差异。long属于基本类型,性能更高,但无法表示空值;Long属于对象类型,可以表示null,更适合用于实体类、数据库字段以及接口数据传输。
进行Long和long转换时,最需要关注的是自动拆箱带来的空指针问题。开发过程中,应避免直接将可能为null的Long赋值给long变量,而应通过条件判断、Optional、Objects.requireNonNullElse等方式进行安全处理。
合理选择Long和long,并建立规范的空值处理习惯,可以有效提升Java程序的稳定性和可维护性。