IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> JDK8系列之Optional API应该怎样用? -> 正文阅读

[Java知识库]JDK8系列之Optional API应该怎样用?

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

1、Optional的简单介绍

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

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

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

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

/**
     * 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<>()

   /**
     * Common instance for {@code empty()}.
     */
    private static final Optional<?> EMPTY = new Optional<>();

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

 /**
  * 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,还是有空指针异常的

 private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

3、创建Optional实例

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

4、访问 Optional 对象的值

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

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的情况

 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语法
Optional<User> userOptiion = Optional.ofNullable(userInfo);
if (userOptiion.isPresent()) {
    User userInfomation = userOptiion.get();
}

5、Optional返回默认值

  • 使用 orElse() 返回默认值,如果有值则返回该值,没数据返回默认值
 //使用 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(供应者) 函数式接口
 User teUser = null;
System.out.println("using orElseGet");
 teUser = Optional.ofNullable(teUser).orElseGet(() -> defaultUserInfo());
 System.out.println("default user information:"+teUser.toString());

defaultUserInfo,返回默认用户数据

 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

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没有调用默认方法

 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,它会在对象为空的时候抛出异常,而不是返回备选的值

 User u = null;
 User userData = Optional.ofNullable(u).orElseThrow(() -> new IllegalArgumentException());

7、Optional转换值

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

map例子:

User us = new User("tom", "15588899988" , "123@foxmail.com", null,"");
String email = Optional.ofNullable(us).map(userInfor -> userInfor.getEmail()).orElse("defaulEmail@foxmail.com");

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

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 值

String position = Optional.ofNullable(us).flatMap(use -> use.getPosition()).orElse("default");

8、Optional过滤值

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

Optional<User> uoptional = Optional.ofNullable(us).filter(euser -> euser.getEmail()!=null && euser.getEmail().contains("@"));
System.out.println(uoptional.get().toString());

9、典型的Optional例子

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


@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写法:

/**
 * 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写法:

/**
  * 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、附录参考资料

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-22 14:00:25  更:2021-07-22 14:00:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/3 17:46:36-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码