Эта аннотация на массиве или типе элемента - массив? - PullRequest
0 голосов
/ 10 мая 2018

Посмотрите на этот простой код.

try (@Foo Stream<@Bar Baz> foo = blabla) { }

Мы знаем, что @Bar аннотирует Baz, а @Foo аннотирует Stream (я написал похожий пример здесь, скомпилируйте его онлайн! ).

А как насчет этого кода?

void whatever(@Foo String[] args) { }

Здесь у нас есть String[] с аннотацией @Foo (какой бы ни была аннотация, это не важно для этого вопроса).

У меня вопрос, это @Foo с комментариями String или String[]?

Очень важно определить цель аннотации, поскольку иногда мы используем аннотации, такие как @NotNull, для представления допустимых значений типа, а @NotNull List<String> означает, что список, который никогда не является нулевым, содержит некоторые возможные нулевые строки; List<@NotNull String> представляет список, который может быть нулевым, но члены никогда не равны нулю.

Возможный вариант использования: мне нужно, чтобы @NotNull показывал, что args не равно нулю, а другой @NotNull, чтобы показать, что члены args также не равны нулю? Мне нужно аннотировать их обоих одновременно. Если args это java.util.List, я могу использовать @NotNull List<@NotNull String>. Но args - это массив - и я не знаю, как аннотация влияет на тип args.

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

Существует два возможных ответа на вопрос «в @Foo String[] args, что такое @Foo аннотирование?».

  • Если @Foo является аннотацией типа (то есть определение Foo мета-аннотировано @Target(ElementType.TYPE_USE)), затем @Foo применяется к типу элемента String, и вы объявили массив @Foo String.

  • Если Foo является аннотацией объявления (его определение не мета-аннотировано с @Target(ElementType.TYPE_USE)), то @Foo применяется ко всей декларации String[] args.Это необычно для формальных параметров.

В этой позиции аннотация @Foo не может ссылаться на тип массива String[].

(Другой ответ даетв частности, полезный ответ для @NonNull, но не отвечает на первоначальный вопрос.)

0 голосов
/ 10 мая 2018

Определение @NonNull до того, как уровень массива, кажется, сделает свое дело (по крайней мере, для Checker Framework):

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
    }
}

Результаты с двумя ошибками (ср. 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                                    |      |        |

Чтобы ответить на ваш актуальный вопрос, см. Спецификацию , §9.7.4 :

@C int @A [] @B [] f;

@A применяется к типу массива int[][], @B применяется к типу его компонента int[] и @C относятся к элементу типа int.

Так что @Foo String[] args на самом деле аннотирует String (читается как: возможно нулевой массив ненулевых строк).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...