String
в Java неизменен. Следующий фрагмент, вообще говоря, "неправильный".
String s = "hello world!";
s.toUpperCase(); // "wrong"!!
System.out.println(s); // still "hello world!"!!!
Несмотря на то, что это "неправильно", код компилируется и запускается, возможно, в замешательство многих новичков, которым нужно либо сказать, что это за ошибка, либо узнать сами, обратившись к документации.
Чтение документации является неотъемлемой частью понимания API, но мне интересно, можно ли это дополнять дополнительными проверками времени компиляции. В частности, мне интересно, можно ли использовать Java-аннотацию для обеспечения того, чтобы значение, возвращаемое некоторыми методами, не игнорировалось. Дизайнеры API/авторы библиотек затем использовали бы эту аннотацию в своих методах для документирования того, какие возвращаемые значения не следует игнорировать.
Как только API будет дополнен этой аннотацией (или, возможно, другим механизмом), тогда всякий раз, когда пользователь пишет код, такой как выше, он не будет компилироваться (или делать это с кормовым предупреждением).
Так можно ли это сделать, и как бы вы сделали что-то подобное?
Приложение: Мотивация
Кажется очевидным, что в общем случае Java должна позволять игнорировать возвращаемые значения методов. Возвращаемые значения методов, таких как List.add
(всегда true
), System.setProperty
(предыдущее значение), можно, вероятно, безопасно игнорировать большую часть времени.
Однако есть также много методов, возвращаемые значения которых НЕ должны игнорироваться. Это почти всегда является ошибкой программиста или, в противном случае, неправильным использованием API. К ним относятся такие вещи, как:
- Способы неизменяемых типов (например,
String
,BigInteger
и т.д.), которые возвращают результат операций вместо того, чтобы мутировать экземпляр, на который он вызывается. - Методы, возвращающее значение которых является критичной частью его поведения и не должно игнорироваться, но люди иногда делают это (например,
InputStream.read(byte[])
возвращает количество прочитанных байтов, которое НЕ следует считать всей длиной массива)
В настоящее время мы можем писать коды, которые игнорируют эти возвращаемые значения и компилируются и запускаются без предупреждения. Статические аналитические проверки/искатели ошибок/стилисты/и т.д. Могут почти наверняка отмечать их как возможные запахи кода, но, похоже, это будет подходящим/идеальным, если это может быть реализовано самим API, возможно, через аннотации.
Для класса почти невозможно гарантировать, что он всегда используется "правильно", но есть вещи, которые он может сделать, чтобы помочь правильному использованию клиентов (см.: Эффективное Java 2nd Edition, пункт 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
?