Google Guava 快速入门 —— 【基础】Optional 类

Google Guava 快速入门.jpg

Guava Optional 类

Optional 用于包含非空对象的不可变对象。 Optional对象,用于不存在值表示null。这个类有各种实用的方法,以方便代码来处理为可用或不可用,而不是检查null值。

一、类声明

以下是 com.google.common.base.Optional<T> 类的声明:

@GwtCompatible(serializable = true)
public abstract class Optional<T> implements Serializable

二、类方法

官方文档:https://google.github.io/guava/releases/27.0.1-jre/api/docs/com/google/common/base/Optional.html

方法类型方法描述
static <T> Optional<T>absent() 
返回没有包含引用的Optional实例。
abstract Set<T>asSet() 
返回一个不可变的单集的唯一元素所包含的实例(如果存在),否则为一个空的不可变的集合。
abstract booleanequals(@Nullable Object object) 
如果object是Optional实例,并且包含的引用彼此相等或两者都不存在,则返回true.
static <T> @Nullable Optional<T>fromJavaUtil(Optional<T> javaUtilOptional) 
返回给定的java.util.Optional,等效com.google.common.base.Optional值,如果参数为null,则返回null
static <T> Optional<T>fromNullable(T nullableReference) 
如果 nullableReference 非null,返回包含该引用的Optional实例,否则返回 absent().
abstract Tget() 
返回必须存在的实例.
abstract inthashCode() 
返回此实例的哈希码。
abstract booleanisPresent() 
如果包含(非null)实例,则返回true。
static <T> Optional<T>of(T reference) 
返回包含给定非null引用的Optional实例。
abstract Optional<T>or(Optional<? extends T> secondChoice) 
如果它有一个值存在,返回Optional,否则返回secondChoice。
abstract Tor(Supplier<? extends T> supplier) 
如果包含实例,则返回该实例,否则返回supplier.get()
abstract Tor(T defaultValue) 
如果包含实例,则返回该实例,否则返回 defaultValue 默认值。
abstract TorNull() 
返回包含的实例(如果存在),否则返回null。
static <T> Iterable<T>presentInstances(Iterable<? extends Optional<? extends T>> optionals) 
从提供的选项中返回每个当前实例的值,按顺序跳过absent()的出现次数。
Optional<T>toJavaUtil() 
返回 java.util.Optional 等效值
static <T> Optional<T>toJavaUtil(@Nullable Optional<T> googleOptional) 
返回给定com.google.common.base.Optional的等效java.util.Optional值,如果参数为null,则返回null。
abstract StringtoString() 
返回此实例的字符串表示形式。
abstract <V> Optional<V>transform(Function<? super T,V> function) 
如果实例存在,则使用给定的函数进行转换; 否则返回 absent()

三、Optional示例

import com.google.common.base.Optional;

public class OptionalDemo {
    public static void main(String args[]) {
        OptionalDemo demo = new OptionalDemo();

        Integer value1 = null;
        Integer value2 = new Integer(10);

        // Optional.fromNullable:允许参数为null.
        Optional<Integer> a = Optional.fromNullable(value1);
        // Optional.of:如果参数为null,则抛出NullPointerException
        Optional<Integer> b = Optional.of(value2);

        System.out.println(demo.sum(a, b));
    }

    public Integer sum(Optional<Integer> a, Optional<Integer> b) {
        // Optional.isPresent:检查值是否存在
        System.out.println("First parameter is present: " + a.isPresent());
        System.out.println("Second parameter is present: " + b.isPresent());

        // Optional.or:如果存在则返回值,否则返回传递的默认值
        Integer value1 = a.or(new Integer(0));

        // Optional.get:获取值,此时有值存在
        Integer value2 = b.get();

        return value1 + value2;
    }
}

执行结果

First parameter is present: false
Second parameter is present: true
10

四、使用 Optional 的意义在哪儿?

使用 Optional 除了赋予 null 语义,增加了可读性,最大的优点在于它是一种傻瓜式的防护。Optional 迫使你积极思考引用缺失的情况,因为你必须显式地从 Optional 获取引用。直接使用 null 很容易让人忘掉某些情形,尽管 FindBugs 可以帮助查找 null 相关的问题,但是我们还是认为它并不能准确地定位问题根源。

如同输入参数,方法的返回值也可能是 null。和其他人一样,你绝对很可能会忘记别人写的方法 method(a,b) 会返回一个 null,就好像当你实现 method(a,b) 时,也很可能忘记输入参数 a 可以为 null。将方法的返回类型指定为 Optional,也可以迫使调用者思考返回的引用缺失的情形。

五、其他处理 null 的便利方法

当你需要用一个默认值来替换可能的 null,请使用 Objects.firstNonNull(T, T)方法。如果两个值都是 null,该方法会抛出 NullPointerException。Optional 也是一个比较好的替代方案,例如:Optional.of(first).or(second).

还有其它一些方法专门处理null或空字符串:Strings.emptyToNull(String)Strings.nullToEmpty(String)Strings.isNullOrEmpty(String)。我们想要强调的是,这些方法主要用来与混淆 null/空 的API进行交互。当每次你写下混淆 null/空 的代码时,Guava团队都泪流满面。(好的做法是积极地把null和空区分开,以表示不同的含义,在代码中把null和空同等对待是一种令人不安的坏味道。

六、测试类

package com.example.guava;

import com.google.common.base.*;
import com.google.common.collect.ImmutableList;
import junit.framework.TestCase;

import java.util.Collections;
import java.util.List;
import java.util.Set;

import static com.google.common.truth.Truth.assertThat;

public class OptionalTests extends TestCase {

    /**
     * 1、toJavaUtil 静态
     */
    public void testToJavaUtil_static() {
        Optional<String> str = Optional.of("abc");

        assertNull(Optional.toJavaUtil(null));
        assertEquals("abc", Optional.toJavaUtil(str).get());
        assertEquals(java.util.Optional.empty(), Optional.toJavaUtil(Optional.absent()));
        assertEquals(java.util.Optional.of("abc"), Optional.toJavaUtil(Optional.of("abc")));
    }

    /**
     * 2、toJavaUtil 实例
     */
    public void testToJavaUtil_instance() {
        assertEquals(java.util.Optional.empty(), Optional.absent().toJavaUtil());
        assertEquals(java.util.Optional.of("abc"), Optional.of("abc").toJavaUtil());
    }

    /**
     * 3、fromJavaUtil
     */
    public void testFromJavaUtil() {
        assertNull(Optional.fromJavaUtil(null));
        assertEquals(Optional.absent(), Optional.fromJavaUtil(java.util.Optional.empty()));
        assertEquals(Optional.of("abc"), Optional.fromJavaUtil(java.util.Optional.of("abc")));
    }

    /**
     * 4、absent
     */
    public void testAbsent() {
        Optional<String> optionalName = Optional.absent();
        assertFalse(optionalName.isPresent());

        // 异常
        try {
            optionalName.get();
            fail();
        } catch (IllegalStateException expected) {
        }
    }

    /**
     * 5、of
     */
    public void testOf() {
        assertEquals("tingfeng", Optional.of("tingfeng").get());

        // 空指针异常
        try {
            Optional.of(null);
            fail();
        } catch (NullPointerException expected) {
        }
    }

    /**
     * 6、fromNullable 取值
     */
    public void testFromNullable() {
        Optional<String> optionalName = Optional.fromNullable("tingfeng");
        assertEquals("tingfeng", optionalName.get());
    }

    public void testFromNullable_null() {
        System.out.println(Optional.absent());              // Optional.absent()
        System.out.println(Optional.fromNullable(null));    // Optional.absent()
        assertSame(Optional.absent(), Optional.fromNullable(null));
    }

    /**
     * 7、isPresent 判断
     */
    public void testIsPresent() {
        assertFalse(Optional.absent().isPresent());
        assertTrue(Optional.of("tingfeng").isPresent());
    }

    /**
     * 8、get - or 取值
     */
    public void testGet_present() {
        assertEquals("training", Optional.of("training").get());
    }

    public void testOr_T_present() {
        assertEquals("a", Optional.of("a").or("default"));
    }

    public void testOr_T_absent() {
        assertEquals("default", Optional.absent().or("default"));
    }

    public void testOr_supplier_present() {
        assertEquals("a", Optional.of("a").or(Suppliers.ofInstance("fallback")));
    }

    public void testOr_supplier_absent() {
        assertEquals("fallback", Optional.absent().or(Suppliers.ofInstance("fallback")));
    }

    public void testOr_nullSupplier_absent() {
        Supplier<Object> nullSupplier = Suppliers.ofInstance(null);
        Optional<Object> absentOptional = Optional.absent();
        try {
            absentOptional.or(nullSupplier);
            fail();
        } catch (NullPointerException expected) {
        }
    }

    public void testOr_nullSupplier_present() {
        Supplier<String> nullSupplier = Suppliers.ofInstance(null);
        assertEquals("a", Optional.of("a").or(nullSupplier));
    }

    public void testOr_Optional_present() {
        assertEquals(Optional.of("a"), Optional.of("a").or(Optional.of("fallback")));
    }

    public void testOr_Optional_absent() {
        assertEquals(Optional.of("fallback"), Optional.absent().or(Optional.of("fallback")));
    }

    public void testOrNull_present() {
        assertEquals("a", Optional.of("a").orNull());
    }

    public void testOrNull_absent() {
        assertNull(Optional.absent().orNull());
    }

    /**
     * 9、asSet 只读集合对象
     */
    public void testAsSet_present() {
        Set<String> expected = Collections.singleton("a");
        assertEquals(expected, Optional.of("a").asSet());
    }

    public void testAsSet_absent() {
        assertTrue("Returned set should be empty", Optional.absent().asSet().isEmpty());
    }

    public void testAsSet_presentIsImmutable() {
        Set<String> presentAsSet = Optional.of("a").asSet();
        try {
            presentAsSet.add("b");
            fail();
        } catch (UnsupportedOperationException expected) {
        }
    }

    public void testAsSet_absentIsImmutable() {
        Set<Object> absentAsSet = Optional.absent().asSet();
        try {
            absentAsSet.add("foo");
            fail();
        } catch (UnsupportedOperationException expected) {
        }
    }

    /**
     * 10、transform 转换
     */
    public void testTransform_absent() {
        assertEquals(Optional.absent(), Optional.absent().transform(Functions.identity()));
        assertEquals(Optional.absent(), Optional.absent().transform(Functions.toStringFunction()));
    }

    public void testTransform_presentIdentity() {
        assertEquals(Optional.of("a"), Optional.of("a").transform(Functions.identity()));
    }

    public void testTransform_presentToString() {
        // 转换类型
        assertEquals(Optional.of("42"), Optional.of(42).transform(Functions.toStringFunction()));
    }

    public void testTransform_present_functionReturnsNull() {
        try {
            Optional<String> unused =
                    Optional.of("a")
                            .transform(
                                    new Function<String, String>() {
                                        @Override
                                        public String apply(String input) {
                                            return null;
                                        }
                                    });
            System.out.println(unused);
            fail("Should throw if Function returns null.");
        } catch (NullPointerException expected) {
            expected.printStackTrace();
        }
    }

    public void testTransform_absent_functionReturnsNull() {
        assertEquals(
                Optional.absent(),
                Optional.absent()
                        .transform(
                                new Function<Object, Object>() {
                                    @Override
                                    public Object apply(Object input) {
                                        return null;
                                    }
                                }));
    }

    /**
     * 11、toString
     */
    public void testToString_absent() {
        assertEquals("Optional.absent()", Optional.absent().toString());
    }

    public void testToString_present() {
        assertEquals("Optional.of(training)", Optional.of("training").toString());
    }

    /**
     * 12、presentInstances
     */
    public void testPresentInstances_allPresent() {
        List<Optional<String>> optionals = ImmutableList.of(Optional.of("a"), Optional.of("b"), Optional.of("c"));
        assertThat(Optional.presentInstances(optionals)).containsExactly("a", "b", "c").inOrder();
    }

    public void testPresentInstances_allAbsent() {
        List<Optional<Object>> optionals = ImmutableList.of(Optional.absent(), Optional.absent());
        assertThat(Optional.presentInstances(optionals)).isEmpty();
    }

    public void testPresentInstances_somePresent() {
        List<Optional<String>> optionals = ImmutableList.of(Optional.of("a"), Optional.absent(), Optional.of("c"));
        assertThat(Optional.presentInstances(optionals)).containsExactly("a", "c").inOrder();
    }

    public void testPresentInstances_callingIteratorTwice() {
        List<Optional<String>> optionals = ImmutableList.of(Optional.of("a"), Optional.<String>absent(), Optional.of("c"));
        Iterable<String> onlyPresent = Optional.presentInstances(optionals);
        assertThat(onlyPresent).containsExactly("a", "c").inOrder();
    }

    public void testPresentInstances_wildcards() {
        List<Optional<? extends Number>> optionals = ImmutableList.<Optional<? extends Number>>of(Optional.<Double>absent(), Optional.of(2));
        Iterable<Number> onlyPresent = Optional.presentInstances(optionals);
        assertThat(onlyPresent).containsExactly(2).inOrder();
    }

}

七、相关文章



未经允许请勿转载:程序喵 » Google Guava 快速入门 —— 【基础】Optional 类

点  赞 (2) 打  赏
分享到: