Ответ 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?
Я думаю, что в этом случае приложения будут по существу ограничены проверками времени компиляции, потому что такая аннотация будет либо локальной, либо для использования типа, и ни одна из них не доступна во время выполнения (или не реально):
- в соответствии с JLS аннотации локальных переменных не сохраняются в двоичном представлении
- аннотации по использованию типов записаны в файл класса, но все еще недоступны во время выполнения путем отражения (вам нужно будет самостоятельно разбирать файл класса!)
Итак, я могу думать об одном "специальном" использовании, но я даже не уверен, что это было бы очень полезно, поскольку есть, вероятно, другие способы сделать это: для некоторых определенных типов ресурсов, которые вы объявляете в 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)к югу >