前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Lambda Optional使用

Lambda Optional使用

作者头像
潇洒
发布2023-10-20 12:35:46
3230
发布2023-10-20 12:35:46
举报
文章被收录于专栏:石头岛

简述

Optional 针对空指处理而设计的类型。 Java 8借鉴了ScalaHaskell,提供了一个新的Optional模板,可以用它来封装可能为空的引用。这是一个可以为null的容器对象。 使用 Optional 的好处是可以以一种专门针对null的处理方式,来避免值可能存在 null 导致出现的程序异常。你可以理解为:处理null,就是你的业务。 在实际使用过程中,你会发现 Optional 的灵活性有时候会让你想用在任何可能出现null的地方,不过凡事都有套路可循,只要清楚利弊就知道该如何选择。

从两个方面说一下 Optional

  • 常用API
  • 项目使用套路

只讲 API 不讲使用套路的文章都是耍流氓。

API说明

先看一下常用API,后面再讲实际使用场景。

  1. 构建API: 构建Optional对象:of()、ofNullable()、empty()
  2. 获取API: 获取Optional对象包装的值:get()、orElse()、orElseGet()、orElseThrow()
  3. 判断API:对Optional对象里包装的值做一些逻辑判断:isPresent()、ifPresent()、filter()
  4. 转换API:将Optional对象里包装的值转换成一个新的值:map()、flatMap();

构建API

Optional.of()

作用:构建 Optional 对象,不允许传入的值为null,传入就 null 马上抛异常。

这个API要慎用,一般在使用 Optional 时,就是要防住 null,这个API 上来就直接抛异常,一点机会也不给。

代码语言:javascript
复制
public static void testOf() {
    Optional<String> op1 = Optional.of("Hello World");
    System.out.println(op1.isPresent()); // 输出 true
    System.out.println(op1.get()); // 输出 Hello
    Optional<String> op2 = Optional.of(null); // 抛出异常
}

Optional.ofNullable()

常用API。

允许传入的值为 null,如果值为 null,返回一个空的 Optional 传入 null 并不抛异常。

使用 Optional.get() 获取值时,有值正常返回,值为 null 抛异常。

代码语言:javascript
复制
public static void testOfNullable() {
    //传入不报错
    Optional<String> name = Optional.ofNullable(null);
    System.out.println(name);      //直接输出是 Optional.empty
    System.out.println(name.isPresent()); //判断是否有值
    System.out.println(name.get()); //  get()  抛异常
}

Optional.empty()

作用:创建一个空的 Optional 对象,一般很少直接这样写,都是通过 ofNullable 直接接住变量。

empty()方法创建的对象没有值,如果对 emptyOpt 变量调用isPresent()方法会返回false, 调用get()方法抛出NullPointerException异常。

代码语言:javascript
复制
public static void testEmpty() {
    Optional<String> emptyOpt = Optional.empty();
    System.out.println(emptyOpt.isPresent()); // 输出 false
    System.out.println(emptyOpt.get()); // 抛异常
}

获取API

这一组API很常用:get、orElse、orElseGet、orElseThrow。 get() 使用简单,后面三个简单一些业务逻辑。

Optional.get()

作用:获取 Optional 中的数据。

可以看上一个例子。使用 Optional 时,如查值是 null,get 会抛异常。

orElse()

作用:如果有值就返回不执行,否则如果值为null,也会执行orElse();

这种做用是相当于在特定场景下的用法可以用它来代替if..else..来完成很简洁的逻辑判断。 看到 orElse 中只有一个String不能做别的事?当然不是,可以写一个方法,orElse调用该方法,就可以写其他代码。

代码语言:javascript
复制
import java.util.Optional;

public class OptionalTest {
    public static void main(String[] args){
        testOrElse(null);
    }

    public static void testOrElse(String nullValue) {
        // 入参为 null,执行 orElse
        String optional = Optional.ofNullable(nullValue).orElse("Su");
        System.out.println(optional);
        // 入参为 Susan,不执行 orElse
        String nonNullOptional = Optional.ofNullable("Susan").orElse("Su");
        System.out.println(nonNullOptional);
    }
}

结果

Su Susan

orElseGet()

作用:入参为null时,才会执行 orElseGet()。

和orElse的区别: 在optional为空值的情况下orElse和orElseGet都会执行,当optional不为空时,orElseGet不会执行。

代码语言:javascript
复制
import java.util.Optional;

public class OptionalTest {
    public static void main(String[] args){
        testOrElseGet(null);
    }

    public static void testOrElseGet(String nullValue) {
        String optionalGet = Optional.ofNullable(nullValue).orElseGet(() -> "Xiao");
        System.out.println(optionalGet);

        String nonNullOptionalGet = Optional.ofNullable("Molly").orElseGet(() -> "Xiao");
        System.out.println(nonNullOptionalGet);
    }
}

结果

Xiao Molly

orElseThrow()

作有:当参数为空时,抛异常。

代码语言:javascript
复制
import java.util.Optional;

public class OptionalTest {
    public static void main(String[] args){
        testOrElseThrow(null);
    }

    public static void testOrElseThrow(String nullValue) {
        try {
            Optional.ofNullable(nullValue)
                .orElseThrow(()-> new Exception("参数为空"));
        } catch (Exception e) {
        e.printStackTrace();
        }
    }
}

结果

java.lang.Exception: 参数为空 at com.test.OptionalTest.lambdatestOrElseThrow2(OptionalTest.java:30) at java.util.Optional.orElseThrow(Optional.java:290) at com.test.OptionalTest.testOrElseThrow(OptionalTest.java:30) at com.test.OptionalTest.main(OptionalTest.java:9)

判断API

Optional.isPresent()

作用:判断变量是否为null

这个比较常用,用来提前判断一下值是否为空。实际业务场景中,很参数传入的时候,程序是不知道是否为null的,可以使用这个先进行判断。

代码语言:javascript
复制
public static void testIsPersent() {
    //传入不报错
    Optional<String> name = Optional.ofNullable(null);
    System.out.println(name.isPresent()); //判断是否有值: true; false
    if (name.isPresent()) {
        System.out.println("有值");
    } else {
        System.out.println("空值");
    }
}

Optional.ifPresent()

很常有的API。

作用:如果值不为null,则可以执行后续操作。

看这段代码,如果值为null不会进入 ifPresent,如果不为null,则进入。这样就不需要if来判断这种特性很方便写一个流畅的工作流风格代码。

代码语言:javascript
复制
public static void testIfPersent() {
    String value = "test";
    Optional.ofNullable(value)  
    .ifPresent((s) -> {
        System.out.println(s);
    }
}

Optional.filter()

作用:条件过滤,根据条件过滤不满足条件的数据。

代码语言:javascript
复制
public List<UserInfo> getUsers() {
    List<UserInfo> userInfo = userService.getUsers();
    List<UserInfo> newUserInfo = Optional
                          .ofNullable(userInfo)
                          .filter(u -> u.getPrice() < 1000)
                          .orElse(UserInfo.builder()
                          .build());
    //直接 return,orElse处理了null,userInfo不会为null
    return userInfo;
}

Optional.map()

作用:映射出新对象。map 时return 什么类型的数据,接收时就必须使用对应的泛型接住。

代码语言:javascript
复制
public static void testMap() {
    String val1 = "test";
    String val2 = null;
    Optional<String> optional = Optional.ofNullable(val2);
    Optional<String> newVal = optional.map((a) -> {
        System.out.println(a);
        return "bb";
    });
    System.out.println(newVal.get());
}

结果: 入参为 val1 时

bb

入参为 val2 时

Exception in thread "main" java.util.NoSuchElementException: No value present

套路

使用 Optional 时,Optional.get() 如果值为 null,还是会抛异常,那使用 Optional 有什么意义。 Optional 能不能当作返回出参,返回给外部调用。

先说第一个问题,意义在于,Optional 本身不会为 null,不会在被调用时出现空指针而导致异常。由于是通过 Optional 包裹可能出现空值的对象,所以多了一层保护机制。

Optional 不建议做为返回值,至于为什么后面说。

套路1 不返回null

保证返回的数据中绝对不返回null,保证不会因为null引起不可预见的异常。 结合 orElse,来保证如果下面的 list 中查出的数据是null,就返回一个空的ArrayList。 这种写法简单实用。

代码语言:javascript
复制
public List<User> getUsers() {
    List<User> userInfo = userService.getUsers();
    return Optional
            .ofNullable(userInfo)
            .orElse(new ArrayList());

}

套路2 先判断,后使用

业务中从一个Service中获得一个数据,那么先处理一下。

判断List是否为空

代码语言:javascript
复制
public static void testService() {
    List<User> users = userService.getUsers();
    Optional<String> usersOptional = Optional.ofNullable(users);
    // 这里用 Optional 接住,再进行判断
    if (usersOptional.isPresent()) {
        //do somthine
    }
}

判断List是否为空,不为空执行后续

代码语言:javascript
复制
public static void testService() {
    List<User> users = userService.getUsers();
    Optional<String> usersOptional = Optional.ofNullable(users);
    usersOptional.ifPresent(user -> {
        System.out.println(user.getSize());
    })
}

这两种写法,其实很相近,该怎么选择呢,简化一下代码,如果只有在有值的情况下才处理,使用 ifPresent 的处理,是最简洁的。

代码语言:javascript
复制
public void test() {
  //正解
  Optional<User> userOpt = Optional.ofNullable(user);
  userOpt.ifPresent(System.out.println(user.get()));

  //而非
  if (userOpt.isPresent()) {
    System.out.println(user.get());
  }
}

这两种方式都是用在处理没程不需要返回值的情况下。

套路3 结合 Stream 使用

开发中使用Stream应该是用的最多的,还是一样的套路,防止出现 List 为空。

代码语言:javascript
复制
List<Person> personList = personService.getPersons();
Optional.ofNullable(personList)
        .orElseGet(() -> {
            System.out.println("personList为null!");
            return new ArrayList<>();
        })
        .stream()
        .filter(Objects::nonNull)
        .forEach(person -> {
            System.out.println(person.getName());
            System.out.println(person.getAge());
        });

总结

Optional 的功能主要是在保证参数不出现null,通过提供的API来实现,让代码更加健壮。 健壮的代码有助于提高系统的稳定性,是一种不可多得的处理手段。即使不使用 Optional,也需要保证,不直接将 null 返回给上一级调用在方法内处理掉null。 不能相信调用的方法是安全的,需要自己对null有安全的处理。 Optional 只是简化了null的操作,即使没有 Optional 也要对null的处理放在一个重点关注的位置。

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 简述
  • API说明
    • 构建API
      • Optional.of()
        • Optional.ofNullable()
          • Optional.empty()
            • 获取API
              • Optional.get()
                • orElse()
                  • orElseGet()
                    • orElseThrow()
                      • 判断API
                        • Optional.isPresent()
                          • Optional.ifPresent()
                            • Optional.filter()
                              • Optional.map()
                              • 套路
                                • 套路1 不返回null
                                  • 套路2 先判断,后使用
                                    • 套路3 结合 Stream 使用
                                    • 总结
                                    相关产品与服务
                                    容器服务
                                    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                                    领券
                                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档