前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java8新特性:Optional类的正确使用姿势

Java8新特性:Optional类的正确使用姿势

作者头像
南风
发布2019-08-01 10:51:23
9140
发布2019-08-01 10:51:23
举报
文章被收录于专栏:Java大联盟Java大联盟

空指针异常是我们在实际开发中经常会遇到的问题,为了防止程序因为异常而中断,通常要在代码中添加大量的非空验证,例如一个释放 JDBC 相关资源的代码,如下所示。

代码语言:javascript
复制
public static void release(Connection conn,Statement stmt,ResultSet rs) {
  try {
    if(conn != null) {
      conn.close();
    }
    if(stmt != null) {
      stmt.close();
    }
    if(rs != null) {
      rs.close();
    }
  } catch (SQLException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
  }
}

上述代码中的非空验证并没有多少技术含量,同时会使代码显得臃肿不堪,为了解决这类问题,Java8 引入了 Optional 类,Optional 就是一个容器,它可以保存任意数据类型的值,包括 null,开发者无需进行空值检测,Optional 类的引入很好的解决了实际开发中的空指针异常问题,接下来我们来详细学习 Optional 类的使用。

Optional 常用方法

1、empty(),返回一个空的 Optional 对象,定义如下所示。

代码语言:javascript
复制
public static<T> Optional<T> empty() {
  @SuppressWarnings("unchecked")
  Optional<T> t = (Optional<T>) EMPTY;
  return t;
}

具体操作如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Optional optional = Optional.empty();
        System.out.println(optional);
    }
}

运行结果如下图所示。

2、of(T value),根据传入的 value 创建一个 Optional 对象,定义如下所示。

代码语言:javascript
复制
public static <T> Optional<T> of(T value) {
  return new Optional<>(value);
}

具体操作如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Optional optional = Optional.of("Hello World");
        System.out.println(optional);
    }
}

运行结果如下图所示。

可以看到输出的结果是 Optional[Hello World],如果要取出 Hello World 直接调用 get 方法即可,如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Optional optional = Optional.of("Hello World");
        System.out.println(optional.get());
    }
}

但是需要注意的是,of 方法不能传 null,否则会抛出空指针异常,如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Optional optional = Optional.of(null);
        System.out.println(optional);
    }
}

3、ofNullable(T value),和 of(T value) 方法类似,都是用来创建 Optional 对象的,区别在于 ofNullable(T value) 方法可以传 null,定义如下所示。

代码语言:javascript
复制
public static <T> Optional<T> ofNullable(T value) {
  return value == null ? empty() : of(value);
}

具体操作如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Optional optional = Optional.ofNullable(null);
        System.out.println(optional);
    }
}

运行结果如下图所示。

4、get(),返回 Optional 中存储的任意类型值,如果 Optional 中的值为 null,则抛出 java.util.NoSuchElementException,定义如下所示。

代码语言:javascript
复制
public T get() {
  if (value == null) {
    throw new NoSuchElementException("No value present");
  }
  return value;
}

具体操作如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Optional optional = Optional.ofNullable("Hello World");
        System.out.println(optional.get());
        optional = Optional.ofNullable(100);
        System.out.println(optional.get());
        Integer[] array = {1,2,3,4,5,6};
        optional = Optional.ofNullable(array);
        System.out.println(optional.get());
    }
}

运行结果如下图所示。

如果是下面这种情况,直接抛出 java.util.NoSuchElementException 异常。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Optional optional = Optional.ofNullable(null);
        System.out.println(optional.get());
    }
}

5、isPresent(),判断 Optional 存储的值是否存在,返回 true 表示有值,false 表示值不存在,定义如下所示。

代码语言:javascript
复制
public boolean isPresent() {
  return value != null;
}

具体使用如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Optional optional = Optional.ofNullable("Hello World");
        System.out.println(optional.isPresent());
        optional = Optional.ofNullable(null);
        System.out.println(optional.isPresent());
    }
}

运行结果如下图所示。

6、ifPresent(Consumer<? super T> consumer),如果值存在,执行 Consumer 的具体操作,如果值不存在,不做任何操作,定义如下所示。

代码语言:javascript
复制
public void ifPresent(Consumer<? super T> action) {
  if (value != null) {
    action.accept(value);
  }
}

具体操作如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        //值存在
        List<Integer> list = Arrays.asList(1,2,3,4,5,6);
        Optional optional = Optional.ofNullable(list);
        System.out.print("值存在:");
        optional.ifPresent(System.out::println);
        //值不存在
        optional = Optional.ofNullable(null);
        System.out.print("值不存在:");
        optional.ifPresent((str)-> System.out.println(str));
    }
}

运行结果如下图所示。

7、ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction),如果值存在,执行 Consumer 的具体操作,如果值不存在,执行 emptyAction 的具体操作,定义如下所示。

代码语言:javascript
复制
public void ifPresentOrElse(Consumer<? super T> action, Runnable emptyAction) {
  if (value != null) {
    action.accept(value);
  } else {
    emptyAction.run();
  }
}

具体操作如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        //值存在
        List<Integer> list = Arrays.asList(1,2,3,4,5,6);
        Optional optional = Optional.ofNullable(list);
        System.out.print("值存在:");
        optional.ifPresentOrElse(System.out::println,()-> System.out.println("value is null"));
        //值不存在
        optional = Optional.ofNullable(null);
        System.out.print("值不存在:");
        optional.ifPresentOrElse(System.out::println,()-> System.out.println("value is null"));
    }
}

运行结果如下图所示。

8、filter(Predicate<? super T> predicate),根据传入的 Predicate 对 Optional 中的值进行过滤,满足条件则返回该 Optional 对象,否则返回一个空的 Optional,定义如下所示。

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

具体操作如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Optional optional = Optional.ofNullable(1);
        Predicate<Integer> predicate = num -> num >= 3;
        System.out.println(optional.filter(predicate));
        predicate = num -> num < 3;
        System.out.println(optional.filter(predicate));
    }
}

运行结果如下图所示。

9、map(Function<? super T, ? extends U> mapper),如果 Optional 有值,则执行 mapper 映射函数,并获取其返回值,如果返回值不为 null,则返回一个包含返回值的 Optional 对象,否则返回一个空的 Optional 对象,定义如下所示。

代码语言:javascript
复制
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));
  }
}

具体操作如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        ClassB classB = new ClassB();
        ClassA classA = new ClassA();
        classA.setClassB(classB);
        Optional optional = Optional.ofNullable(classA)
        .map((classA1)->classA1.getClassB());
        System.out.println(optional);
    }
}

class ClassA {
    private ClassB classB;

    public ClassB getClassB() {
        return classB;
    }

    public void setClassB(ClassB classB) {
        this.classB = classB;
    }
}

class ClassB {

}

上述代码表示如果 classA 中包含 classB,则直接返回一个 Optional[ClassB] 对象,否则返回一个空的 Optional 对象,运行结果如下图所示。

对上述代码进行修改,删除 classA.setClassB(classB); 如下所示。

代码语言:javascript
复制
ClassB classB = new ClassB();
ClassA classA = new ClassA();
Optional optional = Optional.ofNullable(classA)
  .map((classA1)->classA1.getClassB());
System.out.println(optional);

运行结果如下图所示。

这里需要注意的是 map 方法的调用必须和 Optional 的创建连起来写,如下所示。

代码语言:javascript
复制
Optional optional = Optional.ofNullable(classA).map((classA1)->classA1.getClassB());

不能分开写,错误写法如下所示。

代码语言:javascript
复制
Optional optional = Optional.ofNullable(classA);
optional.map((classA1)->classA1.getClassB());

10、flatMap(Function<? super T, ? extends Optional<? extends U>> mapper),功能与 map 类似,区别在于 map 的 mapper 映射函数可返回任意数据类型,但是 flatMap 的 mapper 映射函数只能返回 Optional 类型,定义如下所示。

代码语言:javascript
复制
public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper) {
  Objects.requireNonNull(mapper);
  if (!isPresent()) {
    return empty();
  } else {
    @SuppressWarnings("unchecked")
    Optional<U> r = (Optional<U>) mapper.apply(value);
    return Objects.requireNonNull(r);
  }
}

具体操作如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        ClassB classB = new ClassB();
        ClassA classA = new ClassA();
        classA.setClassB(classB);
        Optional optional = Optional.ofNullable(classA)
        .flatMap((classA1)->{
            return Optional.ofNullable(classA1.getClassB());
        });
        System.out.println(optional);
    }
}

运行结果如下图所示。

11、orElse(T other),如果 Optional 的值存在则返回,否则返回 other,定义如下所示。

代码语言:javascript
复制
public T orElse(T other) {
    return value != null ? value : other;
}

具体操作如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Optional optional = Optional.ofNullable(1);
        System.out.println(optional.orElse("value is null"));
        optional = Optional.ofNullable(null);
        System.out.println(optional.orElse("value is null"));
    }
}

运行结果如下图所示。

12、orElseGet(Supplier<? extends T> supplier),功能与 orElse 类似,区别在于 orElse 可直接返回某个值,orElseGet 需要执行 supplier,并返回其结果,多了一个步骤,定义如下所示。

代码语言:javascript
复制
public T orElseGet(Supplier<? extends T> supplier) {
    return value != null ? value : supplier.get();
}

具体操作如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Optional optional = Optional.ofNullable(1);
        System.out.println(optional.orElseGet(()->"value is null"));
        optional = Optional.ofNullable(null);
        System.out.println(optional.orElseGet(()->"value is null"));
    }
}

运行结果如下图所示。

13、orElseThrow(),如果值存在则返回,否则抛出 NoSuchElementException,定义如下所示。

代码语言:javascript
复制
public T orElseThrow() {
    if (value == null) {
        throw new NoSuchElementException("No value present");
    }
    return value;
}

具体操作如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Optional optional = Optional.ofNullable(1);
        System.out.println(optional.orElseThrow());
        optional = Optional.ofNullable(null);
        System.out.println(optional.orElseThrow());
    }
}

运行结果如下图所示。

14、orElseThrow(Supplier<? extends X> exceptionSupplier),功能与 orElseThrow 类似,如果值存在则返回,否则抛出 exceptionSupplier 返回的异常,定义如下所示。

代码语言:javascript
复制
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
    if (value != null) {
        return value;
    } else {
        throw exceptionSupplier.get();
    }
}

具体操作如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Optional optional = Optional.ofNullable(1);
        try {
            System.out.println(optional.orElseThrow(()->{throw new IllegalStateException();}));
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        optional = Optional.ofNullable(null);
        try {
            System.out.println(optional.orElseThrow(()->{throw new IllegalStateException();}));
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
    }
}

运行结果如下图所示。

上面详细介绍了 Optional 类的各种方法,接下来我们结合实际案例,来看看实际开发中使用 Optional 的优势。

实际案例

我们来设置一个客户订单查询场景。

1、定义 3 个类 Consumer、Order、Product,其中 Consumer 包含 Order,Order 包含 Product,具体代码如下所示。

代码语言:javascript
复制
public class Consumer {
    private Order order;

    public Order getOrder() {
        return order;
    }

    public void setOrder(Order order) {
        this.order = order;
    }
}


public class Order {
    private Product product;

    public Product getProduct() {
        return product;
    }

    public void setProduct(Product product) {
        this.product = product;
    }
}


public class Product {
    private String name;

    public String getName() {
        return name;
    }

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

2、分别创建 Consumer、Order、Product 对象,并完成级联,然后定义返回 Consumer 中 ProductName 的方法,传统的开发方式需要对涉及到的对象都进行非空验证,如下所示。

代码语言:javascript
复制
public class Test {
    public static void main(String[] args) {
        Product product = new Product();
        product.setName("电脑");
        Order order = new Order();
        order.setProduct(product);
        Consumer consumer = new Consumer();
        consumer.setOrder(order);

        System.out.println(getProductName(consumer));
    }

    public static String getProductName(Consumer consumer){
        if(consumer != null){
            Order order = consumer.getOrder();
            if(order != null){
                Product product = order.getProduct();
                if(product != null){
                    return product.getName();
                }
            }
        }
        return null;
    }

}

3、使用 Optional 类对上述代码进行修改,可以将代码变得更加简洁、优雅,不需要一层一层的写非空判断,可直接完成链式调用,如下所示。

代码语言:javascript
复制
public static String getProductName(Consumer consumer){
  return Optional.ofNullable(consumer)
    .map(consumer1 -> consumer1.getOrder())
    .map(order -> order.getProduct())
    .map(product -> product.getName())
    .orElse(null);
}

4、运行结果如下图所示。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java大联盟 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档