Многие объяснения уже присутствуют, чтобы объяснить, как это происходит и как это исправить, но вы также должны следовать рекомендациям, чтобы избежать NullPointerException
вообще.
См. также: A хороший список лучших практик
Я бы добавил, очень важно, хорошо использовать модификатор final
. Использование "окончательной" модификатор, когда это применимо в Java
Сводка:
final
для обеспечения хорошей инициализации. @NotNull
и @Nullable
if("knownObject".equals(unknownObject)
valueOf()
поверх toString (). StringUtils
StringUtils.isEmpty(null)
. volatile
необходим, если Вы читаете из места в памяти, в которую, скажем, может записать абсолютно отдельный process/device/whatever.
я раньше работал с двухпортовым поршнем в многопроцессорной системе в прямом C. Мы использовали аппаратные средства, управляемые 16 битовых значений как семафор для знания, когда другой парень был сделан. По существу мы сделали это:
void waitForSemaphore()
{
volatile uint16_t* semPtr = WELL_KNOWN_SEM_ADDR;/*well known address to my semaphore*/
while ((*semPtr) != IS_OK_FOR_ME_TO_PROCEED);
}
Без volatile
, оптимизатор рассматривает цикл как бесполезный (Парень никогда не устанавливает значение! Он гаек, избавьтесь от того кода!) и мой код продолжился бы не получив семафор, вызвав проблемы позже.
Около того, что энергозависимое ключевое слово используется для сообщения компилятора не оптимизировать доступ к некоторой переменной (который может быть изменен потоком или процедурой прерывания), это может быть также , раньше удалял некоторые ошибки компилятора - ДА это может быть ---.
, Например, я работал над встроенной платформой, был компилятор, делал некоторый неправильный assuptions относительно значения переменной. Если бы код не был оптимизирован, то программа работала бы хорошо. С оптимизацией (которые были действительно необходимы, потому что это была критическая стандартная программа) код не будет работать правильно. Единственное решение (хотя не очень корректный) состояло в том, чтобы объявить 'дефектную' переменную как энергозависимую.
Я использовал его в сборках отладки, когда компилятор настаивает на том, чтобы оптимизировать далеко переменную, которую я хочу смочь видеть, когда я ступаю через код.
Помимо использования его, как предназначено, энергозависимый используется в (шаблоне) метапрограммирование. Это может использоваться для предотвращения случайной перегрузки, поскольку энергозависимый атрибут (как константа) принимает участие в разрешении перегрузки.
template <typename T>
class Foo {
std::enable_if_t<sizeof(T)==4, void> f(T& t)
{ std::cout << 1 << t; }
void f(T volatile& t)
{ std::cout << 2 << const_cast<T&>(t); }
void bar() { T t; f(t); }
};
Это законно; обе перегрузки являются потенциально вызываемыми и делают почти то же. Бросок в volatile
перегрузка законна, поскольку мы знаем, что панель не передаст энергонезависимое T
так или иначе. volatile
версия строго хуже, тем не менее, поэтому никогда не выбираемая в разрешении перегрузки, если энергонезависимое f
доступно.
Примечание, что код никогда на самом деле зависит от volatile
доступ к памяти.
Крупное приложение, что я раньше продолжал работать в начале 1990-х, содержало обработку исключений на базе С с помощью setjmp и longjmp. Энергозависимое ключевое слово было необходимо на переменных, значения которых должны были быть сохранены в блоке кода, который служил пунктом "выгоды", чтобы они Вар быть сохраненным в регистрах и вытертым longjmp.
НЕОБХОДИМО использовать энергозависимый при реализации структур данных без блокировок. Иначе компилятор является бесплатным оптимизировать доступ к переменной, которая изменит семантику.
Другими словами, энергозависимый говорит компилятору, что доступы к этой переменной должны соответствовать операции чтения-записи физической памяти.
, Например, это - то, как InterlockedIncrement объявляется в API Win32:
LONG __cdecl InterlockedIncrement(
__inout LONG volatile *Addend
);
От "Энергозависимый как обещание" статья Dan Saks:
(...) энергозависимый объект является тем, значение которого могло бы измениться спонтанно. Таким образом, когда Вы объявляете объект быть энергозависимыми, Вы говорите компилятору, что объект мог бы изменить состояние даже при том, что никакие операторы в программе, кажется, не изменяют его. "
Вот ссылки на три из его статей относительно volatile
ключевое слово:
Некоторые процессоры имеют регистры с плавающей точкой, которые имеют больше чем 64 бита точности (например, 32-разрядный x86 без SSE, см. комментарий Peter). Тот путь при выполнении нескольких операций на числах двойной точности, Вы на самом деле получает ответ более высокой точности, чем если бы необходимо было усечь каждый промежуточный результат к 64 битам.
Это является обычно большим, но это означает, что в зависимости от того, как компилятор присвоенные регистры и сделал оптимизацию, у Вас будут различные результаты для тех же самых операций на тех же самых исходных данных. При необходимости в непротиворечивости тогда, можно вынудить каждую операцию вернуться к памяти при помощи энергозависимого ключевого слова.
Это также полезно для некоторых алгоритмов, которые не имеют никакого алгебраического смысла, но уменьшают ошибку с плавающей точкой, такую как суммирование Kahan. Algebraicly это - NOP, таким образом, это будет часто неправильно оптимизироваться, если некоторые промежуточные переменные не будут энергозависимы.
volatile
необходим при разработке встроенных систем или драйверов устройств, где необходимо считать или записать устройство с отображенной памятью. Содержание конкретного регистра устройства могло измениться в любое время, таким образом, Вам нужно volatile
ключевое слово, чтобы гарантировать, что такие доступы не оптимизированы далеко компилятором.
Разрабатывая для встроенного, у меня есть цикл, который проверяет переменную, которая может быть заменена в обработчике прерываний. Без "энергозависимого" цикл становится noop - насколько компилятор может сказать, переменная никогда не изменяется, таким образом, это оптимизирует проверку далеко.
То же самое относилось бы к переменной, которая может быть заменена в различном потоке в более традиционной среде, но там мы часто делаем вызовы синхронизации, таким образом, компилятор не является настолько бесплатным с оптимизацией.
Другие ответы уже упоминают, что избежали некоторой оптимизации чтобы к:
Энергозависимый, важно каждый раз, когда Вы нуждаетесь в значении, чтобы казаться, приехать из внешней стороны и быть непредсказуемыми и избежать оптимизации компилятора на основе значения, известного, и когда результат на самом деле не используется, но Вам нужен он, чтобы быть вычисленными, или это используется, но Вы хотите вычислить его несколько раз для сравнительного теста, и Вам нужны вычисления, чтобы запуститься и закончиться в точных точках.
А энергозависимое чтение похоже на входную операцию (как scanf
или использование cin
): значение, кажется, прибывает из за пределами программы, таким образом, любое вычисление, которое имеет зависимость от значения, должно запуститься после него .
А энергозависимая запись похожа на выходную операцию (как printf
или использование cout
): значение, кажется, передается за пределами программы, поэтому если значение зависит от вычисления, это должно быть закончено прежде .
Так пара энергозависимого чтения-записи может использоваться, чтобы приручить сравнительные тесты и сделать измерение времени, значимое .
Без энергозависимого, Ваше вычисление могло быть запущено компилятором прежде, , поскольку ничто не предотвратит переупорядочение вычислений с функциями, такими как измерение времени .