Java8特性学习笔记(三) Optional

2021-12-24  本文已影响0人  简单一点点

参考:

简介

Optional 是 Java8 提供的为了解决 null 安全问题的一个 API。善用 Optional 可以使我们代码中很多繁琐的设计变得十分优雅。

示例

为了方便,我们先定义一个简单的实体类 Book。

public class Book {
    
    private String name;
    private float price;

    public Book(String name, float price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

然后看个例子,传统写法如下:

public static String getName(Book book) {
    if (book == null || book.getName() == null)
        return "Unknown";
    return book.getName();
}

使用 Optional 改为链式调用如下:

public static String getName(Book book) {
    return Optional.ofNullable(book)
            .map(user->user.getName())
            .orElse("Unknown");
}

不推荐的写法如下,这其实只是用 isPresent 方法来替代 u==null

public static String getName(Book book) {
    Optional<Book> myBook = Optional.ofNullable(book);
    if (!myBook.isPresent())
        return "Unknown";
    return myBook.get().getName();
}

构造方法

Java 提供三个静态方法来构造一个Optional:

Optional<String> optStr1 = Optional.of("optional");
Optional<String> optStr2 = Optional.ofNullable(null);
Optional<String> optStr = Optional.empty();

API方法

介绍一些经常使用的方法。

get

get()方法主要用于返回包装对象的实际值,但是如果包装对象值为null,会抛出NoSuchElementException异常。

示例:

String name = Optional.ofNullable(book).get().getName(); // book 不能为空

方法源码:

public T get() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

isPresent

isPresent()方法用于判断包装对象的值是否非空。

使用示例:

System.out.println(Optional.ofNullable(book).isPresent()); 

方法源码:

public boolean isPresent() {
    return value != null;
}

ifPresent

ifPresent()方法接受一个Consumer对象(消费函数),如果包装对象的值非空,运行Consumer对象的accept()方法。

示例:

public static void printName(Book book) {
    Optional.ofNullable(book).ifPresent(b ->  System.out.println("The Book name is : " + b.getName()));
}

方法源码:

public void ifPresent(Consumer<? super T> consumer) {
    if (value != null)
        consumer.accept(value);
}

filter

filter() 方法接受参数为 Predicate 对象,用于对 Optional 对象进行过滤,如果符合 Predicate 的条件,返回 Optional 对象本身,否则返回一个空的 Optional 对象。举例如下:

示例:

public static void filterPrice(Book book) {
    Optional.ofNullable(book).filter( b -> b.getPrice() > 10.0).ifPresent(b ->  System.out.println("The book price is more than 10.0."));
}

方法源码:

public Optional<T> filter(Predicate<? super T> predicate) {
    Objects.requireNonNull(predicate);
    if (!isPresent())
        return this;
    else
        return predicate.test(value) ? this : empty();
}

map

map() 方法的参数为 Function(函数式接口)对象,map()方法将 Optional 中的包装对象用 Function 函数进行运算,并包装成新的 Optional 对象(包装对象的类型可能改变)。

public static Optional<Float> getPrice(Book book) {
    return Optional.ofNullable(book).map(u -> u.getPrice());
}

方法源码:

public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Optional.ofNullable(mapper.apply(value));
    }
}

flatMap

跟map()方法不同的是,入参Function函数的返回值类型为 Optional<U> 类型,而不是 U 类型,这样 flatMap() 能将一个二维的Optional对象映射成一个一维的对象。将上例进行faltMap()改写如下:

public static Optional<Float> getPrice(Book book) {
    return Optional.ofNullable(book).flatMap(b -> Optional.ofNullable(b.getPrice()));
}

方法源码:

public<U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
    Objects.requireNonNull(mapper);
    if (!isPresent())
        return empty();
    else {
        return Objects.requireNonNull(mapper.apply(value));
    }
}

orElse

orElse()方法功能比较简单,即如果包装对象值非空,返回包装对象值,否则返回入参other的值(默认值)。

示例:

public static String getName(Book book) {
    return Optional.ofNullable(book)
            .map(user->user.getName())
            .orElse("Unknown");
}

方法源码:

public T orElse(T other) {
    return value != null ? value : other;
}

orElseGet

orElseGet()方法与orElse()方法类似,区别在于orElseGet()方法的入参为一个Supplier对象,用Supplier对象的get()方法的返回值作为默认值。

示例:

public static String getName(Book book) {
    return Optional.ofNullable(book)
            .map(user->user.getName())
            .orElseGet(() -> "Unkown");
}

方法源码:

public T orElseGet(Supplier<? extends T> other) {
    return value != null ? value : other.get();
}

orElseThrow

orElseThrow()方法其实与orElseGet()方法非常相似了,入参都是Supplier对象,只不过orElseThrow()的Supplier对象必须返回一个Throwable异常,并在orElseThrow()中将异常抛出。

示例:

public static String getName(Book book) {
    return Optional.ofNullable(book)
            .map(user->user.getName())
            .orElseThrow(() -> new RuntimeException("Unkown"));
}

方法源码:

public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}
上一篇 下一篇

猜你喜欢

热点阅读