英文:
What is the difference between the approachs of annotation on nested class type parameter?
问题
org.jetbrains.annotations.NotNull
public static void func(Foo.Bar.@NotNull Baz arg0) {
}
public static void func(@NotNull Foo.Bar.Baz arg0) {
}
public static void func(@NotNull Foo.Bar.@NotNull Baz arg0) {
}
对于嵌套类类型参数的注解方法有什么区别?
哪种方法是推荐的?
英文:
org.jetbrains.annotations.NotNull
public static void func(Foo.Bar.@NotNull Baz arg0) {
}
public static void func(@NotNull Foo.Bar.Baz arg0) {
}
public static void func(@NotNull Foo.Bar.@NotNull Baz arg0) {
}
What is the difference between the approachs of annotation on nested class type parameter?
Which one is recommanded?
答案1
得分: 2
这些只是在语法上有所不同。从语义上讲,它们都表示“此参数不应为null”,实际上,这三种方式都会编译为对参数的相同空值检查。
之所以这三种方式都有效,是因为 NotNull
具有 ElementType.TYPE_USE
的元素类型,所以你可以使用 NotNull
注释任何“类型使用”。在 Foo.Bar
中的 Bar
是类型 Bar
的使用,因此你可以通过 Foo.@NotNull Bar
进行注释。
这引出了一个问题,为什么 NotNull
首先具有 ElementType.TYPE_USE
。显然不是为了让你有三种表达完全相同的方式。更可能的原因是允许你这样做:
List<@NotNull String> listWithNotNullElements;
无论如何,这三种方式都会编译为相同的字节码,因为在这三种情况下,NotNull
注释的是 参数。
以下这三种情况:
package io.github.sweeper777;
import org.jetbrains.annotations.NotNull;
public class Main {
public static void main(String[] args) {
}
public void f( Foo.@NotNull Bar x) {
}
}
class Foo {
static class Bar {
}
}
package io.github.sweeper777;
import org.jetbrains.annotations.NotNull;
public class Main {
public static void main(String[] args) {
}
public void f(@NotNull Foo.@NotNull Bar x) {
}
}
class Foo {
static class Bar {
}
}
package io.github.sweeper777;
import org.jetbrains.annotations.NotNull;
public class Main {
public static void main(String[] args) {
}
public void f(@NotNull Foo.Bar x) {
}
}
class Foo {
static class Bar {
}
}
编译为:
Compiled from "Main.java"
public class io.github.sweeper777.Main {
public io.github.sweeper777.Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: return
public void f(io.github.sweeper777.Foo$Bar);
Code:
0: aload_1
1: ifnonnull 8
4: iconst_0
5: invokestatic #36 // Method $$$reportNull$$$0:(I)V
8: return
private static void $$$reportNull$$$0(int);
Code:
0: ldc #38 // String Argument for @NotNull parameter '%s' of %s.%s must not be null
2: iconst_3
3: anewarray #2 // class java/lang/Object
6: dup
7: iconst_0
8: ldc #39 // String x
10: aastore
11: dup
12: iconst_1
13: ldc #40 // String io/github/sweeper777/Main
15: aastore
16: dup
17: iconst_2
18: ldc #41 // String f
20: aastore
21: invokestatic #47 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
24: new #49 // class java/lang/IllegalArgumentException
27: dup_x1
28: swap
29: invokespecial #52 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
32: athrow
}
英文:
These are only syntactically different. Semantically, they all mean "this parameter should not be null", and practically, all three compiles to the same null check on the parameter.
The reason why all three works is because NotNull
has the ElementType
of TYPE_USE
, so you can annotate any "type use" with NotNull
. Well, the Bar
in Foo.Bar
is a use of the type Bar
, so you can annotate that by doing Foo.@NotNull Bar
.
This raises the question of why does NotNull
have ElementType.TYPE_USE
in the first place. It certainly is not to allow you to have 3 ways of saying the exact same thing. A more likely reason is to allow you to do this:
List<@NotNull String> listWithNotNullElements;
Anyway, all three of these compile to the same byte code, as in all 3 cases, NotNull
is annotating the parameter.
All three of the following:
package io.github.sweeper777;
import org.jetbrains.annotations.NotNull;
public class Main {
public static void main(String[] args) {
}
public void f( Foo.@NotNull Bar x) {
}
}
class Foo {
static class Bar {
}
}
package io.github.sweeper777;
import org.jetbrains.annotations.NotNull;
public class Main {
public static void main(String[] args) {
}
public void f(@NotNull Foo.@NotNull Bar x) {
}
}
class Foo {
static class Bar {
}
}
package io.github.sweeper777;
import org.jetbrains.annotations.NotNull;
public class Main {
public static void main(String[] args) {
}
public void f(@NotNull Foo.Bar x) {
}
}
class Foo {
static class Bar {
}
}
Compiles to:
Compiled from "Main.java"
public class io.github.sweeper777.Main {
public io.github.sweeper777.Main();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: return
public void f(io.github.sweeper777.Foo$Bar);
Code:
0: aload_1
1: ifnonnull 8
4: iconst_0
5: invokestatic #36 // Method $$$reportNull$$$0:(I)V
8: return
private static void $$$reportNull$$$0(int);
Code:
0: ldc #38 // String Argument for @NotNull parameter \'%s\' of %s.%s must not be null
2: iconst_3
3: anewarray #2 // class java/lang/Object
6: dup
7: iconst_0
8: ldc #39 // String x
10: aastore
11: dup
12: iconst_1
13: ldc #40 // String io/github/sweeper777/Main
15: aastore
16: dup
17: iconst_2
18: ldc #41 // String f
20: aastore
21: invokestatic #47 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
24: new #49 // class java/lang/IllegalArgumentException
27: dup_x1
28: swap
29: invokespecial #52 // Method java/lang/IllegalArgumentException."<init>":(Ljava/lang/String;)V
32: athrow
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论