NullPointerException
s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException
. Они наиболее распространены, но другие способы перечислены на странице NullPointerException
javadoc.
Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException
, be:
public class Example {
public static void main(String[] args) {
Object obj = null;
obj.hashCode();
}
}
В первой строке внутри main
я явно устанавливаю ссылку Object
obj
равной null
. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException
, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.
(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)
В C ++ 11 вы можете использовать std::bind
; это просто не так очевидно, как его использовать:
#include <functional>
using namespace std::placeholders;
std::find_if(
foo.begin(),
foo.end(),
// create a unary function object that invokes greater<int>::operator()
// with the single parameter passed as the first argument and `bar`
// passed as the second argument
std::bind(std::greater<int>(), _1, bar)
) - foo().begin() - 1;
Ключом является использование аргумента-заполнителя, объявленного в пространстве имен std::placeholders
. std::bind
возвращает объект функции, который принимает некоторое количество параметров при его вызове. Заполнители, используемые внутри вызова std::bind
, показывают, как аргументы, предоставляемые при вызове результирующего объекта, сопоставляются с списком аргументов вызываемому, к которому вы привязываетесь. Так, например:
auto op1 = std::bind(std::greater<int>(), _1, bar);
op1(5); // equivalent to std::greater<int>()(5, bar)
auto op2 = std::bind(std::greater<int>(), bar, _1);
op2(5); // equivalent to std::greater<int>()(bar, 5)
auto op3 = std::bind(std::greater<int>(), _2, _1);
op3(5, bar); // equivalent to std::greater<int>()(bar, 5)
auto op4 = std::bind(std::greater<int>(), _1, _2);
op4(5, bar); // equivalent to std::greater<int>()(5, bar)
bind
будет:
bind(std::greater<int>(), placeholders::_1, bar)
, но я думаю, что более рекомендуется использовать лямбда, как в:
[bar](const int a){return bar < a;}
Также рекомендуется используйте перегруженные функции begin/end
вместо вызовов методов. так это было бы так:
find_if(begin(foo), end(foo), [bar](const int a){return bar < a;})
Как насчет перехода от каменного века (bind2nd
) к железному веку с генераторной лямбдой C ++ 14, минуя бронзовый век (bind
)?
std::find_if(foo.begin(), foo.end(), [&](auto const& elem) {
return elem > bar;
});
И если вход сортируется
std::lower_bound(foo.begin(), foo.end(), bar);
Lambdas читается намного проще, а также проще встраивать, чем std::bind
выражения. См. Обсуждение Lavevej's CppCon 2015 .
bind
:)
– TemplateRex
23 September 2015 в 12:56