【问题标题】:Most performant way to achieve type safety on primitive types in Java?在 Java 中实现原始类型类型安全的最高效方法?
【发布时间】:2020-02-25 13:30:39
【问题描述】:

假设我想确保 Java 中原始类型的类型安全。为了举例,让我们想区分RatioAbsoluteValue,两者都由double 表示。

据我所知,Java 不支持类型同义词

所以我很有信心会涉及一些开销。

从我的脑海中,我可以想到要么定义包装 double 的新类(很多样板文件),或者子类化 Double... 或者甚至还有其他选项?

哪种方法给我的性能开销最小?

编辑:我仅限于 Java 8,所以这是问题的隐含基础;但是,如果在新版本的语言中有替代解决方案,我仍然很想知道它们。

【问题讨论】:

  • 好吧,你不能子类 Double,它是最终的。如果必须,您可以创建自定义包装类。
  • 有一个units of measure API
  • 对性能影响最小的是基于类型注释的解决方案,因为它根本不会影响运行时行为。事实上,即使是 Java 编译器也会忽略它们,因此您需要集成一个注释处理器来强制执行 @Ratio double 不能从 @AbsoluteValue double 分配的规则。我不知道是否有现成的解决方案,比如配置现有的检查工具来添加该规则。 Treating int like enum 是使用带有语义的原始类型的相关示例。

标签: java java-8 boxing type-safety type-alias


【解决方案1】:

我能想到的最性能的方法是编写你自己的带有一些标记注释的包装类:

@PrimitiveTypeAlias(double.class)
public class Milliseconds
{
    double value() { ... } 
}

然后在编译时挂钩到注释处理器,并用它们的原始对应物物理替换包装器类(使用类似 Lombok 的东西)。

...但我怀疑您可能一直在暗示“最高效且省力”:)

【讨论】:

  • 更简单的是the other way round,创建类型注释并将它们与原始类型一起使用,因此编译器确实已经生成了预期的字节码。因此注释处理器的职责是检查类型使用的正确性,至少在某种程度上,工具确实已经存在。
  • 如前所述,这些工具确实已经存在。 @NonNull 等已经提供的功能并没有什么不同。他们不需要分析堆栈,因为他们只需检查每个分配。当每个赋值都正确时,正确性会传递到整个代码。我已经链接到我之前评论中的一个示例,尽管它是针对用作枚举的int 值量身定制的。但原理是一样的。
  • @Holger 您链接到的该策略的根本问题是,如果注释存在,它只会导致编译时失败。没有什么可以强制您添加它们。您需要实际记住注释 每个 方法返回、参数、字段...如果您错过了复杂调用层次结构的一半,您的 NavigationMode 从严格强制的类型返回,返回到普通的旧 int。如果你有一个 正确的 类型系统,就不会发生这种情况。您不能像使用注解那样忘记类型,因为需要类型而注解不是。
  • 重点是,没有这种东西存在的原因,是因为它非常难。当您使用 DoubleMilliseconds 类之类的引用类型时,该类型的变量可以变为 null 或分配给更广泛类型的引用变量,例如 Object 或存储到数组中,而不仅仅是 @ 类型987654330@,但也属于Object[] 类型(后者甚至可能包含除Milliseconds 之外的其他对象。因此,您不能用等效的原始类型替换每一次出现的盒装类型。
  • @Holger 他问“实现类型安全的最高效方式”是什么。正如我已经解释的那样,您的建议不提供类型安全。在我看来,我在这里写的内容似乎是“实现类型安全的最高效方式”。但是,类型安全的好处值得花时间编写这样的东西吗?我怀疑大多数人的结论是“不”。这会使答案无效吗?我不这么认为。
【解决方案2】:

看看Manifold 框架(类似于Lombok,但更关注类型而不是样板减少)。 @Extension 方法或@Structural 接口提供了各种实现“鸭子类型”的方法,这些方法涵盖了一些要求。但是,它不能直接与原始字段一起使用。在各种情况下,JIT 可以优化一个非常基本的包装类(并且当它登陆时将能够使用Project Valhalla's inline modifier)。

(我怀疑实现一流的别名来补充 Manifold 现有的功能集是一个合理的功能请求。)

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2016-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-20
  • 1970-01-01
  • 2013-01-02
  • 1970-01-01
相关资源
最近更新 更多