当目标是一个属性时@Throws 无效 [英] @Throws has no effect when the target is a property
问题描述
在查看 this question 时,我注意到将 @Throws
应用于get
或 set
use-site 无效.
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
!
does generate a method with the signature public final String getString() throws IOException
!
也许这个案子没有妥善处理?
Perhaps this case wasn't handled properly?
这是一个错误吗?
注意:这与该方法是否实际抛出此异常无关.
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屋!