当目标是一个属性时@Throws 无效 [英] @Throws has no effect when the target is a property

查看:33
本文介绍了当目标是一个属性时@Throws 无效的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在查看 this question 时,我注意到将 @Throws 应用于getset 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.FUNCTIONAnnotationTarget.PROPERTY_GETTERAnnotationTarget.PROPERTY_SETTERAnnotationTarget.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 标记适当的方法以进行互操作时,生成的 getStringsetString 方法没有 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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆