当目标是属性时,@ Throws无效 [英] @Throws has no effect when the target is a property
问题描述
在查看此问题时,我注意到将@Throws
应用于get
或
While taking a look at this question, I noticed that applying @Throws
to a get
or set
use-site has no effect.
另外, @Throws
的唯一有效目标是AnnotationTarget.FUNCTION
,AnnotationTarget.PROPERTY_GETTER
,AnnotationTarget.PROPERTY_SETTER
和AnnotationTarget.CONSTRUCTOR
.
Additionally, the only valid targets for @Throws
are AnnotationTarget.FUNCTION
, AnnotationTarget.PROPERTY_GETTER
, AnnotationTarget.PROPERTY_SETTER
, and AnnotationTarget.CONSTRUCTOR
.
其他批注(例如JPA批注和Deprecated
)可以正常工作,并且已正确应用于该方法!
Other annotations, such as the JPA annotations and Deprecated
work fine and are properly applied to the method!
这是奇怪的行为.
为了演示,我用Java创建了一个简单的抽象类,其中包含一个构造函数,一个方法和一个get方法.
To demonstrate, I created a simple abstract class in Java, with one constructor, one method and one get method.
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
.
As you can see, every method/constructor is marked as throwing IOException
.
但是,当我尝试在Kotlin中编写一个等效类并用throws
标记用于互操作的适当方法时,生成的getString
和setString
方法没有throws
子句.
However, when I try to write an equivalent class in Kotlin, and mark the appropriate methods with throws
for interop, the generated getString
and setString
methods have no throws
clause.
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 {
}
}
在我看来,这是因为这些内部注释必须由编译器专门处理,而不是直接应用于该方法.
To me, it seems to be because these internal annotations must be handled specially by the compiler, instead of being applied directly to the method.
另外,将其应用于非抽象属性的getter:
Additionally, applying it to the getter of a non-abstract property:
val string: String
@Throws(IOException::class) get() = "Foo"
执行生成具有签名public final String getString() throws IOException
!
也许此案处理不当?
这是一个错误吗?
注意:这与方法是否实际抛出此异常无关.
Note: This doesn't have anything to do with whether the method actually throws this 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
子句.
Additionally, this shouldn't matter for abstract methods anyway, as they can't have an implementation and still can have a throws
clause.
如果我按照 @tynn 的建议提出并添加一个具体的实现,则:
If I do as @tynn suggests and add a concrete implementation:
class ConcreteClass : KotlinAbstractClass() {
override val string: String
get() = BufferedReader(FileReader("file.txt")).readText()
...
}
我仍然得到相同的结果.
I still get the same result.
推荐答案
我相信@tynn建议您执行以下操作:
I believe @tynn suggests you do the following:
override val string: String
@Throws(FileNotFoundException::class) get() = BufferedReader(FileReader("file.txt")).readText()
这应该为您提供签名中带有throws
的正确Java版本.我想原因是,如果您这样做:
This should give you the proper Java version with throws
in the signature. I guess the reasoning is that if you just do this:
@get:Throws(IOException::class)
val foo: String = "foo"
编译器非常聪明,可以看到getter中没有任何东西会抛出IOException
,因为您从未覆盖过它,因此不会产生throws
部分.覆盖getter时,编译器无法知道您提供的代码是否可以抛出,因此它服从注释并且始终输出throws
部分.
the compiler is smart enough to see that there's nothing in the getter that would throw an IOException
, since you've never overridden it, so it won't produce the throws
section. When the getter is overridden, the compiler has no way to know if the code you've supplied can throw, so it obeys the annotation and will always output the throws
part.
更新
以下内容似乎会生成正确的字节码:
The following seems to generate correct bytecode:
abstract class KotlinAbstractClass {
abstract var string: String
@Throws(IOException::class) get
@Throws(IOException::class) set
}
仔细研究一下,在这种情况下,我没有理由不使用@get:Throws(IOException::class)
.您可能会在YouTrack for Kotlin上提出问题,然后查看团队成员对此有何评论.
After taking a closer look at it, I see no reason for @get:Throws(IOException::class)
not to work in this case. You might file an issue on the YouTrack for Kotlin and see what the team members have to say about it.
这篇关于当目标是属性时,@ Throws无效的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!