Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException
вообще.
См. также: A хороший список лучших практик
Я бы добавил, очень важно, хорошо использовать модификатор final
. Использование "окончательной" модификатор, когда это применимо в Java
Сводка:
final
для обеспечения хорошей инициализации. @NotNull
и @Nullable
if("knownObject".equals(unknownObject)
valueOf()
поверх toString (). StringUtils
StringUtils.isEmpty(null)
. IMO такая микрооптимизация не необходима, если Вы не работаете с некоторым экзотическим компилятором. Я поместил бы удобочитаемость на первое место.
Это зависело бы от компилятора, его конфигурации и окружающего кода.
Вы не должны пытаться предположить, 'быстрее' ли вещи, не проводя измерения.
В целом Вы не должны волноваться об этом виде наноразмерного материала оптимизации в наше время - это - почти всегда полная неуместность, и если бы Вы были по-настоящему рабочими в домене, где он имел значение, Вы уже использовали бы профилировщика и смотрели бы на вывод ассемблера компилятора.
Не важно. Современные процессоры могут выполнить целочисленную инструкцию MUL в одном такте или меньше, в отличие от более старых переработчиков, которые должны были выполнить ряд сдвигов и добавляют внутренне для выполнения MUL, таким образом, с помощью нескольких циклов. Я поставил бы это
MUL EAX,3
выполняется быстрее, чем
MOV EBX,EAX
SHL EAX,1
ADD EAX,EBX
Последний процессор, где этот вид оптимизации, возможно, был полезен, был, вероятно, 486. (да, это смещается к процессорам Intel, но вероятно представительное для другой архитектуры также).
В любом случае любой разумный компилятор должен смочь сгенерировать самый малочисленный/самый быстрый код. Поэтому всегда идите с удобочитаемостью сначала.
Поскольку легко измерить его самостоятельно, почему не делают этого? (Используя gcc
и time
от cygwin)
/* test1.c */
int main()
{
int result = 0;
int times = 1000000000;
while (--times)
result = result * 3;
return result;
}
machine:~$ gcc -O2 test1.c -o test1
machine:~$ time ./test1.exe
real 0m0.673s
user 0m0.608s
sys 0m0.000s
Сделайте тест для пару раз и повторитесь для другого случая.
Если Вы хотите посмотреть на ассемблерный код, gcc -S -O2 test1.c
Это действительно зависит от компилятора, который Вы на самом деле используете, но очень вероятно, они переводят в тот же код.
Можно проверить его собой путем создания маленькой тестовой программы и проверки ее дизассемблирования.
Не трудно узнать то, что компилятор делает с Вашим кодом (я использую DevStudio 2005 здесь). Запишите простую программу со следующим кодом:
int i = 45, j, k;
j = i * 3;
k = i + (i * 2);
Поместите точку останова в среднюю строку и выполните код с помощью отладчика. Когда точка останова инициирована, щелкните правой кнопкой по исходному файлу, и выбор "Переходят К Дизассемблированию". У Вас теперь будет окно с кодом, который выполняет ЦП. Вы заметите в этом случае, что последние две строки производят точно те же инструкции, а именно, "lea eax, [ebx+ebx*2]" (не разрядное смещение и добавление в данном случае). На современном ЦП IA32, вероятно, более эффективно сделать прямой MUL, а не бит, смещающийся из-за pipelineing природы ЦП, который подвергается штрафу при использовании измененного значения слишком скоро.
Это демонстрирует, какой aku говорит о, а именно, компиляторы достаточно умны для выбора лучших инструкций для кода.
Большинство компиляторов достаточно умно для разложения целочисленного умножения на серию сдвигов разряда, и добавляет. Я не знаю о компиляторах Windows, но по крайней мере с gcc можно заставить это выкладывать ассемблер, и если Вы смотрите на это, можно, вероятно, видеть идентичный ассемблер для обоих способов записать это.
Это не заботится. Я думаю, что существуют более важные вещи оптимизировать. Сколько времени Вы вложили капитал думающий и пишущий что вопрос вместо того, чтобы кодировать и протестировать собой?
:-)
Пока Вы используете достойный оптимизирующий компилятор, просто пишете код, это легко для компилятора понять. Это помогает компилятору выполнить умные оптимизации.
Вы задающий этот вопрос указываете, что оптимизирующий компилятор знает больше об оптимизации, чем Вы. Так доверяйте компилятору. Использовать n * 3
.
Взгляните на этот ответ также.
Компиляторы способны оптимизировать код такой как Ваш. Любой современный компилятор произвел бы тот же код для обоих случаев и дополнительно заменил бы * 2
сдвигом влево.
Доверяйте своему компилятору для оптимизации маленьких кусочков кода как этот. Удобочитаемость намного более важна на уровне кода. Истинная оптимизация должна произойти в более высокий уровень.