一、空指针异常的介绍
------NullPointerException 是 runtimeexception运行时异常的子类,因此,Javac 编译器并不会强迫你使用 try-catch 代码块来捕获该异常。
------在Java中,null 作为一个特殊值被对象引用,用来表示该对象当前指向的是一块未知内存数据。然而NullPointerException这个异常,则是程序在使用或访问一个对象的引用时,而该对象等于null则被抛出。
------那些情况会引发该异常呢?
被调用方法的对象为null。
访问或修改一个null对象的字段。
求一个数组为null对象的长度。
访问或修改一个数组为null对象中的某一个值。
被抛出的值是null并且是一个throwable的子类。
当你用null对象进行synchronized代码块。
向set方法存一个空值时。
二、处理空指针异常
1、业务场景

import com.java.entity.User;
import com.java.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;


@Controller
@RequestMapping
public class UserController {
    @Autowired
    private UserService service;

    @RequestMapping("/getUserList")
    public List<User> getUserList(){
        return service.listUser();
    }
    @RequestMapping("/get")
    public User get(String id){
        return service.get(id);
    }

}
import com.java.entity.User;
import java.util.List;

public interface UserService {
    List<User> listUser();
    User get(String id);
}
import com.java.entity.User;
import com.java.mapper.UserDao;
import com.java.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;

@Service("UserService")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao dao;

    @Override
    public List<User> listUser() {
        List<User> userList = dao.selectAll();
        if(CollectionUtils.isEmpty(userList)){//spring util工具类
            return null;
        }
        return userList;
    }

    @Override
    public User get(String id) {
        return dao.selectByPrimaryKey(id);
    }
}

对于以上描述的接口方法来看,它包含了以下两个含义:
listUser(): 查询用户列表
get(Integer id): 查询单个用户
1-1、 listUser研究

public List<User> listUser(){
    List<User> userList = userListRepostity.selectByExample(new UserExample());
    if(CollectionUtils.isEmpty(userList)){//spring util工具类
      return null;
    }
    return userList;
}

这段代码返回是null,对于集合这样返回值,最好不要返回null,因为如果返回了null,会给调用者带来很多麻烦。你将会把这种调用风险交给调用者来控制。
如果调用者是一个谨慎的人,他会进行是否为null的条件判断。否则,他会按照自己的理解去调用接口,而不进行是否为null的条件判断,如果这样的话,是非常危险的,它很有可能出现空指针异常!
根据墨菲定律来判断: “很有可能出现的问题,在将来一定会出现!”
基于此,我们将它进行优化:
*****对于接口(List listUser()),它一定会返回List,如果返回的集合为空不再返回null,即使没有数据,它仍然会返回List(集合中没有任何元素);
通过以上的修改,我们成功的避免了有可能发生的空指针异常,这样的写法更安全!

@Override
    public List<User> listUser() {
        List<User> userList = dao.selectAll();
        if(CollectionUtils.isEmpty(userList)){//spring util工具类
            return Lists.newArrayList();//com.google.common.collect.Lists提供的方法
        }
        return userList;
    }

2-1:研究get方法

@Override
    public User get(String id) {
        return dao.selectByPrimaryKey(id);
    }

通过代码的时候它的返回值很有可能是null! 但我们通过的接口是分辨不出来的!对于调用者来说是很危险的事情。
这里的建议是,在接口补充文档注释,比如对于异常的说明,使用注解@exception:

public interface UserSearchService{
  /**
   * 根据用户id获取用户信息
   * @param id 用户id
   * @return 用户实体
   * @exception UserNotFoundException
   */
  User get(Integer id);
}

这里的注释是写在后台代码中,如果调用者忽略了注释,这其实是一种弱约束性。
如何确定传入的参数不为空。JDK1.8提供了操作方式:
2-2:强制约束,我们可以通过jsr 303进行严格的约束声明:

public interface UserSearchService{
  /**
   * 根据用户id获取用户信息
   * @param id 用户id
   * @return 用户实体
   * @exception UserNotFoundException
   */
  User get(@NotNull Integer id);

  /**
   * 根据用户id获取用户信息
   * @param id 用户id
   * @return 用户实体,此实体有可能是缺省值
   */
  Optional<User> getOptional(@NotNull Integer id);
}

可以使用注解: @Nullable @Nonnull @CheckForNull 进行接口说明

public interface UserSearchService{
  /**
   * 根据用户id获取用户信息
   * @param id 用户id
   * @return 用户实体
   * @exception UserNotFoundException
   */
  @CheckForNull
  User get(@NonNull Integer id);

  /**
   * 根据用户id获取用户信息
   * @param id 用户id
   * @return 用户实体,此实体有可能是缺省值
   */
  Optional<User> getOptional(@NonNull Integer id);
}

三、避免空指针异常的常用技巧
1、优先使用String.valueOf() 代替toString()
当代码中的某个对象需要用字符串的方式来表示时,请避免使用toString方法;因为若你的对象引用为null,则会抛出 NullPointerException。
相反,使用静态String.valueOf方法,该方法不会抛出任何异常,若对象引用为空,则打印「null」字符串。
下面是基类 Object 的 toString() 方法:

public static String toString(int i) {
        if (i == Integer.MIN_VALUE)
            return "-2147483648";
        int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
        char[] buf = new char[size];
        getChars(i, size, buf);
        return new String(buf, true);
    }

再看string.valueof()的源码:

public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
    }

2、使用三元运算符来校验null值:使用场景常见于分页查询

@Override
    public PageInfo selectByPage(SysMachine machine, Integer page, Integer size, boolean isOnDealer) {
        page = page == null ? 1 : page;
        size = size == null ? 10 : size;
        PageHelper.startPage(page, size);
        return new PageInfo<>(dao.selectByMachine(machine, isOnDealer));
    }

3、使用Apache的StringUtils类,代码片段

@Transactional(rollbackFor = Exception.class)
    @Override
    public void bindCompany(List<String> machineIds, String companyId) {
        if (!StringUtils.isEmpty(companyId) && !StringUtils.isEmpty(machineIds)) {
            for (String machineId : machineIds) {
                machineCompanyService.delete(new SysMachineCompany().setMachineId(machineId));
                machineCompanyService.insertSelective(new SysMachineCompany().setMachineId(machineId).setCompanyId(companyId));
            }
        }
    }

4、创建返回空集合而不是null值的方法。
注意:要熟悉 Collections 这个集合工具类,里面有太多好用的方法了

import org.springframework.util.CollectionUtils;
public void st(){
        List<String> list=new ArrayList<>();
        CollectionUtils.isEmpty(list);
    }
请看源码-------------写的太好了。
public abstract class CollectionUtils {
    public CollectionUtils() {
    }

    ***

> public static boolean isEmpty(Collection collection) {
>         return collection == null || collection.isEmpty();
>     }

***

    public static boolean isEmpty(Map map) {
        return map == null || map.isEmpty();
    }

    public static List arrayToList(Object source) {
        return Arrays.asList(ObjectUtils.toObjectArray(source));
    }

    public static void mergeArrayIntoCollection(Object array, Collection collection) {
        if (collection == null) {
            throw new IllegalArgumentException("Collection must not be null");
        } else {
            Object[] arr = ObjectUtils.toObjectArray(array);
            Object[] arr$ = arr;
            int len$ = arr.length;

            for(int i$ = 0; i$ < len$; ++i$) {
                Object elem = arr$[i$];
                collection.add(elem);
            }

        }
    }

    public static void mergePropertiesIntoMap(Properties props, Map map) {
        if (map == null) {
            throw new IllegalArgumentException("Map must not be null");
        } else {
            String key;
            Object value;
            if (props != null) {
                for(Enumeration en = props.propertyNames(); en.hasMoreElements(); map.put(key, value)) {
                    key = (String)en.nextElement();
                    value = props.getProperty(key);
                    if (value == null) {
                        value = props.get(key);
                    }
                }
            }

        }
    }

    public static boolean contains(Iterator iterator, Object element) {
        if (iterator != null) {
            while(iterator.hasNext()) {
                Object candidate = iterator.next();
                if (ObjectUtils.nullSafeEquals(candidate, element)) {
                    return true;
                }
            }
        }

        return false;
    }

    public static boolean contains(Enumeration enumeration, Object element) {
        if (enumeration != null) {
            while(enumeration.hasMoreElements()) {
                Object candidate = enumeration.nextElement();
                if (ObjectUtils.nullSafeEquals(candidate, element)) {
                    return true;
                }
            }
        }

        return false;
    }
    }

5、instanceof 操作符
instanceof 即使对象的引用等于 null,也可以使用该运算符。在 instanceof 操作时,参考值等于为null,不抛出 NullPointerException,而是返回 false 。例如,下面的代码片段:

public boolean st(Object obj){
        if (obj instanceof User){
            return true;
        }
        return false;
    }

还有很多方法,大家可以尽情的探索。一起交流技术。