文章目录
- 一个引人深思的场景
- 阿里巴巴开发手册的规定
- 包装类型与基本类型的核心区别
- 1. 默认值:null vs 0/false
- 2. 内存与性能对比
- 3. 自动装箱与拆箱的陷阱
- 阿里巴巴为何做出这样的强制要求?
- 1. 业务表达的精确性
- 2. 故障快速发现机制
- 3. 集合框架与泛型的需要
- 实战场景分析
- 场景一:数据库映射
- 场景二:RPC接口返回值
- 场景三:配置信息读取
- 最佳实践与总结
- 什么时候用包装类型?什么时候用基本类型?
- 防范NPE的注意事项
- 总结
- 参考文章
大家好,我是你们的技术老友科威舟,今天给大家分享一下为什么阿里巴巴强制要求使用包装类型定义属性?
技术选型背后的思考,远比你想象得更重要
阿里巴巴为什么在开发手册中强制要求使用包装类型定义属性。相信不少小伙伴在代码审查中,都因使用基本类型而被"教育"过吧?
一个引人深思的场景
假设我们需要创建一个学生成绩管理系统,其中有一个Student类,里面有一个score字段表示考试成绩。使用基本类型和包装类型会有什么不同呢?
// 使用基本类型publicclassStudent{privateintscore;// 默认值为0}// 使用包装类型publicclassStudent{privateIntegerscore;// 默认值为null}看起来差别不大?但想象一下:当学生没有参加考试时,如果用int类型,分数会自动初始化为0,这就会产生误导——到底是考了0分,还是没考试?
使用Integer类型,未参加考试时可以明确表示为null,考了0分则是0。这两种状态在业务上的含义是完全不同的。
阿里巴巴开发手册的规定
在阿里巴巴的Java开发手册中,有这样明确的规定:
- 【强制】所有的POJO类属性必须使用包装数据类型
- 【强制】RPC方法的返回值和参数必须使用包装数据类型
- 【推荐】所有的局部变量使用基本数据类型
这些规定背后,是阿里巴巴多年积累的经验和教训。我们一起来剖析其中的技术深意。
包装类型与基本类型的核心区别
1. 默认值:null vs 0/false
基本类型有固定的默认值:int为0,boolean为false等。包装类型默认值均为null。
这在实际业务中极为重要。以扣费系统为例:需要从外部定价系统读取费率值,使用公式"金额 × 费率 = 费用"计算。
如果费率字段使用double类型,当计费系统异常返回默认值时,会得到0.0,系统可能直接计算并扣费0元,这种异常无法被感知。
如果使用Double类型,异常时返回null,计算时会直接报错,阻断程序,问题能被立即发现。
2. 内存与性能对比
基本类型在栈上直接存储值,内存占用固定且小,效率高。包装类型是对象,在堆中存储,有对象头等额外开销。
来看一个性能测试例子:
longstart=System.nanoTime();intsum=0;for(inti=0;i<10000000;i++){sum+=i;// 直接使用基本类型}System.out.println("基本类型耗时:"+(System.nanoTime()-start));start=System.nanoTime();Integersum2=0;for(Integeri=0;i<10000000;i++){sum2+=i;// 涉及自动装箱拆箱}System.out.println("包装类耗时:"+(System.nanoTime()-start));在测试中,包装类版本的代码运行时间通常是基本类型的3-5倍。这是因为每次运算都涉及对象的创建销毁和自动装箱拆箱的开销。
3. 自动装箱与拆箱的陷阱
自动装箱(autoboxing)是Java 5引入的特性,允许基本类型和包装类型自动转换:
Integera=100;// 自动装箱,实际执行Integer.valueOf(100)intb=a;// 自动拆箱,实际执行a.intValue()但这会带来性能问题和潜在异常:
Integernum=null;intvalue=num;// 抛出NullPointerException!包装类允许为null,这是它的优势,但也需要在拆箱前进行null检查。
阿里巴巴为何做出这样的强制要求?
1. 业务表达的精确性
在业务系统中,“没有值"和"有零值”是两种完全不同的状态。想象一个电商场景:
- 用户未设置年龄(null)与用户年龄为0岁(0)
- 商品库存为null(尚未设置)与库存为0(缺货)
这些情况在业务处理上应该有不同逻辑,包装类型通过null值提供了这种区分能力。
2. 故障快速发现机制
阿里巴巴开发手册中指出,包装类型的null值能够表示额外的信息,如远程调用失败或异常退出。
在分布式系统中,RPC调用可能因为各种原因失败。如果返回包装类型的null,调用方可以明确知道调用失败;而如果返回基本类型的默认值(如0或false),系统可能会错误地继续执行,导致更严重的业务问题。
3. 集合框架与泛型的需要
Java的集合框架(如ArrayList、HashMap)只能存储对象,不能存储基本类型。在使用泛型时,也必须使用包装类型。
// 错误,编译不通过// List<int> list = new ArrayList<>();// 正确List<Integer>list=newArrayList<>();实战场景分析
场景一:数据库映射
当从数据库查询数据时,如果字段允许为NULL,对应的实体类属性应该使用包装类型。
// 用户实体publicclassUser{privateIntegerage;// 使用包装类型,允许为nullprivateStringname;// getter和setter方法}如果使用int类型,当数据库中的age字段为NULL时,ORM框架可能无法正确处理,或者会返回0,导致业务逻辑错误。
场景二:RPC接口返回值
在分布式系统中,远程调用可能失败或被降级,此时返回默认值还是null有重要意义:
// RPC接口定义publicinterfaceProductService{/** * 根据ID查询商品价格 * @param productId 商品ID * @return 价格,如果查询失败返回null */DoublegetPrice(LongproductId);}调用方可以通过判断返回值是否为null,来确定调用是否成功,并相应处理。
场景三:配置信息读取
当从配置中心读取配置时,未配置的项和使用默认值的项应该有不同含义:
publicclassSystemConfig{privateIntegermaxConnections;// 最大连接数,null表示使用系统默认privateBooleanenableCache;// 是否启用缓存,null表示使用系统默认}最佳实践与总结
什么时候用包装类型?什么时候用基本类型?
根据阿里巴巴开发手册和实际经验,总结如下:
- POJO类属性:强制使用包装类型
- RPC方法参数和返回值:强制使用包装类型
- 局部变量:推荐使用基本类型(性能考虑)
- 高频计算场景:使用基本类型(减少自动装箱拆箱开销)
- 集合框架:必须使用包装类型
防范NPE的注意事项
使用包装类型不是逃避NPE问题的借口,反而要更加注意空指针异常。推荐做法:
- 使用前进行null检查
- 使用Java 8的Optional类包装可能为null的值
- 在接口文档中明确标注哪些返回值可能为null
总结
阿里巴巴强制要求使用包装类型定义属性,是基于多年大规模分布式系统开发经验的总结。这一规定主要考虑以下几点:
- 业务表达准确性:null可以明确区分"无值"和"零值"
- 故障快速发现:通过null快速发现异常,避免默认值导致的业务错误
- 系统健壮性:在分布式系统中,包装类型能更好地表达远程调用的真实结果
- 技术一致性:符合面向对象设计和泛型编程的要求
恰当运用包装类型,能让代码更加健壮和易于维护。当然,也要根据具体场景灵活选择,在性能和表达能力之间找到平衡。
希望这篇文章能帮助你理解包装类型的重要性。如果你有相关经验或疑问,欢迎在评论区交流!
参考文章
- http://mp.weixin.qq.com/s?__biz=MzA3MTMzMTAyMw==&mid=2247489463&idx=1&sn=042fb3175a5ddd87faa2d1b10d14ceea&chksm=9e415a04d8c8b900fc74f1632636cbfd25578f496685053ec5b7b6685cb0c75f6a07de825667#rd
- http://mp.weixin.qq.com/s?__biz=MzI3NzE0NjcwMg==&mid=2650168914&idx=1&sn=fd0b9c0adfcac92cc1a22e73b115b3c6&chksm=f2d3e957978836c5c9e9c6a840b7abe00981915d998c5b1fde2788042c8b0581731e3c3f5bfc#rd
- https://blog.51cto.com/u_15127548/4526058
- https://www.nowcoder.com/discuss/745978311058231296?sourceSSR=post
- http://www.mianshiya.com/question/1780933294544678914?comment=1850092084391467010
- http://mp.weixin.qq.com/s?__biz=MzIwNTc3OTAxOA==&mid=2247493167&idx=1&sn=62648f140e3dfafd3b78bc793a46c394&chksm=966f0b7dbe1e861f6ba6f4af35bce428d7543743dae5a4a1fc69528991d10993de7be7a7a846#rd
- 本文主要观点基于以上参考资料,结合实际开发经验整理而成。转载请注明出处。*
更多技术干货欢迎关注微信公众号科威舟的AI笔记~
【转载须知】:转载请注明原文出处及作者信息