Java 杂谈java相关技术

Guava学习笔记:Optional优雅的使用null

2018-09-01  本文已影响1人  it_zzy

Guava学习笔记:Optional优雅的使用null


在我们学习和使用Guava的Optional之前,我们需要来了解一下Java中null。因为,只有我们深入的了解了null的相关知识,我们才能更加深入体会领悟到Guava的Optional设计和使用上的优雅和简单。

null代表不确定的对象

Java中,null是一个关键字,用来标识一个不确定的对象。因此可以将null赋给引用类型变量,但不可以将null赋给基本类型变量。

Java中,变量的使用都遵循一个原则:先定义,并且初始化后,才可以使用。例如如下代码中,我们不能定义int age后,不给age指定值,就去打印age的值。这条对对于引用类型变量也是适用的(String name也同样适用),在编译的时候就会提示为初始化。

public class NullTest {
    public static void testNull(){
        int age;
        System.out.println("user age:"+age);
        
        long money;
        money=10L;
        System.out.println("user money"+money);
        
        String name;
        System.out.println("user name:"+name);
    }
}

在Java中,Java默认给变量赋值:在定义变量的时候,如果定义后没有给变量赋值,则Java在运行时会自动给变量赋值。赋值原则是整数类型int、byte、short、long的自动赋值为0,带小数点的float、double自动赋值为0.0,boolean的自动赋值为false,其他各供引用类型变量自动赋值为null。上面代码会变为如下可运行代码:

public class NullTest {
    public static void testNull(){
        int age = 0;
        System.out.println("user Age:"+age);
        
        long money;
        money=10L;
        System.out.println("user money"+money);
        
        String name = null;
        System.out.println("user name:"+name);
    }
}

null本身不是对象,也不是Objcet的实例

null只是一个关键字,用来标识一个不确定的对象,他既不是对象,也不是Objcet对象的实例。下面我们通过代码确定一下null是不是Object对象实例

public class NullTest {
    public static void main(String[] args) {
        testNullObject();
    }
    
    public static void testNullObject() {
        if (null instanceof java.lang.Object) {
            System.out.println("null属于java.lang.Object类型");
        } else {
            System.out.println("null不属于java.lang.Object类型");
        }
    }
}

运行上面代码,输出:null不属于java.lang.Object类型
可见,null对象不是Object对象的实例。

null对象的使用

Connection conn = null;
 try {
  conn = DriverManager.getConnection("url", "user", "password");
 } catch (SQLException e) {
   e.printStackTrace();
 }
 String catalog = conn.getCatalog();
如果刚开始的时候不指定conn = null,则最后一句就会报错。

Guava的Optional

大多数情况下程序员使用null是为了表示某种不存在的意思,也许应该有一个value,但是这个value是空或者这个value找不到。比方说,在用不存在的key值从map中取  value,Map.get返回null表示没有该map中不包含这个key。

若T类型数据可以为null,Optional<T>是用来以非空值替代T数据类型的一种方法。一个Optional对象可以包含一个非空的T引用(这种情况下我们称之为“存在的”)或者不包含任何东西(这种情况下我们称之为“空缺的”)。但Optional从来不会包含对null值的引用。

import com.google.common.base.Optional;

public class OptionalTest {
    
    public void testOptional() throws Exception { 
        Optional<Integer> possible=Optional.of(6);
        if(possible.isPresent()){
            System.out.println("possible isPresent:"+possible.isPresent());
            System.out.println("possible value:"+possible.get());
        }
    } 
}

执行结果如下:

possible isPresent:true
possible value:6

由于这些原因,Guava库设计了Optional来解决null的问题。许多Guava的工具被设计成如果有null值存在即刻报错而不是只要上下文接受处理null值就默认使用null值继续运行。而且,Guava提供了Optional等一些工具让你在不得不使用null值的时候,可以更加简便的使用null并帮助你避免直接使用null。

Optional<T>的最常用价值在于,例如,假设一个方法返回某一个数据类型,调用这个方法的代码来根据这个方法的返回值来做下一步的动作,若该方法可以返回一个null值表示成功,或者表示失败,在这里看来都是意义含糊的,所以使用Optional<T>作为返回值,则后续代码可以通过isPresent()来判断是否返回了期望的值(原本期望返回null或者返回不为null,其意义不清晰),并且可以使用get()来获得实际的返回值。

Optional方法说明和使用实例

import com.google.common.base.Optional;

public class OptionalTest {
    
    @Test
    public void testOptional() throws Exception { 
        Optional<Integer> possible=Optional.of(6);
        Optional<Integer> absentOpt=Optional.absent();
        Optional<Integer> NullableOpt=Optional.fromNullable(null);
        Optional<Integer> NoNullableOpt=Optional.fromNullable(10);
        if(possible.isPresent()){
            System.out.println("possible isPresent:"+possible.isPresent());
            System.out.println("possible value:"+possible.get());
        }
        if(absentOpt.isPresent()){
            System.out.println("absentOpt isPresent:"+absentOpt.isPresent()); ;
        }
        if(NullableOpt.isPresent()){
            System.out.println("fromNullableOpt isPresent:"+NullableOpt.isPresent()); ;
        }
        if(NoNullableOpt.isPresent()){
            System.out.println("NoNullableOpt isPresent:"+NoNullableOpt.isPresent()); ;
        }
    } 
}

运行结果:

possible isPresent:true
possible value:6
NoNullableOpt isPresent:true
import java.util.Set;
import com.google.common.base.Optional;

public class OptionalTest {
    
    public void testMethodReturn() {
        Optional<Long> value = method();
        if(value.isPresent()==true){
            System.out.println("获得返回值: " + value.get());     
        }else{
                
            System.out.println("获得返回值: " + value.or(-12L));    
        }
        
        System.out.println("获得返回值 orNull: " + value.orNull());
        
        Optional<Long> valueNoNull = methodNoNull();
        if(valueNoNull.isPresent()==true){
            Set<Long> set=valueNoNull.asSet();
            System.out.println("获得返回值 set 的 size : " + set.size());    
            System.out.println("获得返回值: " + valueNoNull.get());     
        }else{
            System.out.println("获得返回值: " + valueNoNull.or(-12L));    
        }
        
        System.out.println("获得返回值 orNull: " + valueNoNull.orNull());
    }

    private Optional<Long> method() {
        return Optional.fromNullable(null);
    }
    private Optional<Long> methodNoNull() {
        return Optional.fromNullable(15L);
    }
    
}

运行结果:

获得返回值: -12
获得返回值 orNull: null
获得返回值 set 的 size : 1
获得返回值: 15
获得返回值 orNull: 15

Optional除了给null值命名所带来的代码可阅读性的提高,最大的好处莫过于Optional是傻瓜式的。Optional对象的使用强迫你去积极的思考这样一种情况,如果你想让你的程序返回null值,这null值代表的含义是什么,因为你想要取得返回值,必然从Optional对象内部去获得,所以你必然会这么去思考。但是只是简单的使用一个Null值会很轻易的让人忘记去思索代码所要表达的含义到底是什么,尽管FindBugs有些帮助,但是我们还是认为它并没有尽可能的解决好帮助程序员去思索null值代表的含义这个问题。

这种思考会在你返回某些存在的值或者不存在的值的时候显得特别相关。和其他人一样,你绝对很可能会忘记别人写的方法method(a,b)可能会返回一个null值,就好像当你去写method(a,b)的实现时,你也很可能忘记输入参数a也可以是null。如果返回的是Optional对象,对于调用者来说,就可以忘却怎么去度量null代表的是什么含义,因为他们始终要从optional对象中去获得真正的返回值。

参考:
http://www.cnblogs.com/peida/archive/2013/06/14/Guava_Optional.html

上一篇 下一篇

猜你喜欢

热点阅读