Подтвердить что ты не робот

Аннотации по переменным, объявленным в try-with-resources?

Просто интересно, какие аннотации можно использовать с переменными, объявленными в операторах try-with-resources, что разрешено в соответствии с его грамматикой. В разделе 14.20.3 из спецификации языка (Java 7) читается

TryWithResourcesStatement:
    try Условные блоки выделения ресурсов opt Наконец opt

ResourceSpecification:
    ( Ресурсы ; opt)

Ресурсы:
    Ресурс ресурсов ; Ресурсы

Ресурс:
    VariableModifiers opt Тип VariableDeclaratorId = Выражение

И VariableModifiers расширяется как (раздел 14.4),

VariableModifiers:
    VariableModifier
    VariableModifiers VariableModifier

VariableModifier: один из
    Аннотация final

Здесь вы: VariableModifier может иметь аннотацию. Ну, это в основном означает, что мы можем написать что-то вроде этого:

try( @SomeAnnotation SomeType obj = createSomeType() ) { 
  //some code
}

Итак, мой вопрос: как и какие аннотации могут быть использованы в try-with-resources и для достижения какого поведения? Любая инновационная идея? Кто-нибудь их использовал?

4b9b3361

Ответ 1

Не в Java 7, но я подозреваю, что вы отметили этот java-7 только потому, что версия, в которую вводились try-with-resources, и вы по-прежнему заинтересованы в возможностях использования за пределами Java 7 (я думаю, этот вопрос очень интересен для Java >= 8).

Я думаю, что нет ничего особенного, связывающего try-with-resources и аннотации, это не особый случай в грамматике; в этом отношении такие переменные (объявленные в заявлении try-with-resources) аналогичны другим локальным переменным, и грамматика также позволяет аннотации:

  • В Java 7 появились инструкции try-with-resources, в которых вы можете объявить переменную, которая получит специальную обработку.
  • Грамматика позволяет добавлять аннотации к объявлениям локальных переменных уже в Java 5, когда были добавлены аннотации (но нам пришлось ждать Java 6, чтобы получить полезный API для обработки аннотаций).
  • Но даже с Java 7 было невозможно для обработчиков аннотаций обращаться к аннотации локальных переменных. Единственной аннотацией к локальной переменной, которая была "полезной", была @SuppressWarnings, но она была обработана специально самим компилятором, и вы не могли в нее влезть.
  • В Java 8 появился новый вид аннотационного контекста помимо контекста объявления, теперь существует "контекст типа", и теперь аннотация Target может быть ElementType.TYPE_USE

Таким образом, ответ (с Java 8) совпадает с любой аннотацией по локальным переменным.


(некоторые пустяки по поводу новых аннотаций типа Java 8)

... и это становится интересным: аннотировать любой тип использования!

Синтаксические местоположения, в которых могут появляться аннотации, разбиваются на контексты деклараций, где аннотации применяются к объявлениям, и типа, где аннотации применяются к типам, используемым в объявлениях и выражениях.

Такие аннотации не сохраняются во время выполнения, но могут использоваться во время компиляции для различных "проверок". См. checker framework, которая построена поверх работы, выполненной для JSR-308 (тот же автор, если я правильно понимаю).

Очень быстро, потому что это весело, теперь мы можем это сделать:

@NonNull Object @Nullable [] array; // Nullable array of non-null objects
@Nullable Object @NonNull [] array; // Non-null array of nullable objects

@Foo List<@Foo Integer> doSomething(@Foo Integer @Foo [] arrayOfIntegers, @Foo long x) {
    arrayOfIntegers[0] = (@Foo int) x;
    return Arrays.asList(arrayOfIntegers);
}

Примеры таких "аннотаций типа" :

Checker Framework предоставляет несколько аннотаций типов, которые могут принести пользу как разработчикам библиотек, так и разработчикам приложений, например:
@NonNull - Компилятор может определить случаи, когда путь кода может принимать нулевое значение, без необходимости отлаживать исключение NullPointerException.
@ReadOnly - компилятор отметит любую попытку изменения объекта. Это похоже на Collections.unmodifiableList, но более общее и проверенное во время компиляции.
@Regex - Обеспечивает проверку времени компиляции, которую String, предназначенная для использования в качестве обычного выражения, является правильным форматированным регулярным выражением.
@Tainted и @Untainted - типы идентификаторов данных, которые не должны использоваться вместе, например, удаленный пользовательский ввод, используемый в системных командах, или конфиденциальная информация в журнальных потоках.
@m - Единицы измерения гарантируют, что числа, используемые для измерения объектов, используются и сравниваются правильно или прошли надлежащее преобразование единиц измерения.

Но ни один из тех, которые особенно полезны в контексте инструкции try-with-resources (я имею в виду, не больше или меньше, чем где-либо еще).


Вернуться к вопросу: используются для аннотаций локальных переменных, которые были бы особенно интересны при объявлении в заявлении try-with-resources?

Я думаю, что в этом случае приложения будут по существу ограничены проверками времени компиляции, потому что такая аннотация будет либо локальной, либо для использования типа, и ни одна из них не доступна во время выполнения (или не реально):

Итак, я могу думать об одном "специальном" использовании, но я даже не уверен, что это было бы очень полезно, поскольку есть, вероятно, другие способы сделать это: для некоторых определенных типов ресурсов, которые вы объявляете в try- с-ресурсами, вам может потребоваться убедиться, что ресурс полностью уничтожен до того, как он закрыт (я видел что-то подобное с клиентской библиотекой HTTP и частью API, который читает заголовки, - не может запомнить детали).

/* Say getResponse() taps into a third-party library that has a quirk:
 * a response object must be consumed entirely before being closed. */
try(@MustConsumeEntirely Stream<String> lines = getResponse()) {
    lines.findFirst().ifPresent(System.out::println);
    /* The stream is not entirely consumed (unless it is only 1 line but there is no way to tell).
     * A smart checker could catch this and issue a warning. */
}

В этой аннотации была бы целевая ElementType.LOCAL_VARIABLE (поэтому не требовались бы новые типы аннотаций Java 8, но требовалось бы обрабатывать java 8), и контролер должен, вероятно, убедиться, что переменная эффективно объявлена ​​в try- (компилятор не может запретить использовать его для любой локальной переменной), а затем проанализировать исходное дерево, чтобы определить, потребляются ли ресурсы по мере необходимости.
Вероятно, было бы невозможно реализовать такую ​​проверку в 100% правильном виде, но на бумаге можно проверить некоторые известные плохие шаблоны, и это будет в основном иметь смысл, когда целевая переменная объявляется в try-with- ресурса.

Другая идея (по-прежнему используется в переменных и не в типе), также очень низкая полезность: @MustNotEscape, если вы хотите контролировать, что переменная не передается другому методу, потому что (по причинам, аналогичным приведенным выше) вы хотите, чтобы способность контролировать все, что происходит с объектом (например, как в предыдущей идее), и это будет сложнее выполнить, если переменная передается.

Чтобы проиллюстрировать, что такая вещь смутно возможна, вот пример рамки, которая ожидает, что вы будете следовать своим "встроенным DSL" внутри определенный блок и не удается, если вы этого не сделаете. Можно представить аннотацию, чтобы помочь проверить соответствие с аналогичными ограничениями, наложенными гипотетической структурой на ресурсе в блоке try-with-resources.
Не сказать, что это был бы хороший дизайн, хотя... (Я в случае с ModelMapper, DSL был всего лишь хитроумным трюком, который они придумали перед java 8, и теперь у них лучшие и безопасные решения с lambdas)к югу >

Ответ 2

Единственный вид аннотаций, которые вы можете применить к локальной переменной (включая назначение переменной в try блока try-with-resources), - это те, у которых есть @Target({ElementType.LOCAL_VARIABLE}). И они недоступны во время выполнения (через отражение), поэтому они могут быть доступны только компилятору.

Примеры, когда они могут быть полезны:

  • @SuppressWarnings("unchecked") - если у вас есть unchecked присваивание в try(...)
  • Использование JSR 305 (аннотации для обнаружения дефектов программного обеспечения), например @Nullable, @Nonnull