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

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

问题描述

在查看此问题时,我注意到将@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.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

也许此案处理不当?

这是一个错误吗?

注意:这与方法是否实际抛出此异常无关.

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天全站免登陆