preface

What is your most memorable exception in Java programming? The NullPointerException null pointer is notorious. Do not say that primary programmers will encounter, even intermediate, expert programmers a little careless, will fall into this pit.

Any object in Java can be null, and NullPointerException is thrown when we call a method on an empty object, which is a very common type of error. There are several ways to avoid such exceptions and make our code more robust.

Several cases in which a null pointer occurs

1. An instance method of an empty object is called

public class Person {
    / / property
    private String name;
    private int age;

    public void print(a){
        System.out.println("This is Person Class");
    }
    
    public String read(a){
        System.out.println("This is person read");
        return null;
    }

    public static void main(String[] args)
    {
        Person person = null;
        // An instance method of an empty object is calledperson.print(); }}Copy the code

2. Access properties of empty objects

Person person = null;
// An empty object property is called
System.out.println(person.age);
Copy the code

3. When an array is an empty object, take its length

Person person = null;
// When the array is an empty object, take its length
System.out.println(person.name.length());
Copy the code

The method returns null and is used directly by the caller

Person person = new Person();
// The method returns null and is used directly by the caller
System.out.println(person.read().contains("Java"));
Copy the code

How do I avoid null Pointers at root

1, before use must be initialized, or check whether initialization;

2. Try to avoid returning NULL in functions or giving detailed comments.

3, external values, unless specified, must determine whether NULL.

Equals and equalsIgnoreCase() methods

Object class in the equals method the null Object reference not to achieve equal relationship, have symmetry x.equals (y) and y.e quals (x) the result is the same, but thrown when x = = null null pointer exception.

Such as:

String x = null;
String y = "world";
if(x.equals(y)){ // java.lang.NullPointerException
	
}

if(y.equals(x)){// NullPointerException can be avoided even if x is null
    
}
Copy the code

So we put objects or values that are definitely not NULL first.

The valueOf () and toString ()

Calling toString() on a null object raises a null pointer exception. Using valueOf() yields the same value. Passing a NULL to valueOf() returns NULL. Especially in wrapper classes like Integer, Float, Double, and BigDecimal.

Such as:

Integer i = null;
System.out.println(i.toString()); // Throw a NullPointerException
System.out.println(String.valueOf(i)); // Return null without exception
Copy the code

Optional type

Java 8 introduces the Optional type, which we can use to wrap the return value of a function. The advantage of this approach is that it is clear that the method may return a null value, so the caller must take care so that a nullpointer exception is not thrown. However, it is also inevitable to write more code and generate a lot of garbage objects, which increases the pressure on the GC, so it needs to be used with discretion.

Nested objects within objects is a common scenario in business systems, as shown in the following example code:

// Outermost object
class Outer {
    Nested nested;
    Nested getNested(a) {
        returnnested; }}// Layer 2 object
class Nested {
    Inner inner;
    Inner getInner(a) {
        returninner; }}// The lowest level object
class Inner {
    String foo;
    String getFoo(a) {
        returnfoo; }}Copy the code

In business, if we need to get Outer against foo in the underlying Inner, we have to write a bunch of non-null validations to prevent nullPointerExceptions:

// Tedious code
Outer outer = new Outer();
if(outer ! =null&& outer.nested ! =null&& outer.nested.inner ! =null) {
    System.out.println(outer.nested.inner.foo);
}
Copy the code

In Java8, we have a more elegant solution, which is Optional, which means we can do a flow-through map operation in one line of code. The map method is automatically null-checked internally:

Optional.of(new Outer())
    .map(Outer::getNested)
    .map(Nested::getInner)
    .map(Inner::getFoo
    .ifPresent(System.out::println); // If it is not null, the value of foo is finally printed
Copy the code

The Suppiler function customizes the enhanced API

We can use the Suppiler function to come up with an ultimate solution:

public static <T> Optional<T> resolve(Supplier<T> resolver) {
    try {
        T result = resolver.get();
        return Optional.ofNullable(result);
    }
    catch (NullPointerException e) {
        // A null pointer exception may be thrown, returning an empty Optional object
        returnOptional.empty(); }}Copy the code

Use the resolve method above to refactor the above non-null validation code snippet:

Outer obj = new Outer();
// Call resolve directly, internally nulling pointer handling
resolve(() -> obj.getNested().getInner().getFoo());
    .ifPresent(System.out::println); // If it is not null, the value of foo is finally printed
Copy the code

Use null-safe methods and libraries

Many open source libraries already do the heavy null-pointer checking for you. One of the most commonly used is StringUtils in Apache Commons. You can use stringutils.isblank (), isNumeric(), isWhiteSpace(), and other utility methods without worrying about null-pointer exceptions.

//StringUtils methods are null-pointer safe; they do not throw null-pointer exceptions
System.out.println(StringUtils.isEmpty(null));
System.out.println(StringUtils.isBlank(null));
System.out.println(StringUtils.isNumeric(null));
System.out.println(StringUtils.isAllUpperCase(null)); Output:true
true
false
false
Copy the code

assertions

Assertions are used to check the security of a program. Conditions are checked before use. If conditions are not met, an exception is reported.

The assert keyword comes with Java, for example:

assert name == null : "Name cannot be empty";
Copy the code

Output:

Exception in thread "main"Java. Lang. AssertionError: name is not correctCopy the code

However, assertion checking is not enabled by default and requires the JVM parameter -enableassertions to be effective.

This is rarely used in Java. It is recommended to use Spring, which is more powerful and convenient to use.

Use in Spring:

Assert.notNull(name,"Name cannot be empty");
Copy the code

Create a method that returns an empty collection instead of null

A good technique is to create methods that return an empty collection rather than a null value. Your application’s code can iterate through the empty collection and use its methods and fields without throwing a NullPointerException. The Collections class provides convenient empty lists, sets, and maps: collections. EMPTY_LIST, collections. EMPTY_SET, collections. EMPTY_MAP.

Such as:

public class Example {
   private static List<Integer> numbers = null;

   public static List<Integer> getList(a) {
     if (numbers == null) {return Collections.EMPTY_LIST;
     } else {
         returnnumbers; }}}Copy the code

A null pointer appears when the assignment is automatically unpacked

1. Null pointer for automatic unpacking of variable assignment

Long i = null;
// The null pointer appears when variable assignment is automatically unboxed
long j = i;
Copy the code

If the value of the Long variable is null, the automatic unpacking will be reported to the NPE.

2. The null pointer is abnormal due to automatic unpacking during method parameter transfer

public static int add(int x, int y)
{
    return x + y;
}


public static void main(String[] args)
{
    Integer left = null;
    Integer right = null;
    // The null pointer is abnormal due to automatic unpacking during parameter transfer
    System.out.println(add(left, right));
}
Copy the code

The above automatic unpacking is reported to NPE because the value of the boxing is NULL, and any method that calls NULL will report an error.

Circumvention Guide:

  • Primitive data types are preferred over wrapper types.
  • For indeterminate wrapper types, be sure to check for NULL.

Primitive data types are more time – and space-efficient than wrapper types.

conclusion

There is much more to avoid null Pointers effectively. One is to pay attention to code writing specifications and the other is to improve code literacy. Let’s come on together