@Throws在目标是属性时不起作用
在看这个问题的时候 ,我注意到将@Throws
应用到get
或set
use-site没有任何作用。
此外, @Throws
的唯一有效目标是AnnotationTarget.FUNCTION
, AnnotationTarget.PROPERTY_GETTER
, AnnotationTarget.PROPERTY_SETTER
和AnnotationTarget.CONSTRUCTOR
。
其他注释,如JPA批注和Deprecated
工作正常,并适用于该方法!
这是奇怪的行为。
为了演示,我用Java创建了一个简单的抽象类,有一个构造函数,一个方法和一个get方法。
public abstract class JavaAbstractClass { @Deprecated @NotNull public abstract String getString() throws IOException; public abstract void setString(@NotNull String string) throws IOException; public abstract void throwsFunction() throws IOException; public JavaAbstractClass() throws IOException { } }
正如你所看到的,每个方法/构造函数都被标记为抛出IOException
。
但是,当我尝试在Kotlin中编写一个等同的类,并用互斥标记相应的方法时,生成的getString
和setString
方法没有throws
子句。
abstract class KotlinAbstractClass @Throws(IOException::class) constructor() { @get:Deprecated("Deprecated") @get:Throws(IOException::class) @set:Throws(IOException::class) abstract var string: String @Throws(IOException::class) abstract fun throwsFunction() }
反编译的代码:
@Metadata(Some metadata here) public abstract class KotlinAbstractClass { /** @deprecated */ @Deprecated( message = "Deprecated" ) // @Deprecated made it through! @NotNull public abstract String getString(); // Nothing here! public abstract void setString(@NotNull String var1); // Nothing here! public abstract void throwsFunction() throws IOException; public KotlinAbstractClass() throws IOException { } }
对我来说,这似乎是因为这些内部注释必须由编译器专门处理,而不是直接应用于该方法。
此外,将其应用于非抽象属性的getter:
val string: String @Throws(IOException::class) get() = "Foo"
生成一个方法与签名public final String getString() throws IOException
!
也许这个案子处理不好?
这是一个错误?
注意:这与方法是否实际引发此exception没有任何关系。
如果我做:
@get:Throws(IOException::class) val string: String get() = BufferedReader(FileReader("file.txt")).readText()
编译的代码仍然是
@NotNull public final String getString() { return TextStreamsKt.readText((Reader)(new BufferedReader((Reader)(new FileReader("file.txt"))))); }
尽管FileReader
构造函数抛出FileNotFoundException
。
另外,对于抽象方法来说,这应该不是问题,因为它们不能实现,并且还可以有一个throws
子句。
如果我这样做@tynn建议并添加一个具体的实现:
class ConcreteClass : KotlinAbstractClass() { override val string: String get() = BufferedReader(FileReader("file.txt")).readText() ... }
我仍然得到相同的结果。
我相信@tynn建议你做以下几点:
override val string: String @Throws(FileNotFoundException::class) get() = BufferedReader(FileReader("file.txt")).readText()
这应该给你签名中的适当的Java版本。 我猜的原因是,如果你只是这样做:
@get:Throws(IOException::class) val foo: String = "foo"
编译器足够聪明,可以看到getter中没有任何东西会抛出IOException
,因为你从来没有重写它,所以它不会产生throws
部分。 当getter被覆盖时,编译器无法知道你提供的代码是否可以抛出,所以它遵从注释,并总是输出throws
部分。
UPDATE
以下似乎生成正确的字节码:
abstract class KotlinAbstractClass { abstract var string: String @Throws(IOException::class) get @Throws(IOException::class) set }
仔细看后,我发现@get:Throws(IOException::class)
没有理由@get:Throws(IOException::class)
在这种情况下不起作用。 您可能会针对Kotlin的YouTrack提出问题,并查看团队成员对此有何评论。