1. Введение
NullPointerException
Это должно быть самой распространенной проблемой при разработке Java и самой распространенной ошибкой Java-программистов. Это может показаться небольшой ошибкой, но влияние немаленькое. Тони Хоар (изобретатель нулевой ссылки) сказал в 2009 году, что NPE обходится предприятиям в миллиарды долларов. За полгода этой работы я несколько раз наступал на яму NPE. Например, мне нужно добавить кусок кода к исходной логике, но вновь добавленный код выдает ошибку NPE, и в то же время не выполняется обработка исключений, что напрямую приводит к тому, что последующая логика не запускается, влияя на вся оригинальная логика тоже.Ужасно. Поэтому все должны быть осторожны, чтобы избежать ямы NPE.
Эта статья начнется со следующих двух аспектов:
- Вероятность NPE
- Совет по избеганию NPE
2. Вероятность NPE
Сначала нам нужно понять, как происходит NPE.
String s;
String[] ss;
При объявлении ссылочной переменной, если вы не укажете, на что она указывает, Java по умолчанию будет иметь значение null, пустой адрес, что означает «ни на что не указывает». Если впоследствии переменной не будет присвоено значение, при использовании содержимого этой переменной будет выброшен NPE.
Например,.
для доступа к методу или переменной,[]
Чтобы получить доступ к слоту массива:
System.out.println(s.length());
System.out.println(ss[0]);
Ниже приведены6 возможных ситуаций, описанных в Javadoc NPE:
-
Вызов метода экземпляра для пустого объекта. При вызове статического метода или метода класса для пустого объекта NPE не будет сообщено, поскольку статическому методу не требуется экземпляр для вызова любого метода;
-
При доступе или изменении любой переменной или поля в пустом объекте;
-
выдает null при возникновении исключения;
-
Когда массив равен нулю, получить доступ к длине массива;
-
Когда массив равен нулю, получить доступ или изменить слот массива;
-
Синхронизируйте пустой объект или используйте null внутри синхронизированного блока.
3. Советы по избеганию NPE
В этом разделе представлены некоторые советы о том, как избежать NPE во время разработки.
(1)Старайтесь избегать вызова метода equals() и метода equalsIgnoreCase() для неизвестных объектов, вместо этого вызывайте их для известных строковых констант.
из-заequals()
а такжеequalsIgnoreCase()
У него есть симметрия, поэтому его можно переворачивать напрямую, чего легко добиться.
Object unknowObject = null;
if (unknowObject.equals("knowObject")) {
System.out.println("如果 unknowObject 是 null,则会抛出 NPE");
}
if ("knowObject".equals(unknowObject)) {
System.out.println("避免 NPE");
}
(2)Избегайте toString(), вместо этого используйте String.valueOf()
Это потому чтоString.valueOf()
Непустая проверка выполняется посередине, и объектtoString()
метод, так что результат тот же.
Object unknowObject = null;
System.out.println(unknowObject.toString());
System.out.println(String.valueOf(unknowObject));
(3)Использование нулевых безопасных методов и библиотек
Методы библиотек с открытым исходным кодом обычно имеют ненулевую проверку, например, в общей библиотеке Apache.StringUtils
в классе инструментовisBlank()
,isNumeric()
и другие методы, вам не нужно беспокоиться о NPE при его использовании. Затем, когда мы используем стороннюю библиотеку, мы должны знать, безопасна ли она для нулевого значения, если нет, нам нужно самостоятельно выполнить ненулевую проверку.
System.out.println(StringUtils.isBlank(null));
System.out.println(StringUtils.isNumeric(null));
(4)Когда метод возвращает коллекцию или массив, не возвращайте null, а возвращайте пустую коллекцию или пустой массив.
При возврате пустой коллекции или пустого массива гарантированно вызывается метод (например,size()
,length()
) не будет отображаться NPE. а такжеCollections
В классе предусмотрены удобные пустые List, Set и Map,Collections.EMPTY_LIST
,Collections.EMPTY_Set
,Collections.EMPTY_MAP
.
public List fun(Customer customer){
List result = Collections.EMPTY_LIST;
return result;
}
(5)Аннотировать с помощью @NotNull и @Nullable
-
@NonNull
Может быть отмечен на методе, поле, параметре, указывая, что соответствующее значение не может быть пустым -
@Nullable
Он может быть отмечен на методе, поле, параметре, указывая, что соответствующее значение может быть пустым.
Вышеуказанные две аннотации не будут играть никакой роли в процессе запуска программы, а будут запрашиваться только при проверке IDE, компилятора, FindBugs и генерации документа.
есть несколько@NotNull
а также@Nullable
Я не могу досконально понять, как использовать конкретные я не высказываюсь. Но даже помимо обнаружения, простое определение также может играть роль в документе.
(6)Избегайте ненужной упаковки и распаковки
Если объект-оболочка имеет значение null, во время распаковки может возникнуть NPE.
Integer integer = null;
int i = integer;
System.out.println(i);
(7)Определите разумные значения по умолчанию
Предоставляйте разумные значения по умолчанию при определении переменных-членов.
public class Main {
private List<String> list = new ArrayList<>();
private String s = "";
}
(8)Режим пустого объекта
Пустой объект — это особый экземпляр дизайна, обеспечивающий поведение по умолчанию для таких методов, какCollections
серединаEMPTY_List
, мы все еще можем использовать егоsize()
, который возвращает 0 без создания NPE.
Другой пример в Джексоне, когда дочерний узел не существует,path()
вернетMissingNode
объект при вызовеMissingNode
объектpath()
метод будет продолжать возвращатьсяMissingNode
. Такие связанные вызовы не вызовут NPE. После окончательного возврата пользователь просто должен проверить, является ли результатMissingNode
Вы можете сказать, если вы можете найти его.
JsonNode child = root.path("a").path("b");
if (child.isMissingNode()) {
//...
}
(9)Optional
Optional
Новая функция Java8, объекты-контейнеры, допускающие значение NULL. Если значение существует и не равно нулю, тоisPresent()
метод вернет true, вызовитеget()
метод может вернуть этот объект. Что он делает, так это избегает нулевой проверки, которую мы показываем.
Вот пример обычной проверки null:
// 最外层
public class Outer {
Nested nested;
Nested getNested() {
return nested;
}
}
// 第二层
public class Nested {
Inner inner;
Inner getInner() {
return inner;
}
}
// 最底层
public class Inner {
String foo;
String getFoo() {
return foo;
}
}
мы проходимOuter
доступ к объектамInner
серединаfoo
Атрибут, если добавлена проверка нулевого значения, код выглядит следующим образом:
Outer outer = new Outer();
if (outer != null) {
if (outer.nested != null) {
if (outer.nested.inner != null) {
System.out.println(outer.nested.inner.foo);
}
}
}
Этот вид вложенного оператора суждения очень распространен при проверке нулей. при использованииOptional
В сочетании с функциями лямбда-выражений Java8 и потоковой обработки можно использовать цепные операции, что является более кратким.
Optional.of(new Outer())
.map(Outer::getNested)
.map(Nested::getInner)
.map(Inner::getFoo)
.ifPresent(System.out::println);
Optional.of()
метод может вернутьOptional<Outer>
объект и будетOuter
Предметы помещаются внутрь контейнера,Optinal.map()
Метод, пройдетisPresent()
Метод оценивает, является ли он нулевым, если он нулевой, он возвращаетOptional<Outer>
Пустой объект типа, который не влияет на последующие связанные вызовы. Это выглядит знакомо, это похоже на шаблон пустого объекта, о котором мы говорили в пункте 8, вOptional
Этот шаблон также используется в реализации .
(10)осторожный
Эй, давайте сделаем десятый пункт.
Наконец, я желаю вам всем успеха, чтобы избежатьNullPointerException
, если у вас есть другие хорошие предложения, пожалуйста, оставьте сообщение для обмена!
4. Ссылка
- Java Tips and Best practices to avoid NullPointerException in Java Applications
- Как кокетливо избегать исключений нулевого указателя в Java 8
Друзья, которым нравятся мои статьи, вы можете отсканировать код и подписаться на мой официальный аккаунт: "Травяной щипок"