Guava,Objects/MoreObjects 重载以避免自动装箱。

Guava, Objects/MoreObjects overloading to avoid autoboxing.

Guava Objects(已弃用)或 MoreObjects 使用构建器模式实现 ToStringHelper class,add() 函数为基本类型和对象实现:

public ToStringHelper add(String name, @Nullable Object value)
public ToStringHelper add(String name, boolean value) 
public ToStringHelper add(String name, char value) 
... (other primitive type)

即使不重载基本类型,class 也能正常工作,因为自动装箱会转换并调用 add(String, Object) 函数。

所以我的问题是对所有基元使用重载以避免自动装箱的原因?

1.repetitive 自动装箱可能是一个巨大的开销,但对于大多数用例来说,这不会发生。有效 Java 项 49,优先使用原始类型而不是盒装原始类型。

2.Efffective Java,项目 41,P193,

A safe conservative policy is never to export two overloadings with the same number of parameters.

ToStringHelper 示例明显违反了此政策。作者接着在 class ObjectOutputStream 中讲到,不同的原语有自己的函数:writeBoolean(boolean), writeInt(int) ...这个具体的例子,为什么好呢?

欢迎任何意见。

我犹豫要不要给出这个答案,因为这是对 Guava 语言设计者的质疑。他们可能会给你一个明确的答案,但这是我的推测:

在 Effective Java 第二版第 193 页的 "conservative policy" 之前不久声明:

Avoid confusing uses of overloading

然后它接着说

Exactly what constitutes a confusing use of overloading is up for some debate

我认为这不是对重载的混淆使用。我这样说是因为 class 的逻辑行为与简单实现为:

的逻辑行为相同
public ToStringHelper add(String name, @Nullable Object value)
// No primitive overloads.

但是,EJ 中还有其他建议可以发挥作用。一个是第 20 页的第 49 项,另一个是第 5 项,"Avoid creating unnecessary objects".

没有必要创建装箱的基元,因为有 String.valueOf(...) 的重载处理每个基元类型,不可避免地比装箱和调用 toString().

更有效

请记住,Guava 首先是为 Google 编写的,然后他们将其开源。在 Google 工作的规模上,使用原始类型和创建盒装类型、调用 toString() 和销毁对象之间的区别将是可以衡量的。

添加这些重载将带来性能上的提升,而调用者实际上不需要做任何事情来获得它。另一方面,如果有不同名称的重载(例如 addCharaddBoolean),您实际上必须有意识地选择要调用的重载,并且可能许多调用会懒惰 select Object 重载,因为,嘿,它有效。保持相同的名称可以使其透明地工作。


Guava 中还有很多其他示例可以避免通过重载创建不必要的对象。例如,ImmutableListof 静态工厂方法,为零、一、二、...、十一个元素重载,然后其他一切都由可变参数重载处理。

可以简单地实现为ImmutableList.of(T... elements),但这需要每次都隐式创建可变参数数组,必须在内部进行防御性复制,以便保证列表的不变性。

因此,这些重载提供了更有效地构建列表的机会。然而,作为 class 的用户,您可能从未注意到这一点。

我对对象进行了更改以添加额外的重载。 是的,这样做是为了避免自动装箱。我们偶尔会看到性能敏感代码和自动装箱的问题(另一个 API 我们经常收到关于 w.r.t.autoboxing 是先决条件,但我们还没有在那里进行更改)。

FWIW,这是 original bug report