Всегда использовать Final?

Я читал, что создание чего-то окончательного, а затем использование его в цикле повысит производительность, но подходит ли это для всего? У меня много мест, где нет цикла, но я добавляю final к локальным переменным. Это делает его медленнее или все еще хорошо?

Также есть места, где у меня есть финальная глобальная переменная (например, краска для Android), означает ли это, что мне не нужно делать ее локальной финальной при использовании в циклах?


person nebkat    schedule 26.07.2011    source источник


Ответы (9)


Первое, что вы должны учитывать, это; Каков самый простой и понятный способ написать этот код. Часто это хорошо работает.

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

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

person Peter Lawrey    schedule 26.07.2011
comment
Я бы добавил, что final для полей очень сильно отличается от final для локальных переменных. Создание поля final часто является абсолютной необходимостью для достижения корректности программы в параллельном программировании. - person Enno Shioji; 26.07.2011
comment
За исключением довольно тонкого условия передачи нового объекта в другой поток (я не видел примера этого сбоя), если поле, которое может быть final, но не является, оно будет вести себя так же. Если сделать его final, станет ясно, что с примитивом или ссылкой проблем с потокобезопасностью не будет, потому что их нельзя изменить. Примечание. Объект, на который делается ссылка, может измениться. - person Peter Lawrey; 26.07.2011
comment
Я просто оставлю ссылки на спецификации. конечная переменная: java.sun.com/docs /books/jls/ Third_edition/html/ окончательные поля:java.sun.com/docs/books/jls/ Third_edition/html/ tl;dr: первое полезно для документации, второе может заметно изменить поведение программы. - person Enno Shioji; 26.07.2011

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

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

person Enno Shioji    schedule 26.07.2011

По моему опыту, большинство переменных можно было бы объявить final.

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

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

person marc    schedule 26.07.2011

Считается хорошим тоном использовать final там, где это возможно (для полей и переменных, а не для классов и методов), хотя бы по той причине, что это упрощает тестирование. Финал никогда не окажет негативного влияния на производительность.

person Dmitri    schedule 26.07.2011

Вот мои 2 цента:

Используйте final для атрибутов, чтобы свести к минимуму изменчивость, и в целях документирования используйте final для локальных переменных, только если они используются во внутренних/анонимных классах.

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

person helpermethod    schedule 26.07.2011

Final для атрибутов не должен влиять на производительность. За исключением: в многопоточной среде, где несколько потоков обращаются к одному и тому же полю и «не знают», нужно ли им перезагружать его. Final на локальные переменные вообще не влияет, так как ничто, кроме локальной области, не может получить к ним доступ в любом случае. Final on методы могут повлиять на JIT-компиляцию. Если метод окончательный и маленький, компилятор может встроить его в циклы, так как понятно, что никто его не перезапишет. Обычно я вообще не использую final для атрибутов, так как final атрибуты не могут быть легко загружены из БД и т. д. Объявление параметров для методов final lokos уродливо (я все равно никогда не назначаю их внутри своего кода), но может предотвратить простые ошибки, возникающие из-за опечаток. . Однако, если вы начнете использовать собственные имена для ваших переменных, вы вряд ли сделаете такие опечатки.

person Angel O'Sphere    schedule 26.07.2011

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

В некоторых ситуациях было бы полезно изменить одну переменную на две, например. из этого

String a = "foo";
if (lol) a += "bar";

for(.. 1000 ...) doSomething(a);

to

final String a;
{
    String ma = "foo";
    if (lol) ma += "bar";
    a = ma;
}

for(.. 1000 ...) doSomething(a);

Отказ от ответственности: я не эксперт JIT.

person Bart van Heukelom    schedule 26.07.2011

Конечные переменные являются константами, поэтому компилятор может генерировать постоянное значение вместо инструкции ссылки на переменную. Конечно, это улучшит скорость (и, как правило, размер).

Также есть места, где у меня есть финальная глобальная переменная (например, краска для Android), означает ли это, что мне не нужно делать ее локальной финальной при использовании в циклах?

Извините, вы имеете в виду, что вам не нужно:

final int somefinalvalue = 0;

void amethod() {
  final int somefinalvalue = 0; // repeated from global one
}

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

person LeleDumbo    schedule 26.07.2011
comment
Думаю, он имеет в виду локальное кэширование полей. - person Bart van Heukelom; 26.07.2011
comment
В java они неизменны, но не постоянны, как если бы компилятор знал, какое значение он будет иметь. Компилятор просто запрещает присваивания. - person marc; 26.07.2011
comment
@Марк, вот почему я сказал, что компилятор может, а не будет. Если компилятор достаточно умен, с помощью некоторого анализа он может решить, оптимизировать ли его как константу или нет (возможно, только для простых значений, таких как целое число или с плавающей запятой). - person LeleDumbo; 26.07.2011
comment
Да, для примитивов это действительно было бы возможно, но только потому, что они являются значениями, поэтому 1 == 1 напротив new Object() == new Object(). - person marc; 26.07.2011
comment
Конечные переменные не являются константами в смысле константы С++. И компилятор не будет его оптимизировать. Если бы это было так, производные классы больше не могли бы читать это поле. Компилятор не должен быть таким умным, так как это должен сделать JIT-компилятор!! - person Angel O'Sphere; 26.07.2011
comment
@Angel O'Sphere: статические конечные поля (если их значение можно определить во время компиляции) скорее похожи на настоящие константы. Они не стираются, но if (CONSTANT_THAT_IS_FALSE) блоков удаляются компилятором. - person Bart van Heukelom; 26.07.2011
comment
Это правда, но статическое поле равно 4, компилятор не генерирует пару инструкций загрузки 4 и сравнения, а выполняет инструкцию загрузки статического поля. - person Angel O'Sphere; 26.07.2011
comment
@Angel O'Sphere: я должен был указать JIT, я действительно имею в виду, а не компилятор байт-кода. Спасибо, что разъяснили :) - person LeleDumbo; 27.07.2011

Я не думаю, что это должно быть вашей первой заботой, как упомянул @perter-lawrey. Во-первых, оптимизация компилятора может очень помочь; во-вторых, есть несколько инструментов, которые могут анализировать сгенерированные вами файлы классов и делать то же самое, например, ProGuard: сокращение Java, оптимизатор, обфускатор и преверификатор.

person Jerry Tian    schedule 26.07.2011