避免Java应用中NullPointerException的技巧和最佳实践

 

1. 已知对象放首位

说明:即调用已知对象的访问与未知对象比较或操作

以String类的equal方法

Object unknownObject = null;

//错误方式 – 可能导致 NullPointerException

if(unknownObject.equals("knownObject")){

   System.err.println("This may result in NullPointerException if unknownObject is null");

}

//正确方式 - 即便 unknownObject是null也能避免NullPointerException

if("knownObject".equals(unknownObject)){

    System.err.println("better coding avoided NullPointerException");

}

2.  对象转字符串,用String.valueOf(object)不用object.toString(),避免object为null

BigDecimal bd = getPrice();

System.out.println(String.valueOf(bd)); //不会抛出空指针异常

System.out.println(bd.toString()); //抛出 "Exception in thread "main" java.lang.NullPointerException"

 

3. 使用null 安全的方法、库/jar包,以apache commons包为例

你可以使用StringUtils.isBlank(),isNumeric(),isWhiteSpace()以及其他的工具方法而不用担心空指针异常。

//StringUtils方法是空指针安全的,他们不会抛出空指针异常

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

ps:stringutils.isblank与isempty的区别:空白字符

 public static boolean isBlank(String str)
判断某字符串是否为空或长度为0或由空白符(whitespace)构成
下面是示例:
StringUtils.isBlank(null) = true
StringUtils.isBlank("") = true
StringUtils.isBlank(" ") = true
StringUtils.isBlank(" ") = true
StringUtils.isBlank("\t \n \f \r") = true //对于制表符、换行符、换页符和回车符StringUtils.isBlank()均识为空白符
StringUtils.isBlank("\b") = false //"\b"为单词边界符
StringUtils.isBlank("bob") = false
StringUtils.isBlank(" bob ") = false
public static boolean isEmpty(String str)
判断某字符串是否为空,为空的标准是str==null或str.length()==0
下面是StringUtils判断是否为空的示例:
StringUtils.isEmpty(null) = true
StringUtils.isEmpty("") = true
StringUtils.isEmpty(" ") = false //注意在StringUtils中空格作非空处理
StringUtils.isEmpty(" ") = false
StringUtils.isEmpty("bob") = false
StringUtils.isEmpty(" bob ") = false

4. 避免从方法中返回空指针,而是返回空collection或者空数组

Collections类提供了方便的空List,Set和Map: Collections.EMPTY_LIST,Collections.EMPTY_SET,Collections.EMPTY_MAP。这里是实例。

5.  使用annotation@NotNull 和 @Nullable

@Nullable表示可以为null ,@NotNull表示不可以为null

6. 避免包装类,自动包装和自动解包报空指针

Person 类的private Integer  phone;

Person ram = new Person("ram");

int phone = ram.getPhone(); //此时phone=null, null转int报空指针异常

7.给与合适的默认值

说明:某些对象的属性必须有值,否则会报空指针,因此要么创建对象必须指定其值,否则无法创建对象,要不给与默认值

8.定义数据库中的字段是否可为空

说明:这个跟第7点一样,差异就是这个对象是通过dao操作返回的对象。因此该对象导致空指针的字段必须在数据库表中有值(可以设置默认值)

9.使用空对象模式---带完善

空对象是一个特殊的对象,其在不同的上下文中有不同的意义。例如一个空的迭代器调用hasNext()返回false时,可以是一个空对象。同样的在返回Container和Collection类型方法的例子中,空对象可以被用来代替null作为返回值

从网上了一个

一、空对象模式简介
在空对象模式中,一个空对象取代NULL对象的实例的检查。NULL对象不是检查空值,而是反映一个不做任何动作的关系。这样的NULL对象也可以在数据不可用的时候提供默认的行为。
在空对象模式中,我们创建一个指定各种要执行的操作的抽象类和扩展该类的实体类,还创建一个未对该类做任何实现的空对象类,该空对象类将无缝地使用在需要检查空值的地方。
空对象模式一般和策略模式或工厂模式结合使用。

二、示例演示
1、业务需求
假设这样一个场景:
在一个图书信息查询系统中,你调用一个方法,传过去你要查找图书的ID,然后它返回给你,你要查找的图书对象,这样你就可以调用对象的方法来输出图书的信息。
下面,我们来实现以下具体的代码。
2、不使用空对象设计模式
首先,我们来看一下ConcreteBook类的代码(提供构造函数和展示图书信息的show()方法。)
public class ConcreteBook {
    private int ID;
    private String name;
    private String author;
 
    // 构造函数
    public ConcreteBook(int ID, String name, String author) {
        this.ID = ID;
        this.name = name;
        this.author = author;
    }
    //显示图示信息
    public void show() {
        System.out.println(ID + "**" + name + "**" + author);
    }
 
}

再来看看创建图书对象的图书工厂的代码(主要提供一个获得ConcreteBook的方法):
public class BookFactory {
    
    public ConcreteBook getBook(int ID) {
        ConcreteBook book = null;
        switch (ID) {
        case 1:
            book = new ConcreteBook(ID, "设计模式", "GoF");
            break;
        case 2:
            book = new ConcreteBook(ID, "我的设计模式", "空对象模式");
            break;
        default:
            book = null;// 其实这个可以省略,因为初始化已经赋值为null。
            break;
        }
 
        return book;
    }
}

最后,来看一下客户端的代码:
public class Client {
 
    static void main(String[] args) {
        BookFactory bookFactory = new BookFactory();
        ConcreteBook book = bookFactory.getBook(1);
        book.show();
    }
 
}
运行结果:
1**设计模式**GoF
如果我们把ConcreteBook book = bookFactory.getBook(1);中的1改为-1则会出现空指针异常,因为我们通过bookFactory.getBook()方法获取ConcreteBook对象的时候,如果我们传入的参数,即图书的ID,属于非法值(如-1)或者不存在(如3)的话(其实这种情况是经常遇到的。),就会返回null,表示我们查找的图书信息并不存在。这时,book为null.你再调用book.show()。当然要报空指针的错误了。那怎么解决呢?我们可以使用空对象模式来解决这个问题。


3、使用空对象模式

首先定义一个抽象接口Book类
public interface Book {
    // 判断Book对象是否为空对象(Null Object)
    public boolean isNull();
 
    // 展示Book对象的信息内容。
    public void show();
}
然后新增一个空对象类NullBook类和一个非空对象类ConcreteBook类
public class NullBook implements Book {
    public boolean isNull() {
        return true;
    }
 
    public void show() {
        System.out.println("Sorry,未找到符合您输入的ID的图书信息,请确认您输入的不是非法值。");
 
 
    }
}
public class ConcreteBook implements Book{
    private int ID;
    private String name;
    private String author;
 
    // 构造函数
    public ConcreteBook(int ID, String name, String author) {
        this.ID = ID;
        this.name = name;
        this.author = author;
    }
 
 
    public void show() {
        System.out.println(ID + "**" + name + "**" + author);
    }
    public boolean isNull(){
        return false;
    }
}

定义工厂类(返回对象从ConcreteBook改为Book,并当ID属于非法值或者不存在时,返回NullBook对象。)
public class BookFactory {
   
    public Book getBook(int ID) {
        Book book;//将原来的ConcreteBook改为Book
        switch (ID) {
        case 1:
            book = new ConcreteBook(ID, "设计模式", "GoF");
            break;
        case 2:
            book = new ConcreteBook(ID, "我的设计模式", "空对象模式");
            break;
        default:
            book = new NullBook();//创建一个NullBook对象
            break;
        }
 
        return book;
    }
}

测试代码
public static void main(String[] args) {
        BookFactory bookFactory = new BookFactory();
        Book book = bookFactory.getBook(-1);
        book.show();
}

这样即使输入的参数不合法,不会出现程序异常,但会提醒用户输入参数不合法。

三、总结
空对象模式的优点
1、它可以加强系统的稳固性,能有有效地防止空指针报错对整个系统的影响,使系统更加稳定。
2、它能够实现对空对象情况的定制化的控制,能够掌握处理空对象的主动权。
3、它并不依靠Client来保证整个系统的稳定运行。
4、它通过isNull对==null的替换,显得更加优雅,更加易懂。

--------------------- 
作者:想作会飞的鱼 
来源:CSDN 
原文:https://blog.csdn.net/xiaokang123456kao/article/details/69676798 
版权声明:本文为博主原创文章,转载请附上博文链接!

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值