java - 当目标是属性时,@Throws 无效

标签 java annotations jvm kotlin throws

一边看this question ,我注意到将 @Throws 应用于 getset 使用站点没有任何效果。

此外,@Throws唯一有效目标AnnotationTarget.FUNCTIONAnnotationTarget.PROPERTY_GETTERAnnotationTarget.PROPERTY_SETTERAnnotationTarget.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 中编写等效类,并使用 throws 标记适当的方法进行互操作时,生成的 getStringsetString 方法没有 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!

也许这个案子没有得到妥善处理?

这是一个错误吗?


注意:这与该方法是否真正抛出此异常没有任何关系。

如果我这样做:

@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 constructor抛出 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()

这应该为您提供在签名中带有 throws 的正确 Java 版本。我想原因是如果你这样做:

@get:Throws(IOException::class)
val foo: String = "foo"

编译器足够聪明,可以看到 getter 中没有任何东西会抛出 IOException,因为您从未覆盖它,所以它不会产生 throws部分。当 getter 被覆盖时,编译器无法知道您提供的代码是否可以抛出异常,因此它会遵守注释并始终输出 throws 部分。

更新

以下似乎生成了正确的字节码:

abstract class KotlinAbstractClass {

    abstract var string: String
        @Throws(IOException::class) get
        @Throws(IOException::class) set
}

在仔细研究之后,我认为 @get:Throws(IOException::class) 没有理由在这种情况下不起作用。您可以在 YouTrack for Kotlin 上提交问题,看看团队成员对此有何评论。

关于java - 当目标是属性时,@Throws 无效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47737623/

相关文章:

java - System.getProperty ("key") 从哪里(哪个属性文件)读取?

java - JAXB 将循环引用映射到 XML

java - 尝试使用 ical4j 解析 ical 文件,说明属性后出现换行问题

iphone - 隐藏 map 注释而不删除它们

java - 非空注释和标准 java 包

Java方法扩展而不是覆盖

java - Spring-JPA 和 Spring-Data-JPA 之间的区别

java - Spring REST 向客户端抛出异常

java - 有什么方法可以知道执行字节代码时 JVM 的速度吗?

设置 Xms Xmx 时,Java Heap Space 不会增加,