前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JDK8系列之Optional API应该怎样用?

JDK8系列之Optional API应该怎样用?

作者头像
SmileNicky
发布2021-07-23 16:07:25
3310
发布2021-07-23 16:07:25
举报
文章被收录于专栏:Nicky's blogNicky's blog

JDK8系列之Optional API应该怎样用?

1、Optional的简单介绍

前面的章节的学习中,我们学习了jdk8的新特性,lambada表达式、方法引用、函数式接口等等,接着本博客继续JDK8的一个比较重要的特性,JDK8中Optional,jdk8设计这个Optional的目的就是为了避免开发中很常见的NullPointerException

Optional 是 Java 实现函数式编程的保障一步,并且帮助在范式中实现

2、为什么Optional可以避免空指针?

看下Optional源码,为什么Optional可以避免NullPointerException?里面可以找到如下代码:

代码语言:javascript
复制
/**
     * Returns an {@code Optional} describing the specified value, if non-null,
     * otherwise returns an empty {@code Optional}.
     *
     * @param <T> the class of the value
     * @param value the possibly-null value to describe
     * @return an {@code Optional} with a present value if the specified value
     * is non-null, otherwise an empty {@code Optional}
     */
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

	//...
	public static<T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

value值为null的情况,返回empty(),其实也就是返回一个Optional对象,如下代码,直接new Optional<>()

代码语言:javascript
复制
   /**
     * Common instance for {@code empty()}.
     */
    private static final Optional<?> EMPTY = new Optional<>();

而另外一个方法Optional.of()

代码语言:javascript
复制
 /**
  * Returns an {@code Optional} with the specified present non-null value.
   *
   * @param <T> the class of the value
   * @param value the value to be present, which must be non-null
   * @return an {@code Optional} with the value present
   * @throws NullPointerException if value is null
   */
  public static <T> Optional<T> of(T value) {
      return new Optional<>(value);
  }

next,可以看出如果传入T value的值为null,还是有空指针异常的

代码语言:javascript
复制
 private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

3、创建Optional实例

  • 使用 empty() 方法创建一个空的 Optional。
代码语言:javascript
复制
 // 使用 empty() 方法创建一个空的 Optional
Optional<User> empOpt = Optional.empty();
  empOpt.get();
  • 使用 of() 方法创建包含值的 Optional,不可以传入一个null值
代码语言:javascript
复制
User user = new User();
Optional<User> opt = Optional.of(user);
  • 使用 ofNullable() 方法创建包含值的 Optional,可以传入一个null值
代码语言:javascript
复制
User userObj = null;
Optional<User> userOptional = Optional.ofNullable(userObj);

4、访问 Optional 对象的值

获取Optional对象的值,使用 get() 方法获取值

代码语言:javascript
复制
String name = "jack";
Optional<String> strOpt = Optional.ofNullable(name);
String getStr = strOpt.get();
System.out.println(getStr);

看起来是很正常的,如果传入一个null值,会抛异常java.util.NoSuchElementException: No value present,所以需要使用ifPresent,避免userInfo值为null的情况

代码语言:javascript
复制
 City city = new City("上海");
Address address = new Address("200000",city);
  User userInfo = new User("jack", "15588899988" , "123@foxmail.com", address);
  Optional.ofNullable(userInfo).ifPresent(us -> System.out.println(us.toString()));
  • isPresent不建议这样写,语法上来说,也是可以的,不过设计者的目的是使用表达式语言简洁java语法
代码语言:javascript
复制
Optional<User> userOptiion = Optional.ofNullable(userInfo);
if (userOptiion.isPresent()) {
    User userInfomation = userOptiion.get();
}

5、Optional返回默认值

  • 使用 orElse() 返回默认值,如果有值则返回该值,没数据返回默认值
代码语言:javascript
复制
 //使用 orElse() 返回默认值,如果有值则返回该值,没数据返回默认值
User tUser = null;
 System.out.println("using orElse");
 tUser = Optional.ofNullable(tUser).orElse(defaultUserInfo());
 System.out.println("default user information:"+tUser.toString());
  • 使用 orElseGet() 返回默认值 ,这个方法会在有值的时候返回值,如果没有值,它会执行作为参数传入的 Supplier(供应者) 函数式接口
代码语言:javascript
复制
 User teUser = null;
System.out.println("using orElseGet");
 teUser = Optional.ofNullable(teUser).orElseGet(() -> defaultUserInfo());
 System.out.println("default user information:"+teUser.toString());

defaultUserInfo,返回默认用户数据

代码语言:javascript
复制
 protected static User defaultUserInfo(){
    System.out.println("create default user information!");
    City city = new City("上海");
    Address address = new Address("200000",city);
    User userInfo = new User("jack", "15588899988" , "123@foxmail.com", address);
    return userInfo;
}

乍一看,这两个方法的作用好像都一样?有什么区别?还是通过例子进行验证:

①、传入的value值为null的情况,对比orElse、orElseGet

代码语言:javascript
复制
User tUser = null;
System.out.println("using orElse");
tUser = Optional.ofNullable(tUser).orElse(defaultUserInfo());
System.out.println("default user information:"+tUser.toString());

User teUser = null;
System.out.println("using orElseGet");
teUser = Optional.ofNullable(teUser).orElseGet(() -> defaultUserInfo());
System.out.println("default user information:"+teUser.toString());

可以看出,orElse、orElseGet都调用了默认方法

using orElse create default user information! using orElseGet create default user information!

②、传入的value不为null的情况,可以看出orElse还是调用了默认方法,而orElseGet没有调用默认方法

代码语言:javascript
复制
 User tUser = new User("jack", "15588899988" , "123@foxmail.com", address);
System.out.println("using orElse");
 tUser = Optional.ofNullable(tUser).orElse(defaultUserInfo());
 System.out.println("default user information:"+tUser.toString());
      
User teUser = new User("jack", "15588899988" , "123@foxmail.com", address);
System.out.println("using orElseGet");
teUser = Optional.ofNullable(teUser).orElseGet(() -> defaultUserInfo());
System.out.println("default user information:"+teUser.toString());

using orElse create default user information! using orElseGet

ok,从例子就可以很明显得看出区别,orElse、orElseGet在传入的值为null的情况,都调用了默认方法。在传入的值不为null的情况,orElse调用了默认方法,而orElseGet没有调用默认方法

6、Optional返回异常

Optional 还定义了 orElseThrow() API,它会在对象为空的时候抛出异常,而不是返回备选的值

代码语言:javascript
复制
 User u = null;
 User userData = Optional.ofNullable(u).orElseThrow(() -> new IllegalArgumentException());

7、Optional转换值

用于转换数据的,可以使用 map() 方法转换 Optional 的值

map例子:

代码语言:javascript
复制
User us = new User("tom", "15588899988" , "123@foxmail.com", null,"");
String email = Optional.ofNullable(us).map(userInfor -> userInfor.getEmail()).orElse("defaulEmail@foxmail.com");

如果类中的数据是用Optional进行封装的,如下:

代码语言:javascript
复制
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.Accessors;

import java.util.Optional;

@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
  	// ...
    private String position;
    public Optional<String> getPosition() {
        return Optional.ofNullable(position);
    }
}

用 flatMap() 时,用它作为参数,返回的值是解除包装的 String 值

代码语言:javascript
复制
String position = Optional.ofNullable(us).flatMap(use -> use.getPosition()).orElse("default");

8、Optional过滤值

除了转换值之外,Optional 类也提供了按条件“过滤”值的方法filter,filter() 接受一个 Predicate 参数

代码语言:javascript
复制
Optional<User> uoptional = Optional.ofNullable(us).filter(euser -> euser.getEmail()!=null && euser.getEmail().contains("@"));
System.out.println(uoptional.get().toString());

9、典型的Optional例子

用一个嵌套调用的典型例子:

代码语言:javascript
复制
@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class User {
    private String name;
    private String mobiTel;
    private String email;
    private Address address;
    private String position;
    public Optional<String> getPosition() {
        return Optional.ofNullable(position);
    }
}



@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Address {

    private String emailCode;
    private City city;

}

@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class City {
    private String cityName;

}

画图表示类关系:

在这里插入图片描述
在这里插入图片描述

uml类图:

在这里插入图片描述
在这里插入图片描述

jdk7写法:

代码语言:javascript
复制
/**
 * the example of jdk7 getCityName .<br>
 * @Author  nicky.ma
 * @Date 2021/07/20 14:39
 * @Param [user]
 * @return java.lang.String
 */
protected static String getCityName(User user) {
    if (user != null) {
        Address address = user.getAddress();
        if (address != null) {
            City city = address.getCity();
            if (city != null) {
                return city.getCityName();
            }
        }
    }
    throw new IllegalArgumentException("取值错误");
}

jdk8写法:

代码语言:javascript
复制
/**
  * the example of jdk8 getCityName .<br>
  * @Author nicky.ma
  * @Date 2021/07/20 14:38
  * @Param [user]
  * @return java.lang.String
  */
 protected static String obtainCityName(User user) {
     return Optional.ofNullable(user)
             .map(u -> u.getAddress())
             .map(a -> a.getCity())
             .map(c -> c.getCityName())
             .orElseThrow(() -> new IllegalArgumentException("取值错误"));
 }

10、附录参考资料

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-07-20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • JDK8系列之Optional API应该怎样用?
  • 1、Optional的简单介绍
  • 2、为什么Optional可以避免空指针?
  • 3、创建Optional实例
  • 4、访问 Optional 对象的值
  • 5、Optional返回默认值
  • 6、Optional返回异常
  • 7、Optional转换值
  • 8、Optional过滤值
  • 9、典型的Optional例子
  • 10、附录参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档