I believe that Java programmers are familiar with NPE exception, which is the abbreviation of NullPointerException; recently, the development of business requirements is a bit anxious, and NPE exceptions appear from time to time in the test environment, which is a special headache; as one of the most frequently seen exceptions, once you start Java development , it can be said that it will accompany you throughout your career; whether you are a novice Xiaobai or an old driver, you are both "love" and ruthless towards NPE abnormalities. The main reason for love is that it is easy to deal with. Will step on the pit; in order to improve the quality of the code, NPE exceptions must be eliminated;
Since it is easy to deal with, what is there to worry about? Honestly, the verification is not over, but the experience for programmers during the whole processing process is very bad;
-
make the code verbose
In many cases, the amount of core business logic code is not large, but once various judgments and verifications are added, the code will become redundant, and the readability and maintainability will decrease accordingly;
-
Pure hard work
This kind of mechanical empty judgment and verification is essentially physical work, and there is no coding fun at all. Writing this kind of code for a long time will lose the passion for programming;
-
Easy to take the blame
Many businesses require the cooperation of multiple people, and sometimes there may be a fluke, thinking that other people will handle it when they use it; some pits have been dug invisibly, and the pot will fall from the sky if you are not careful;
Based on these not-so-good experiences above, the difficulty of elimination has increased a lot;
Sometimes when the demand is very urgent, most of the programmers will choose to focus on functions, and some less important things are always thought to be added later, and the important content is skipped first, and the result is that there is nothing after skipping. up;
In order to solve the NPE problem without affecting our development efficiency; JDK and the three-party framework provide us with many excellent tools, so there is no need to waste time and effort to reinvent the wheel;
Here are 10 coups to completely solve the NPE problem:
1Objects tool class
Since it is necessary to solve the null pointer, it is natural to perform a null check on the object in advance; under normal circumstances, it will be used to check the if( null != obj )
object; in Java 7, a tool class is specially provided java.util.Objects
to make the null check of the object easier;
features
-
Java 7 comes with no additional dependencies
-
static method, easy to use
-
Only supports object null detection
example
-
Objects.isNull
Determine whether the object is empty,
null
returntrue
, otherwise returnfalse
Object obj = null; System.out.println(Objects.isNull(obj)); // true obj = new Object(); System.out.println(Objects.isNull(obj)); // false
-
Objects.nonNull
And
Objects.isNull
the opposite; judge the object is not empty,null
returnfalse
, otherwise returntrue
Object obj = null; System.out.println(Objects.nonNull(obj)); // false obj = new Object(); System.out.println(Objects.nonNull(obj)); // true
-
Objects.requireNonNull
Verify that it is not empty. Once the object is empty, a NullPointerException will be thrown. You can customize the exception description by changing the method, so that you can quickly locate the problem after the exception:
Object obj = null; Objects.requireNonNull(obj); // 自定义错误描述 Objects.requireNonNull(obj,"obj 对象为空");
Execution output:
Exception in thread "main" java.lang.NullPointerException: obj 对象为空 at java.util.Objects.requireNonNull(Objects.java:228) at com.ehang.helloworld.controller.NullTest.t5(NullTest.java:97) at com.ehang.helloworld.controller.NullTest.main(NullTest.java:23)
2 The string is judged to be empty
Strings are the most used data type in the development process, so the judgment and verification of strings are essential. The native method is to judge the length of empty objects:
String str = "一行Java"
if ( null != str && s1.length() > 0 ){
// 对str字符串进行使用
}
However, in addition to judging the empty string, there are many other scenarios for checking the string, such as judging whether it is an empty string (String str = ), whether there are ""
only spaces (String str = " "
), etc., then these checks , it will be a little troublesome; but it doesn't matter, the ready-made tools are enough;
Spring StringUtil tool class
org.springframework.util.StringUtils
It is a string tool class that comes with the String framework, and its functions are relatively simple. In the new version of the teaching tool, the string null detection method of this tool class has been deprecated, so it is not recommended to use it;
-
StringUtils.isEmpty
Validation of empty objects and empty strings;
String s1 = null; String s2 = ""; String s3 = " "; System.out.println(StringUtils.isEmpty(s1)); // true System.out.println(StringUtils.isEmpty(s2)); // true System.out.println(StringUtils.isEmpty(s3)); // false
Apache lang3 StringUtil tool class
The apache lang3 StringUtil tool class ( org.apache.commons.lang3.StringUtils
) is more powerful than the tool class brought by the Spring framework, covering all the encapsulation of String operations;
There are mainly 4 for null check StringUtils.isEmpty
, StringUtils.isNotEmpty
, StringUtils.isBlank
,StringUtils.isNotBlank
-
rely
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency>
-
StringUtils.isEmpty
andStringUtils.isNotEmpty
Determine whether the string object is empty and whether the length of the string is 0; the check results of isEmpty and isNotEmpty are opposite;
String s1 = null; String s2 = ""; String s3 = " "; System.out.println(StringUtils.isEmpty(s1)); // true System.out.println(StringUtils.isEmpty(s2)); // true System.out.println(StringUtils.isEmpty(s3)); // false System.out.println(); System.out.println(StringUtils.isNotEmpty(s1)); // false System.out.println(StringUtils.isNotEmpty(s2)); // false System.out.println(StringUtils.isNotEmpty(s3)); // true
-
StringUtils.isBlank
、StringUtils.isNotBlank
On the basis of the sum
StringUtils.isEmpty
andStringUtils.isNotEmpty
judgment, after removing the spaces at the beginning and end of the string, it is judged whether the length is greater than 0String s1 = null; String s2 = ""; String s3 = " "; String s4 = " 1 2 "; System.out.println(StringUtils.isBlank(s1)); // true 空对象 System.out.println(StringUtils.isBlank(s2)); // true 长度等于0 System.out.println(StringUtils.isBlank(s3)); // true 去掉前后空格之后,长度也等于0 System.out.println(StringUtils.isBlank(s4)); // false 去掉前后空格(1 2),长度大于0 System.out.println(); System.out.println(StringUtils.isNotBlank(s1)); // false System.out.println(StringUtils.isNotBlank(s2)); // false System.out.println(StringUtils.isNotBlank(s3)); // false System.out.println(StringUtils.isNotBlank(s4)); // true
-
Other functions
This article mainly discusses the null check. The StringUtil tool class of lang3 covers almost all the encapsulation of String operations, which greatly reduces the complexity of our String processing. For more functions, please refer to the official documentation
https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html
3 string comparison
When comparing strings, you also need to pay special attention to NPE exceptions;
For example:
public Boolean isEhang(String name) {
if (name.equals("ehang")) {
return true;
}
return false;
}
When the name is null, an NPE exception will occur;
The following adjustments can be made:
if ("ehang".equals(name))
...
In this way, even if the name is null, there will be no NPE exception, and it can be judged normally;
4Map, List, Set judge empty
Map, List, and Set are data structures that are often used. Although they all contain isEmpty()
methods to determine whether the container contains elements, they cannot determine whether the self-generated object is empty. Once the object is not instantiated, call isEmpty() A null pointer exception will be reported; Spring provides us with a org.springframework.util.CollectionUtils
tool class, which isEmpty
will first judge whether the object is empty, and then judge whether there is an element through isEmpty(), which can greatly reduce the null pointer caused by the object being empty abnormal;
Map map = null;
System.out.println(map.isEmpty()); // 空指针异常
System.out.println(CollectionUtils.isEmpty(map)); // true
map = new HashMap();
System.out.println(map.isEmpty()); // true
System.out.println(CollectionUtils.isEmpty(map)); // true
map.put("1", "2");
System.out.println(CollectionUtils.isEmpty(map)); // false
System.out.println(map.isEmpty()); // false
List list = null;
System.out.println(list.isEmpty()); // 空指针异常
System.out.println(CollectionUtils.isEmpty(list)); // true
list = new ArrayList();
System.out.println(list.isEmpty()); // true
System.out.println(CollectionUtils.isEmpty(list)); // true
list.add("1");
System.out.println(CollectionUtils.isEmpty(list)); // false
System.out.println(list.isEmpty()); // false
Set set = null;
System.out.println(set.isEmpty()); // 空指针异常
System.out.println(CollectionUtils.isEmpty(set)); // true
set = new TreeSet();
System.out.println(set.isEmpty()); // true
System.out.println(CollectionUtils.isEmpty(set)); // true
set.add("1");
System.out.println(CollectionUtils.isEmpty(set)); // false
System.out.println(set.isEmpty()); // false
In addition to empty judgment, the tool class also contains many useful methods, such as getting the first element: firstElement(), the last element: lastElement(), whether it contains an element: contains(), etc.
hutool的CollectionUtil
Simply judge the empty space, the previous Spring CollectionUtils is enough, and other functions are also sufficient to meet most usage scenarios; hutool的CollectionUtil
more complete functions are provided, and you can also choose if necessary;
rely:
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.22</version>
</dependency>
5 Assign initial value, try not to return null object
When defining local variables and defining object properties, those that can be assigned initial values should be provided with initial values as much as possible;
Map map = new HashMap();
private Integer age = 0;
When the method has a return value, try not to return null unless necessary;
For example, the execution of a method finally returns a List. When the List has no value, instead of returning a null object, an empty List can be returned.
public List select(){
// 这里处理其他逻辑
// 一旦返回的是null是,返回一个空List对象
return Collections.emptyList();
}
6Optional
Optional is an object container provided by Java 8. The purpose is to effectively solve this annoying null pointer exception. We can regard Optional as an object for the wrapper class;
-
Instantiate the Optional object
Object o1 = null; Optional<Object> op1 = Optional.of(o1); Optional<Object> op2 = Optional.ofNullable(o1);
Optional.of()
When the object is null, the creation process will throw an NPE exception
Optional.ofNullable()
When the object is null, the Optional object can also be returned normally
-
Empty isPresent()
Integer i1 = null; Optional<Integer> op1 = Optional.of(i1); System.out.println(op1.isPresent()); // false Integer i2 = 123; Optional<Integer> op2 = Optional.ofNullable(i2); System.out.println(op2.isPresent()); // true op2.ifPresent(i->{ System.out.println(i); });
isPresent() returns true when the object is null and false when it is not empty
Chain processing of lambda expressions:
op2.ifPresent(obj->{ System.out.println(obj); });
-
value
// 取出原值,如果原对象为null会报NoSuchElementException异常 Integer integer = op2.get(); // 取出原值,如果原值为空,则返回指点的默认值 Integer integer1 = op1.orElse(456); // 取出原值,如果原值为空,返回默认值,不过在返回之前还需要做一些其他的事情 Integer integer2 = op2.orElseGet(() -> { // 在这里做一些其他的操作 return 456; }); // 取出原值,如果原值为空,就抛出指定的异常 op2.orElseThrow(RuntimeException::new); op2.orElseThrow(() -> new RuntimeException("不好,我的值是空的!"));
-
map() and flatMap()
During the encoding process, there are often chain calls like: a.xxx().yyy().zzz().mmm(). Once there is a problem in any link in the process, NPE will be abnormal. Therefore, we You can use map() and flatMap() to avoid this problem;
Test object:
@Data @NoArgsConstructor @AllArgsConstructor static class User { private String name; private Integer age; private Optional<String> addr; }
test:
// 得到姓名的长度,如果没有姓名就返回0 Integer nameLen = Optional.of(new User(null, 10, null)) .map(User::getName) .map(String::length) .orElse(0); System.out.println(nameLen); // 得到地址的长度,如果没有姓名就返回0 Integer addr = Optional.of(new User(null, 10, Optional.of("北京"))) .flatMap(User::getAddr) .map(String::length) .orElse(0); System.out.println(addr);
map will encapsulate the returned object into an Optional object. If the returned object itself is an Optional object, then use flatMap()
7 Affirmations
The translation in Spring is " assertionorg.springframework.util.Assert
" in Chinese , which is used to determine whether an actual operating value is consistent with the expected item, and an exception is thrown if it is inconsistent. With the help of this class, you can also do a null test;
The Assert class provides the following static methods:
method name | describe | throw exception on failure |
---|---|---|
isNull(Object object, String message) | object is not null, an exception is thrown | IllegalArgumentException |
notNull(Object object, String message) | object is empty, an exception is thrown | IllegalArgumentException |
hasLength(String text, String message) | text is an empty string, an exception is thrown | IllegalArgumentException |
hasText(String text, String message) | does not contain a blank string, an exception is thrown | IllegalArgumentException |
doesNotContain(String textToSearch, String substring, String message) | textToSearch contains substring, throws an exception | IllegalArgumentException |
notEmpty(Object[] array, String message) | array is empty or the length is 1, an exception is thrown | IllegalArgumentException |
noNullElements(Object[] array, String message) | If the array contains null elements, an exception will be thrown | IllegalArgumentException |
notEmpty(Collection collection, String message) | collection contains no elements, an exception is thrown | IllegalArgumentException |
notEmpty(Map map, String message) | If the map contains null, an exception is thrown | IllegalArgumentException |
isInstanceOf(Class type, Object obj, String message) | If obj is not of type type, an exception is thrown | IllegalArgumentException |
isAssignable(Class superType, Class subType, String message) | subType is not a superType subclass, an exception is thrown | IllegalArgumentException |
state(boolean expression, String message) | expression is not true and an exception is thrown | IllegalStateException |
isTrue(boolean expression, String message) | expression is not true and an exception is thrown | IllegalArgumentException |
Integer i1 = null;
Assert.notNull(i1,"i1 不为空");
Map map = null;
Assert.notEmpty(map,"map 不为空");
abnormal:
Exception in thread "main" java.lang.IllegalArgumentException: map 不为空
at org.springframework.util.Assert.notEmpty(Assert.java:555)
at com.ehang.helloworld.controller.NullTest.t6(NullTest.java:119)
at com.ehang.helloworld.controller.NullTest.main(NullTest.java:23)
pay attention:
Assert is used to determine whether an actual operating value is consistent with the expected item, so it is the opposite of the verification method of other tool classes; for example, the method isNull
expects the object to be null, and if it is not empty, an error will be reported; notNull
Indicates that the expected object is not empty, and when the object is empty, an error will be reported;
8 Local variables use basic data types
In the previous article " Why Ali Prohibits the Use of Basic Data Types in Objects ", from the perspective of performance, it is recommended to use basic data types as much as possible for the definition of local variables. Using basic data types can also effectively avoid null pointer exceptions;
Examples are as follows:
int x;
Integer y;
System.out.println( x + 1 ); // 编译失败
System.out.println( y + 1 ); // 编译失败
int i = 1;
Integer j = null;
System.out.println( i + 1 ); // 正常
System.out.println( j + 1 ); // 空指针异常
int m = i; // 正常
int n = j; // 空指针异常
When the variables x and y are only defined and not assigned, x + 1 and y + 1 cannot be compiled; and the packaging class j can specify objects. When the packaging class participates in the operation, the unboxing operation will be performed null
first , that is to call the intValue() method. Since the object is empty, the calling method will naturally report a null pointer; at the same time, when assigning a wrapper class to a basic data type, the unboxing operation will also be performed, and naturally it will be empty The pointer is abnormal;
However, the basic data type must specify a specific value, and there will be no null pointer exception regardless of subsequent operations or assignment operations;
9 Verify parameters in advance
Most of the background data is transmitted through terminal requests, so it is necessary to verify the parameters of the verification at the place closest to the user; for example, the StringBoot project needs to pass the parameters requested by the client at the Controller layer For verification, once the parameters that must be passed do not have a value, you should directly report an error to the client and remind the user, instead of passing these null values that do not meet the requirements to the Service or even save them in the database. Verify and intercept them as soon as possible. Can greatly reduce the probability of problems
The previous introduction hibernate-validator
can perfectly solve the problem of parameter verification. For details, see: SpringBoot! Are your requests, responses, and exceptions standardized?
10IDEA Reminder
IDEA will remind you of empty objects or objects that may have null values, and you can perceive and prevent them in advance according to the reminders
public static String t1(int i){
String name1 = null;
String name2 = null;
if(i>0){
name2 = "ehang";
}
t2(name1);
t2(name2);
return name2;
}