Look at this simple code.
try (@Foo Stream<@Bar Baz> foo = blabla) { }
We know that @Bar
is annotating Baz
, and @Foo
is annotating Stream
(I've written a similar example here, compile it online! ).
But what about this code?
void whatever(@Foo String[] args) { }
Here we have a String[]
annotated with @Foo
(whatever the annotation is, it's not important for this question).
My question is, is @Foo
annotated on String
or String[]
?
It's quite important to determine the target of the annotation, since sometimes we use annotations like @NotNull
to represent nullabilities of a type, and @NotNull List<String>
means a list which is never null is containing some possibly null strings; List<@NotNull String>
represents a list which is possibly null but the members are never null.
A possible use case: I need a @NotNull
to show args
is not null and another @NotNull
to show the members of args
are also not null? I need to annotate them both at the same time. If args
is a java.util.List
, I can use @NotNull List<@NotNull String>
. But args
is an array -- and I don't know how does the annotation affect on the type of args
.
Defining @NonNull
before the array level seems to do the trick (for the Checker Framework at least):
import org.checkerframework.checker.nullness.qual.NonNull;
class App {
void foo() {
String @NonNull [] bar;
bar = null; // NOK
bar = new String[1];
bar[0] = null; // NOK
}
}
Results in two errors (cf. live demo ):
| No. | Type | Description | Line | Column |
|-----|-------|-----------------------------------------------------------------------------|------|--------|
| 1 | error | Error: [assignment.type.incompatible] incompatible types in assignment. | 6 | 15 |
| | | found : null | | |
| | | required: @Initialized @NonNull String @UnknownInitialization @NonNull [] | | |
| 2 | error | Error: [assignment.type.incompatible] incompatible types in assignment. | 8 | 18 |
| | | found : null | | |
| | | required: @Initialized @NonNull String | | |
To answer your actual question, see the specification, §9.7.4 :
@C int @A [] @B [] f;
@A
applies to the array typeint[][]
,@B
applies to its component typeint[]
, and@C
applies to the element typeint
.
So @Foo String[] args
is actually annotating String
(read as: a possibly null array of non-null strings).
There are two possible answers to the question "in @Foo String[] args
, what is @Foo
annotating?".
If @Foo
is a type annotation (that is, the definition of Foo
is meta-annotated with @Target(ElementType.TYPE_USE)
), then @Foo
applies to the element type String
, and you have declared an array of @Foo String
.
If Foo
is a declaration annotation (its definition is not meta-annotated with @Target(ElementType.TYPE_USE)
), then @Foo
applies to the entire declaration String[] args
. This is uncommon for formal paremeters.
In that position, the @Foo
annotation cannot refer to the array type String[]
.
(The other response gives a useful answer for @NonNull
in particular, but doesn't answer the original question.)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.