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

Все финал

Я использую PMD, чтобы помочь выявить потенциальные проблемы в моем Java-коде, и я нашел, что его совет разделяется на полезные, идиосинкразивные и "WTF?!".

Одна из вещей, которые он продолжает говорить мне, - это использовать ключевое слово final для буквально каждой переменной, к которой я могу подключить ее, включая входные параметры. Для реальных констант это кажется разумным, но для других вещей это просто поражает меня как нечетное, возможно даже немного контрпродуктивное.

Существуют ли конкретные преимущества/недостатки для подвешивания final для каждого объявления переменных, которое вы, возможно, можете?

4b9b3361

Ответ 1

"Каждое объявление переменной, которое вы, возможно," звучит немного экстремально ", но final действительно полезно во многих отношениях. Иногда мне хочется, чтобы final был по умолчанию, и не требовал никакого ключевого слова, но для истинных" переменных" требовался модификатор variable. Scala принял что-то вроде этого подхода с его ключевыми словами val и var; использование val (ключевое слово final) настоятельно рекомендуется.

Особенно важно внимательно рассмотреть, есть ли каждая переменная-член final, volatile или ни то, ни другое, поскольку безопасность потока класса зависит от того, как это правильно. Значения, назначенные переменным final и volatile, всегда отображаются в других потоках без использования блока synchronized.

Для локальных переменных это не так важно, но использование final может помочь вам более четко определить ваш код и избежать некоторых ошибок. Если вы не ожидаете изменения значения в методе, скажем так с final, и пусть компилятор обнаружит незаметные нарушения этого ожидания. В настоящее время я не знаю, что делать, но легко понять, что компилятор JIT может использовать этот намек для повышения производительности.

На практике я не объявляю локальные переменные final всякий раз, когда мог. Мне не нравится визуальный беспорядок, и он кажется громоздким. Но это не значит, что я не должен что-то делать.

Было добавлено предложение добавить ключевое слово var к Java, предназначенное для поддержки вывода типа. Но в рамках этого предложения было высказано несколько предложений относительно дополнительных способов указания локальной неизменяемости переменных переменных. Например, одним предложением было также добавить ключевое слово val для объявления неизменяемой переменной с предполагаемым типом. В качестве альтернативы, некоторые сторонники используют final и var вместе.

Ответ 2

final сообщает читателю, что значение или ссылка, назначенные первой, одинаковы в любое время позже.

Поскольку все, что МОЖЕТ быть окончательным, окончательно в этом сценарии, недостающий финал говорит читателю, что значение изменится позже и учтет это.

Ответ 3

Это обычная идиома для таких инструментов, как PMD. Например, ниже приведены соответствующие правила в Checkstyle. Это действительно вопрос стиля/предпочтения, и вы можете спорить для обеих сторон.

По-моему, использование final для параметров метода и локальных переменных (если применимо) является хорошим стилем. "Дизайн для расширения" идиома спорна.

Ответ 4

PMD также имеет правила опций, которые вы можете включить, которые жалуются на final; это произвольное правило.

Если я делаю проект, в котором API экспортируется в другую команду - или в мир - оставьте правило PMD в его нынешнем виде. Если вы просто разрабатываете что-то, что будет навсегда и всегда будет закрытым API, отключите правило и сэкономьте некоторое время.

Ответ 5

Вот некоторые причины, по которым может быть полезно иметь почти все тегированные как final

Конечные константы

 public static class CircleToolsBetter {
     public final static double PI = 3.141;
        public double getCircleArea(final double radius) {
          return (Math.pow(radius, 2) * PI);
        }
    }

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

Конечные переменные

public static String someMethod(final String environmentKey) {
    final String key = "env." + environmentKey;
    System.out.println("Key is: " + key);
    return (System.getProperty(key));

  }

}

В этом классе вы создаете конечную переменную с областью действия, которая добавляет префикс к параметру environmentKey. В этом случае конечная переменная является окончательной только в пределах области выполнения, которая отличается при каждом выполнении метода. Каждый раз, когда вводится метод, окончательный реконструируется. Как только он будет создан, он не может быть изменен во время выполнения метода. Это позволяет фиксировать переменную в методе на время действия метода. см. ниже:

public class FinalVariables {


  public final static void main(final String[] args) {
    System.out.println("Note how the key variable is changed.");
    someMethod("JAVA_HOME");
    someMethod("ANT_HOME");
  }
}

Конечные константы

public double equation2Better(final double inputValue) {
    final double K = 1.414;
    final double X = 45.0;

double result = (((Math.pow(inputValue, 3.0d) * K) + X) * M);
double powInputValue = 0;         
if (result > 360) {
  powInputValue = X * Math.sin(result); 
} else {
  inputValue = K * Math.sin(result);   // <= Compiler error   
}

Это особенно полезно, когда у вас действительно длинные строки кодов, и он будет генерировать ошибку компилятора, чтобы вы не запустили логическую/бизнес-ошибку, когда кто-то случайно меняет переменные, которые не следует изменять.

Окончательные коллекции

В другом случае, когда мы говорим о коллекциях, вам нужно установить их как не подлежащие регистрации.

 public final static Set VALID_COLORS; 
    static {
      Set temp = new HashSet( );
      temp.add(Color.red);
      temp.add(Color.orange);
      temp.add(Color.yellow);
      temp.add(Color.green);
      temp.add(Color.blue);
      temp.add(Color.decode("#4B0082")); // indigo
      temp.add(Color.decode("#8A2BE2")); // violet
      VALID_COLORS = Collections.unmodifiableSet(temp);
    }

в противном случае, если вы не устанавливаете его как не подлежащее изменению:

Set colors = Rainbow.VALID_COLORS;
colors.add(Color.black); // <= logic error but allowed by compiler

Окончательные классы и Окончательные методы не могут быть расширены или перезаписаны соответственно.

РЕДАКТИРОВАТЬ: ДЛЯ АДРЕСА ЗАДАЧИ ОКОНЧАТЕЛЬНОГО КЛАССА В ОТНОШЕНИИ ЭНЕРГИИ:

Есть два способа сделать окончательный класс. Во-первых, использовать ключевое слово final в объявлении класса:

public final class SomeClass {
  //  . . . Class contents
}

Второй способ сделать окончательный класс - объявить все его конструкторы как частные:

public class SomeClass {
  public final static SOME_INSTANCE = new SomeClass(5);
  private SomeClass(final int value) {
  }

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

public class Test{
  private Test(Class beanClass, Class stopClass, int flags)
    throws Exception{
    //  . . . snip . . . 
  }
}

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

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