Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/397.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java:类型别名支持注释处理工具(APT)?_Java_Type Safety_Annotation Processing_Type Alias - Fatal编程技术网

Java:类型别名支持注释处理工具(APT)?

Java:类型别名支持注释处理工具(APT)?,java,type-safety,annotation-processing,type-alias,Java,Type Safety,Annotation Processing,Type Alias,我从未使用过类型别名,但这个概念似乎是一个非常有用的功能,它可以为相同类型的对象添加语义,并防止常见的拼写错误 比如说,有void foo(浮动体积,浮动重量)。如果像这样调用它是可以的:foo(v,m),但是foo(m,v)不是一个明显的打字错误无效进程(Iterable javaPath,Iterable classPath)可以是另一个用例。不幸的是,Java中没有类型别名,有些变通方法真是过火了: 将单个字段聚合到类中(将原语装箱到对象中;对象中的对象具有额外引用;更复杂的序列化/反序

我从未使用过类型别名,但这个概念似乎是一个非常有用的功能,它可以为相同类型的对象添加语义,并防止常见的拼写错误

比如说,有
void foo(浮动体积,浮动重量)
。如果像这样调用它是可以的:
foo(v,m)
,但是
foo(m,v)
不是一个明显的打字错误<代码>无效进程(Iterable javaPath,Iterable classPath)可以是另一个用例。不幸的是,Java中没有类型别名,有些变通方法真是过火了:

  • 将单个字段聚合到类中(将原语装箱到对象中;对象中的对象具有额外引用;更复杂的序列化/反序列化规则)
  • 从一个类扩展到另一个类(比如-对于原语来说是不可能的;类可能是final或具有不可访问的构造函数)
因此,这两种方法都有缺点和运行时/性能成本

据我所见,在Java中,基于运行时的“类型别名”可能会被编译时检查所取代,比如处理@NotNull和@Nullable。是否有支持void foo(@Volume float Volume,@Weight float Weight)等构造的静态类型别名检查器/APT工具,以便检查器可以在编译时验证此类“类型安全”,并要求对传递的变量/常量和文本进行注释(分别在声明和调用站点)



这个问题也被提出了,因为我目前正在开发一个可以使用多个后端(目前仅限于JDT)的Java源代码处理工具。只要我希望它是JDT不可知的,我就希望有类型、方法和字段的业务对象。尽管我丢失了很多来自JDT AST的信息,但我的工具目前最好的方法是使用字符串(它允许执行一些足以满足工具范围的分析)。但是像
voidprocess(String类型、String字段、String方法)
这样的方法比较混乱,所以我创建了
type
field
method
,它们表示域对象,并且与JDT无关。它们很好,但我不希望将来扩展它们(这三种类型都有一个
私有的最终字符串名;
field+I必须重写
hashCode/equals
toString
)。这让我再次想到了类型检查APT。只要可以处理原始数据,就可以使用类似于
void process(@Type String Type,@Field String Field,@Method String Method)
(我仍然可以使用单个对象)。

如果您的问题是调用
foo(v,m)
时看起来很模糊,人们可能会错误地编写
foo(m,v)
在没有任何警告或可见错误线索的情况下,您可以使用类似于fluent builder的模式:

(代码未经测试,只是为了演示想法而编写)

通过这样做,调用者可以

MyClass myObj = ....;
int result = myObj.foo().withVolume(a).withWeight(b).run();
// which is the same as result = myObject.foo(a,b);

我不明白。如果我正在调用a和b都是
int
foo(a,b)
,那么工具应该如何验证我的
a
是否是
?如果你需要
Volume
来承载语义,那就把它变成一个类。@AdrianShum我只需要在浮点上有更多的语义。将一个原语包装到一个类中会导致另一个类实例化(更多堆),在序列化器/反序列化器中需要更多适配器(例如,GSON不适用于新类--需要更多适配器)。这个想法就像NotNull和Nullable的想法一样——创建类不仅仅是为了添加语义,而是为了注释,对吧。NET支持值类型,这些值类型可以轻松地保存原语,而无需付出性能代价(它本身没有原语,一切都是真实的对象)。但是Java中没有值类型。除非你能告诉我如何检查输入
int
是否是
,否则我认为在这种情况下使用注释是不可行的。如果您正在寻找减少意外输入错误的方法,那么您可能需要一个类似于构建器的流畅模式:类似于
foo().withVolume(a).withWeight(b).run()
。当然,还有额外的开发工作,但是如果方法参数真的那么模糊并且容易混淆,那么额外的工作是值得的。而且,C#中的值对象并不能解决问题。是的,从堆栈实例化的开销较小,但如果我的理解正确的话,仍然会有额外的开销。在Java中,这个问题没有直接的解决方案。如果情况真的那么糟糕,那么包装器类的额外性能损失应该不是什么大问题。有很多方法可以减少额外的开销:flyweight、工厂方法、不变的obj等等。。。。我有点困惑。使用类似于fluent builder的模式不会使模块相互依赖。这只是写方法的另一种方式现在我更明白你的意思了,谢谢。我猜还有另一件事:
myObj.foo()。带音量(b)。带重量(a)。run()
——这里
a
b
被意外地交换了。有了正确的命名约定,你可以用肉眼看到它。使用普通的旧方法,如果执行
myObj.foo(w,v),它仍然“看起来”不错,而
myObj.foo().withVolume(w).withWeight(v).run()
不是是的,所以我需要一个工具来捕捉这种情况并添加更多语义。例如,IntelliJ IDEA有一些内部检查,试图(因为它们可能不那么可靠)覆盖显示警告的可疑调用。正如我所说,如果需要提供更多语义含义,那么在Java中创建另一个类几乎是唯一的方法。在这种情况下,注释几乎帮不上忙。告诉我,你将如何决定传入的整数是否是
@Volume
?如果你想用相同的注释来注释局部变量,那么你就没有办法处理局部变量注释了
MyClass myObj = ....;
int result = myObj.foo().withVolume(a).withWeight(b).run();
// which is the same as result = myObject.foo(a,b);