Использование аннотации, чтобы гарантировать, что значение, возвращаемое методом, не отбрасывается

Строка в Java неизменяема. Следующий фрагмент, в широком смысле, «неправильный».

String s = "hello world!";

s.toUpperCase(); // "wrong"!!

System.out.println(s); // still "hello world!"!!!

Несмотря на то, что это «неправильный», код компилируется и запускается, что, возможно, приводит в замешательство многих новичков, которым нужно либо сказать, в чем ошибка, либо или чтобы выяснить это сами, обратившись к документации.

Чтение документации является важной частью понимания API, но мне интересно, можно ли это дополнить дополнительными проверками во время компиляции. В частности, мне интересно, можно ли использовать структуру аннотаций Java для обеспечения того, чтобы значение, возвращаемое некоторыми методами, не игнорировалось. Затем разработчики API / авторы библиотек будут использовать эту аннотацию в своих методах, чтобы задокументировать, какие возвращаемые значения не следует игнорировать.

После того, как API будет дополнен этой аннотацией (или, возможно, другим механизмом), тогда всякий раз, когда пользователь пишет код, например выше, он не будет компилироваться (или сделает это с серьезным предупреждением).

Так можно ли это сделать, и как бы вы сделали что-то подобное?


Приложение: Мотивация

Кажется очевидным, что в общем случае Java должна позволять игнорировать возвращаемые значения методов. Возвращаемые значения таких методов, как List.add ( always true ), System.setProperty (предыдущее значение), вероятно, можно безопасно игнорировать большую часть время.

Однако есть также много методов, возвращаемые значения которых НЕ следует игнорировать. Это почти всегда ошибка программиста или неправильное использование API. Сюда входят такие вещи, как:

  • Методы неизменяемых типов (например, String , BigInteger и т. Д.), Которые возвращают результат операций вместо изменения экземпляра. вызывается.
  • Методы, возвращаемое значение которых является важной частью его поведения и не должно игнорироваться, но иногда люди все равно это делают (например, InputStream.read (byte []) возвращает количество прочитанных байтов, которое должно быть НЕ , как полная длина массива)

В настоящее время мы можем писать коды, которые игнорируют эти возвращаемые значения и заставляют их компилироваться и запускаться без предупреждения. Средства проверки статического анализа / средства поиска ошибок / средства обеспечения соблюдения стилей и т. Д. Почти наверняка могут пометить их как возможные запахи кода, но было бы уместным / идеальным, если бы это могло быть реализовано самим API, возможно, с помощью аннотаций.

Это почти невозможно гарантировать, что класс всегда используется «правильно», но есть вещи, которые он может сделать, чтобы помочь клиентам правильно использовать (см .: Эффективное 2-е издание Java, Правило 58: Используйте проверенные исключения для восстанавливаемых условий и исключения времени выполнения для ошибок программирования и Элемент 62: Задокументируйте все исключения, создаваемые каждым методом ). Наличие аннотации, которая заставляла бы клиентов не игнорировать возвращаемые значения определенных методов, и ее принудительное выполнение компилятором во время компиляции либо в форме ошибок, либо в виде предупреждений, казалось бы, соответствует этой идее.


Приложение 2: Фрагмент

Ниже приводится предварительная попытка, кратко иллюстрирующая то, чего я хочу достичь:

@interface Undiscardable { }
//attachable to methods to indicate that its
//return value must not be discarded

public class UndiscardableTest {
     public static @Undiscardable int f() {
             return 42;
     }

     public static void main(String[] args) {
             f(); // what do I have to do so this generates
                  // compilation warning/error?

             System.out.println(f()); // this one would be fine!
     }
}

Приведенный выше код компилируется и работает нормально (, как показано на ideone.com ). Как я могу сделать это не так? Как я могу назначить семантику, которую я хочу @Undiscardable ?

28
задан polygenelubricants 1 September 2010 в 01:28
поделиться

2 ответа

В орехе: вы хотели бы иметь @Deprecated как аннотация, которая помогла бы компилятору/IDE предупредить/об ошибке, когда метод вызывается без присвоения его результата? Вы не можете добиться этого без изменения исходного кода Java и компилятора. Конкретный метод должен быть аннотирован, и компилятор должен знать о них. Не изменяя исходный код и/или компилятор, вы можете в лучшем случае создать тип плагина/настройки IDE, который распознает случаи и соответственно генерирует ошибку/предупреждение.


Обновление: вы можете написать вокруг него фреймворк/плагин, который соответственно проверяет вызываемый метод и ошибки. Вы хотели бы, чтобы аннотация была доступна только во время выполнения. Вы можете сделать это, аннотировав аннотацию с помощью @Retention (RetentionPolicy.RUNTIME) . Затем вы можете использовать Method#getAnnotation() , чтобы определить, доступна ли эта аннотация. Вот начальный пример того, как такая структура может выполнять эту работу:

package com.example;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

public class Test {

    public static void main(String[] args) throws Exception {
        if (Test.class.getMethod("f", new Class[0]).getAnnotation(Undiscardable.class) != null) {
            System.err.println("You should not discard the return value of f()!");
        } else {
            f();
        }

        System.out.println(f());
    }

    public static @Undiscardable int f() {
        return 42;
    }
}

@Retention(RetentionPolicy.RUNTIME)
@interface Undiscardable {}

Тем не менее, чтобы вместо этого заставить компилятор выполнять эту работу, вам нужно проделать немного больше работы.

2
ответ дан 28 November 2019 в 03:51
поделиться

Вам не нужно определять аннотацию. Вы можете определить правило при вызове метода:

  1. метод имеет возвращаемый тип void;
  2. результат метода используется в качестве аргумента для вызова другого метода; или
  3. результат метода присваивается переменной.

Вы можете реализовать процессор, который применяет это правило, или реализовать контрольный стиль, который применяет это правило.

1
ответ дан 28 November 2019 в 03:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: