前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于 if (someobject != null) 的问题

关于 if (someobject != null) 的问题

作者头像
四火
发布2022-07-18 13:59:13
4720
发布2022-07-18 13:59:13
举报
文章被收录于专栏:四火的唠叨

下内容来自于在 StackOverflow 上的有一个有趣的讨论,说的话题很小,就是对于这样的对象为空的检查:

代码语言:javascript
复制
if (someobject != null) {
    someobject.doCalc();
}

为了避免空指针异常,看起来也没什么不妥。不过代码里面一片一片的对象是否为空的判断,实在难看。

对象是否为空的契约

通常我们在定义 API 的时候,是遵循一些规矩的,这些规矩可以叫做规约,比如这样的接口:

代码语言:javascript
复制
public Set<String> getCollections();

通常情况下,或者说没有特殊说明的情况下,返回的 set 是不能为 null 的,如果没有元素,应当是一个 EmptySet 才对。接口上下游都遵守这样的规约了,那么一些防御性代码就可以省掉。所以严格来说,返回是否为空,应当加入到 API 的文档中去,在返回为空时,需要声明其特殊意义。对象为空,经常能够表达特殊含义:

代码语言:javascript
复制
public void updateUser(User user);

比如这样的方法,要更新 user 的信息,user 有一个属性 age,类型 Integer,当它为空的时候,表示忽略该属性,不更新。如果使用原语类型 int 就需要使用某种特殊值了,没有 Integer 来得自然。

其他语言的改进

在 Groovy 中,使用问号这样一个语法糖,使得代码判空的逻辑得到最简化:

代码语言:javascript
复制
def streetName = user?.address?.street

上面的代码中,如果 user 为空,是不会访问它的 address 成员的,如果 address 为空,则是不会访问 street 的。

在 Objective C 中,方法调用变成了消息传递机制,在往 nil 传递消息的时候,除了返回 0 并没有什么副作用发生。关于 “空”,在 Objective C 当中有这样四种

NULL 来自于 C 语言的空指针;nil 是一个指向空的对象;Nil 和 nil 类似,只不过它是一个指向空的类;NSNull 是用来解决集合元素没法放空元素的问题的,它就相当于空元素的一个包装,在集合中表示一个空元素。

Scala 中有一个 Option 抽象类,它是强类型的,即 OptionT,这个类型一旦被定义就不能改变。它下面有两个子类,Some 和 None,None 是一个表示空的单例对象,而 Some 存放的是实际结果:

代码语言:javascript
复制
def show(x: Option[String]) = x match {
  case Some(s) => s
  case None => "?"
}

编译期间发现对象为空的问题

JSR 305: Annotations for Software Defect Detection 中,最初来自于 FindBug 和 IntelliJ 的灵感,说白了就是 @NonNull 和 @CheckForNull 这两个注解:

如果有这样的方法定义:

代码语言:javascript
复制
void someMethod(@NotNull someParameter) { }

那么,在调用的时候,这样的代码会直接编译失败的:

代码语言:javascript
复制
someMethod(null);

反之,定义这样的方法:

代码语言:javascript
复制
@Nullable iWantToDestroyEverything() { return null; }

那么这样未经检查的方法调用也会在编译期间失败:

代码语言:javascript
复制
iWantToDestroyEverything().something();

也就是说,在编译时间就找出潜在的 NPE 问题。

对象为空的检查

不需要自己写防御性质的判断语句来处理空对象了。比如 JDK7 的 Objects 对象:

代码语言:javascript
复制
this.child = Objects.requireNonNull(child, "it is empty");

这会在对象不为空时完成赋值语句,对象为空时抛出消息为 “it is empty” 的异常。

Jarkata Commons 的 API 也提供了检查对象是否为空的方法;或者,你可以用 Java 原生的 assert 关键字。

NPE 也受欢迎

比如这样的代码:

代码语言:javascript
复制
public Photo getGirlfriendPhoto() {
    try {
        return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().getName());
    } catch (NullPointerException e) {
        return null;
    }
}

如果要避免 NPE,就可能会写成类似这样的代码:

代码语言:javascript
复制
public Photo getGirlfriendPhoto() {
    if(appContext != null) {
    	if(appContext.getPhotoDataSource() != null) {
    		if(me != null) {
    			if(me.getGirlfriend() != null) {
    				if(me.getGirlfriend().getName() != null){
    					// finally we are arrived
    					return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().getName());
    				}
    			}
    		}
    	}
    }

    return null;
}

原帖中还有对空对象模式的讨论等等,话题虽小,也挺有趣的。

文章未经特殊标明皆为本人原创,未经许可不得用于任何商业用途,转载请保持完整性并注明来源链接 《四火的唠叨》

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档