Понимание чистого метода @Contract - PullRequest
1 голос
/ 31 мая 2019

Я недавно переключился с Eclipse на IntelliJ и был быстро представлен аннотациями @Contract, и мне сразу понравилась концепция, стоящая за этими аннотациями ( "найти проблемы в методах, которые вызывают аннотированные вами методы" ). Моей первой мыслью было использовать их для определения методов получения и утилит, и параметр аннотации pure, кажется, соответствует этому счету:

Атрибут pure предназначен для методов, которые не изменяют состояние своих объектов, а просто возвращают новое значение. Если его возвращаемое значение не используется, удаление его вызова не повлияет на состояние программы или не изменит семантику, если только вызов метода не вызывает исключение (исключение не считается побочным эффектом).

Однако меня смущает то, что на самом деле означает вышесказанное.

  • Указывают ли упомянутые объекты на объекты, передаваемые через параметры метода или поля класса? Более того, что можно квалифицировать как изменение , изменение ссылки на объект, содержимого или, возможно, и того и другого?

  • Нарушает ли контракт вызов методов, которые изменяют состояние этих объектов в чистом методе? Как методы конструктора, вызывающие конструкторы.

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

Ответы [ 2 ]

1 голос
/ 04 июня 2019

Указывают ли упомянутые объекты на объекты, переданные через параметры метода или поля класса?

И переданные объекты и поля экземпляра, к которому вызывается метод.

Более того, что можно квалифицировать как изменение, изменение ссылки на объект, контент или, возможно, и то и другое?

Оба.Любое изменение квалифицируется.

Нарушает ли контракт вызов методов, которые изменяют состояние этих объектов в чистом методе?

Да.Примесь заразна: вызов не чистого метода из другого метода также делает последний нечистым.

Важная часть заключается в следующем:

Если его возвращаемое значение не используется, удаление его вызова не повлияет на состояние программы или не изменит семантику, если только вызов метода не вызовет исключение (исключение не считается побочным эффектом.)

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

1 голос
/ 03 июня 2019

Пример может быть уточняющим. Рассмотрим следующий код:

class X {
  public void main(String[] ss) {
    ss[0].toUpperCase(java.util.Locale.ENGLISH);
  }
}

Вызов String.toUpperCase() не изменяет объект ss[0], к которому он вызывается, а также не изменяет предоставленный аргумент java.util.Locale.ENGLISH. Он возвращает новый объект, но этот объект не используется в коде. Вызов не изменяет состояние любых объектов, используемых в программе. Таким образом, удаление вызова не меняет поведение программы. (Строго говоря, он будет работать немного быстрее, но это не считается значимым изменением семантики.)

Обратите внимание, что когда метод main вызывается с пустым массивом, он вызывает исключение. Когда вызов удален, этого не произойдет. Но исключения не рассматриваются как побочные эффекты для аннотации @Contract. Исключения можно рассматривать как тип возвращаемого значения.

Таким образом, метод String.toUpperCase() можно аннотировать как чистый. Чистые методы обрабатываются специально во многих местах в IntelliJ IDEA. Например, если неиспользуемая переменная инициализируется чистым методом, быстрое исправление «знает», что при удалении переменной можно безопасно удалить инициализатор.

Геттеры обычно чистые, void методы обычно нет. Но есть исключения, например, junit.framework.Assert.fail() - это void, но pure, поскольку он не имеет побочных эффектов. Насколько я знаю, никаких официальных указаний нет.

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