为了程序的健壮性,我们可以使用空对象模式

空对象模式 (null object Pattern)是一种软件设计模式。可以用于返回无意义的对象时,它可以承担处理null的责任。有时候空对象也被视为一种设计模式。

在写代码的时候我们经常会遇到空指针,为了避免空指针的发生需要做一些判断。如果是复杂对象的话,还需要一层层地去判断。这个时候我就无比怀念groovy、kotlin这类语言。可以使用形如:

     user?.address?.name

这样的语法糖,而无需一层层的判断。

google的guava库提供了Optional类,可以有效的判断null对象。

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

guava可以创建指定的null对象

Optional<Integer> nullable=Optional.fromNullable(null);
System.out.println("from Nullable Optional isPresent:"+nullable.isPresent());  //returns from Nullable Optional isPresent:false

在java 8中也新增了Optional类。

同时,我自己也仿照guava的Optional类写了一个简化版的Optional并附上使用方法,它借助了rxjava。

import rx.Observable;

/**
 * 使用方法:
 *      String s = null;
 *      Optional.ofNullable(s).orElse("default")); // 如果s为null,则显示default,否则显示s的值
 * @author Tony Shen
 *
 */
public class Optional<T> {

    Observable<T> obs;

    public Optional(Observable<T> obs) {
        this.obs = obs;
    }

    public static <T> Optional<T> of(T value) {
        if (value == null) {
            throw new NullPointerException();
        } else {
            return new Optional<T>(Observable.just(value));
        }
    }

    public static <T> Optional<T> ofNullable(T value) {
        if (value == null) {
            return new Optional<T>(Observable.<T>empty());
        } else {
            return new Optional<T>(Observable.just(value));
        }
    }

    public T get() {
        return obs.toBlocking().single();
    }

    public T orElse(T defaultValue) {
        return obs.defaultIfEmpty(defaultValue).toBlocking().single();
    }
}

上面讲了那么多,是为了防止空指针出现,现在我们来看看空对象模式具体的使用场景吧,假设我们在代码中使用了链式调用,形如:

client = RestClient.post(request.getUrl())
        .readTimeout(request.getReadTimeoutMillis())
        .connectTimeout(request.getConnectTimeoutMillis())
        .addHeaders(request.getHeaders());

只要某一个环节出现问题,就会有空指针的隐患的。比如RestClient的post()方法内部出现了问题,那就非常严重了,后面整个链路都会断掉,报空指针异常。

那我们如何保证整个链路不断呢?在post()方法里面会调用一个getConnection()方法

    public HttpURLConnection getConnection() {
        if (connection == null)
            connection = createConnection();

        if (connection == null) {
            clientIsNull = true;
            connection = NullConnection.createNull(url);
        }
        return connection;
    }

请注意,在getConnection()方法里会有两个connection == null的判断。理论上,第一次调用createConnection()方法时,connection是不会为空的。但是在使用某个APM sdk时,确实发现有极少的概率connection会为空。如果它为空,那么我们在第二个判断中增加了如下的代码,来保证返回的connection不为null,提高程序的健壮性。

   connection = NullConnection.createNull(url);

我们来看看,NullConnection是怎么回事

/**
 * Created by Tony Shen on 2016/12/6.
 */

public class NullConnection extends HttpURLConnection {

    private NullConnection(URL url) {
        super(url);
    }

    @Override
    public void disconnect() {

    }

    @Override
    public boolean usingProxy() {
        return false;
    }

    @Override
    public void connect() throws IOException {

    }

    public boolean isNull() {
        return true;
    }

    public static NullConnection createNull(URL url) {
        return new NullConnection(url);
    }
}

其实,基本没做啥事,主要多了一个createNull()的方法。它会产生一个NullConnection对象,它的作用是防止产生null,从而保证原先的RestClient链路是正常的。这就是空对象模式。

链式调用,会让代码更加清晰,带给我们的好处是非常明显的。只要我们处理好空指针的隐患,就可以更愉悦地写代码了O(∩_∩)O哈哈~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 11,186评论 6 13
  • __block和__weak修饰符的区别其实是挺明显的:1.__block不管是ARC还是MRC模式下都可以使用,...
    LZM轮回阅读 3,387评论 0 6
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,779评论 18 399
  • 1、定义 2、定义拦截器2.1、定义一个类2.2、拦截器配置2.2.1、 针对某种mapping配置2.2.2、配...
    acooler15阅读 386评论 0 2
  • 我们已经很久没联系了 可我还是一眼就认出了他,在蘑菇街逛着,猛然看见一个男模,我看见了他的眼,有点奇怪,怎么和我蜘...
    星酒儿阅读 347评论 6 2