Хорошим местом для начала является JavaDocs . Они охватывают это:
Брошено, когда приложение пытается использовать null в случае, когда требуется объект. К ним относятся:
- Вызов метода экземпляра нулевого объекта.
- Доступ или изменение поля нулевого объекта.
- Выполнение длины null, как если бы это был массив.
- Доступ или изменение слотов с нулевым значением, как если бы это был массив.
- Бросать нуль, как если бы это было значение Throwable.
Приложения должны бросать экземпляры этого класса для указания других незаконных видов использования нулевого объекта.
blockquote>Также, если вы попытаетесь использовать нулевую ссылку с
synchronized
, который также выдаст это исключение, за JLS :SynchronizedStatement: synchronized ( Expression ) Block
blockquote>
- В противном случае, если значение выражения равно null,
NullPointerException
.Как это исправить?
Итак, у вас есть
NullPointerException
. Как вы это исправите? Возьмем простой пример, который выдаетNullPointerException
:public class Printer { private String name; public void setName(String name) { this.name = name; } public void print() { printString(name); } private void printString(String s) { System.out.println(s + " (" + s.length() + ")"); } public static void main(String[] args) { Printer printer = new Printer(); printer.print(); } }
Идентифицирует нулевые значения
. Первый шаг - точно определить , значения которого вызывают исключение . Для этого нам нужно выполнить некоторую отладку. Важно научиться читать stacktrace . Это покажет вам, где было выбрано исключение:
Exception in thread "main" java.lang.NullPointerException at Printer.printString(Printer.java:13) at Printer.print(Printer.java:9) at Printer.main(Printer.java:19)
Здесь мы видим, что исключение выбрано в строке 13 (в методе
printString
). Посмотрите на строку и проверьте, какие значения равны нулю, добавив протоколирующие операторы или используя отладчик . Мы обнаруживаем, чтоs
имеет значение null, а вызов методаlength
на него вызывает исключение. Мы видим, что программа перестает бросать исключение, когдаs.length()
удаляется из метода.Трассировка, где эти значения взяты из
Затем проверьте, откуда это значение. Следуя вызовам метода, мы видим, что
s
передается сprintString(name)
в методеprint()
, аthis.name
- null.Трассировка, где эти значения должны быть установлены
Где установлен
this.name
? В методеsetName(String)
. С некоторой дополнительной отладкой мы видим, что этот метод вообще не вызывается. Если этот метод был вызван, обязательно проверьте порядок , что эти методы вызывают, а метод set не будет называться после методом печати. Этого достаточно, чтобы дать нам решение: добавить вызов
printer.setName()
перед вызовомprinter.print()
.Другие исправления
Переменная может иметь значение по умолчанию (и
setName
может помешать ему установить значение null):private String name = "";
Либо метод
printString
может проверить значение null например:printString((name == null) ? "" : name);
Или вы можете создать класс, чтобы
name
всегда имел ненулевое значение :public class Printer { private final String name; public Printer(String name) { this.name = Objects.requireNonNull(name); } public void print() { printString(name); } private void printString(String s) { System.out.println(s + " (" + s.length() + ")"); } public static void main(String[] args) { Printer printer = new Printer("123"); printer.print(); } }
См. также:
Я все еще не могу найти проблему
Если вы попытались отладить проблему и до сих пор не имеете решения, вы можете отправить вопрос для получения дополнительной справки, но не забудьте включить то, что вы пробовали до сих пор. Как минимум, включите stacktrace в вопрос и отметьте важные номера строк в коде. Также попробуйте сначала упростить код (см. SSCCE ).
Альтернатива метапрограммированию стиля шаблонов является Макростилем, который Вы видите в различных реализациях Lisp. Я предложил бы загрузить Paul Graham На Lisp и также смотреть на Clojure, если Вы интересуетесь Lisp с макросами, которые работают на JVM.
Макросы в Lisp намного более мощны, чем C/C++ разрабатывает и составляет язык самостоятельно - они предназначены для метапрограммирования.
Метаязык (ML), конечно: http://cs.anu.edu.au/student/comp8033/ml.html
Lisp поддерживает форму "метапрограммирования", хотя не в том же смысле как шаблонное метапрограммирование C++. Кроме того, Ваш "статичный" термин мог означать разные вещи в этом контексте, но Lisp также поддерживает статический контроль типов, если это - то, что Вы имеете в виду.
'метапрограммирование' является действительно дурной славой для этой определенной функции, по крайней мере, когда Вы обсуждаете больше чем один язык, так как эта функция только необходима для узкой части языков, которые являются:
вынимают любой из них, и 'статическое метапрограммирование', просто не имеет смысла. поэтому, я был бы удивлен, имел ли какой-либо удаленно основной язык что-то как этот, как понято на C++.
, конечно, динамические языки и несколько функциональных языков поддерживают полностью различные понятия, которые можно было также назвать метапрограммированием.
Большая работа в Haskell: Предметно-ориентированные языки (DSL's), Исполняемые спецификации, Преобразование Программы, Частичное Приложение, Подготовленное Вычисление. Немного ссылок для запущения Вас:
Языковая семья ML была специально разработана с этой целью. Одна из самых известных историй успеха OCAML библиотека FFTW для высокоэффективного FFTs, который является кодом C, сгенерированным почти полностью программой OCaml.
С наилучшими пожеланиями, Jon Harrop.
язык программирования "D" является C ++-like, но имеет намного лучшую поддержку метапрограммирования. Вот является пример трассировщика лучей записанным использующим только метапрограммированием времени компиляции:
Кроме того, существует ответвление gcc, названное "Понятие GCC", который поддерживает конструкции метапрограммирования, которые тот C++, по крайней мере, еще не делает ().
Nemerle и Шиканье мои любимые для таких вещей. Nemerle имеет очень изящный макро-синтаксис, несмотря на его плохую документацию. Документация шиканья превосходна, но ее макросы немного менее изящны. Обе работы невероятно хорошо, как бы то ни было.
И целевая.NET, таким образом, они могут легко взаимодействовать с C# и другими языками.NET - даже двоичные файлы Java, если Вы используете IKVM.
Редактирование: Для разъяснения я имею в виду макросы в значении слова Lisp, не макросы препроцессора C. Они позволяют определение нового синтаксиса и тяжелого метапрограммирования во время компиляции. Например, Nemerle поставлется с макросами, которые проверят Ваши SQL-запросы против Вашего SQL-сервера во время компиляции.
Шаблонное метапрограммирование является по существу злоупотреблением шаблонным механизмом. То, что я имею в виду, - то, что Вы получаете в основном, что Вы ожидали бы от функции, которая была незапланированным побочным эффектом---, это - путаница, и (хотя инструменты являются улучшением), реальная боль в заднице, потому что язык не поддерживает Вас в выполнении его (я должен отметить, что мой опыт с современным состоянием на этом устарел, так как я по существу разочаровался в подходе. Я не услышал ни о каких больших достигнутых успехах, хотя)
Бездельничание с этим приблизительно в '98 было тем, что управляло мной для поиска лучших решений. Я мог записать полезные системы, которые полагались на него, но они были адскими. Ввод по абсолютному адресу вокруг в конечном счете ведомого меня к языку Common LISP. Несомненно, шаблонный механизм полон по Тьюрингу, но с другой стороны так intercal.
язык Common LISP делает метапрограммирование правильно. Вы имеете полную мощность в наличии языка, в то время как Вы делаете это, никакой специальный синтаксис, и потому что язык является очень динамичным, можно сделать больше с ним.
, конечно, существуют другие опции. Никакой другой язык, который я использовал, не делает метапрограммирование лучше, чем Lisp, который является, почему я использую его для кода исследования. Существует много причин, Вы могли бы хотеть попробовать что-то еще, хотя, но это все собирается быть компромиссами. Можно посмотреть на Haskell/ML/OCaml и т.д. Много функциональных языков имеет что-то приближающееся к питанию макросов Lisp. Можно найти некоторую.NET предназначенным материалом, но они являются все довольно крайними (с точки зрения базы пользователей и т.д.). Ни один из крупных игроков на промышленно используемых языках не имеет ничего как это, действительно.
позвольте мне перечислить немного важных деталей о том, как метапрограммирование работы в шепелявости (или схема , или большой список , или выбирают Ваш любимый "динамический" язык):
случайные примеры того, что можно реализовать как пользовательская библиотека метапрограммирование шепелявости использования (это фактические примеры библиотек языка Common LISP):
Язык Common LISP поддерживает программы, которые пишут программы несколькими различными способами.
1) данные Программы и программа "абстрактное синтаксическое дерево" универсальны (S-выражения!)
2) defmacro
3) макросы Читателя.
4) MOP
их, реальный вентилятор ума является MOP. Прочитайте "Искусство Протокола Метаобъекта". Это изменит вещи для Вас, я обещаю!
Большинство людей пытаются найти язык, имеющий "окончательное отражение" для самопроверки и что-то вроде "eval" для определения нового кода. Такие языки трудно найти (LISP является ярким контрпримером) и они определенно не являются общепринятыми.
Но другой подход состоит в использовании набора инструментов, которые могут проверять, генерировать программный код и управлять им. Джекпот - такой инструмент сосредоточился на Java. http://jackpot.netbeans.org/
Наш набор инструментов для реинжиниринга программного обеспечения DMS такой инструмент, который работает на C, C ++, C #, Java, COBOL, PHP, Javascript, Ada, Verilog, VHDL и множество других языков. (Он использует интерфейсы производственного качества, чтобы он мог читать все эти языки). Более того, он может делать это на нескольких языках одновременно. См. http://www.semdesigns.com/Products/DMS/DMSToolkit.html
DMS успешна, потому что она предоставляет обычный метод и инфраструктуру поддержки для полного доступа к структуре программы в виде AST, и в большинстве случаев дополнительные данные, такие как таблицы символов, информация о типах, управление и анализ потока данных, все необходимое для сложных программных манипуляций.