基元需要走吗?

我目前正在使用JSF作为视图技术,使用JPA作为持久层的企业应用程序。 它可能是支持bean或服务方法中的某种东西,但令我震惊:是否有充分的理由在企业应用程序中使用原语?

当我开始围绕J2SE 1.2使用Java进行编程(或者是J2SE 5.0,或者也许是Java 2?)时,我仅在代码中使用了原语。 当时,我认为可以依靠默认值,而不必在使用之前初始化某些东西,这很好。 当时我对包装器并不了解太多,并且认为我没有充分的理由进一步研究它们。

我没有什么清楚的记忆,我何时开始使用原始包装器,但是我确实记得JDK 1.5何时允许在原始体及其各自的原始包装器类之间进行自动转换,或者通常称为自动装箱/拆箱。 很好,因为将int传递给需要Integer的方法并不重要,反之亦然。 语法糖似乎使编程容易一些。

构架

即使诸如JSF和JPA之类的Java企业框架为您做了很多工作,它也暴露了依赖自动装箱和原语的一些弱点。

这些框架依赖于原始包装类的使用,而不是各个原始包装类的使用。 如果使用JPA工具基于现有表创建实体,则该工具将使用变量类型的包装器。 JSF输入和转换器对对象进行操作。 使用JPA,必须这样做。 还记得原始的默认值吗? 基元的默认值可以与数据库中存储的值混淆。

如果将long用作简单的实体ID,则该实体的默认值为0L。 从技术上讲0L是一个值,因此很难知道该实体是否已保留。 如果id的类型为Long ,则很容易判断该实体是否已保留,因为id现在可以为null ,因此表示未持久的实体。

//id is long and entity is not persisted
long id = entity.getId();  //value of 0L
Long id = entity.getId();  //doesn’t help, still 0L

//id is Long and entity is not persisted
Long id = entity.getId();  //null
long id = entity.getId();  //what happens here?
//reference: https://keyholesoftware.com/2014/10/13/java-and-the-sweet-science/

类型上下文

原始类型不能充分表达值的语义上下文。 假设我们从服务中检索今天的温度,并且返回的值表示度数是int 。 容易确定int度的上下文是什么?

首先,该值是以摄氏度还是华氏度表示的? 第二,如果值为0,该怎么办? 您将不得不假设该值是实际设置的,而不是默认值0。您可能想知道为什么当服务说它为0时,它感觉像是70度外。

最好的解决方案可能是使用解析为适当值的自定义对象,而不是使用原始或什至原始包装器。 对于代表温度的值,我们可以创建一个华氏温度对象。 该对象将消除对值上下文的所有怀疑。

//
public class Fahrenheit {
…
	private Integer degrees;
…
}

Fahrenheit f = temperatureService.getDegrees(today);

//

当该方法期望华氏温度时,开发人员将无法意外传入一个摄氏温度对象。

//
…
public Celsius convertDegrees(Fahrenheit f) {
…
}

//only this would work
Celsius c = temperatureService.convertDegrees(f);

//

使用原语作为返回值也可能是模棱两可的。 返回一个布尔值以表示某件事是否有效不一定表示发生了什么。 通过包含更多信息,使用Result对象更具描述性。

嘲笑

尽管模拟框架可以处理基元,但是模拟框架喜欢与对象一起使用。 下面的代码段是JMock中的Expectations类。 如下面的代码片段所示,一些自动装箱魔术使框架可以设置期望返回int值为6的期望。

Expectations.returnValue(Object result):        

  context.checking(new Expectations() {
 	{
   	atLeast(1).of(serviceMock).getPrimitive(5);
            	will(returnValue(6));
….
}

无标题2

由于动态创建了数组对象,因此JMock似乎可以正确处理原始数组。

Expectations.returnValue(Object result):        

  context.checking(new Expectations() {
 	{
           	int[] ints = { 2, 3 };
            	atLeast(1).of(serviceMock).getPrimitives(5);
            	will(returnValue(ints));
….
}

无题3

即使基元和基元数组与模拟框架一起使用,也感觉您未在使用真实值。 您的参数是一个int ,但是模拟框架希望您使用Integer。

思想

回顾原始包装器的历史,随着时间的推移包装器的功能不断增强,自动装箱/拆箱以及从其他语言的开发人员那里阅读文章,感觉原始器可能已被排除在Java的最初实现之外。 Java是一种面向对象的语言,但是包含非对象原语。 自动装箱功能比真正的解决方案更像创可贴。

由于企业应用程序可以访问大量资源,因此我将其特定于企业应用程序。 该环境使创建使用诸如IntegerFahrenheit之类的对象的描述性代码变得更加容易。 在垃圾收集成本和堆大小很重要的受限设备中,原语很有意义,并且比对象同类具有优势。

翻译自: https://www.javacodegeeks.com/2015/02/do-primitives-need-to-go.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值