暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

对 java.util.Objects#nonNull 改进的思考

背井 2021-03-03
4572

本文尝试以一种渐进的方式,谈谈怎么对jdk内置的 java.util.Objects#nonNull 进行改进。


打开 Objects 类的源码,可以看到 nonNull 方法的实现如下:

        /**
    * Returns {@code true} if the provided reference is non-{@code null}
    * otherwise returns {@code false}.
    *
    * @apiNote This method exists to be used as a
    * {@link java.util.function.Predicate}, {@code filter(Objects::nonNull)}
    *
    * @param obj a reference to be checked against {@code null}
    * @return {@code true} if the provided reference is non-{@code null}
    * otherwise {@code false}
    *
    * @see java.util.function.Predicate
    * @since 1.8
    */
    public static boolean nonNull(Object obj) {
    return obj != null;
    }


    方法体只有一行(第16行),判断入参 obj 是否为 null。注释比方法体长多了,主要是注意第5~6行的解释:该方法存在的目的是为了作为 Predicatefilter 使用。




    对于如下pojo:

      class User {
      String name;
      User user;


      public User(String name) {
      this.name = name;
      }
      }


      如果我们有个User集合是这样的:

        List<User> users = Arrays.asList(
        new User("Tom"),
        null, // 有个 null 用户
        new User("Jerry")
        );


        要把非空User过滤出来组成新集合的话,需要这样做:

          List<User> nonNullUsers = users.stream()
          .filter(Objects::nonNull)
          .collect(Collectors.toList());


          注意第2行,我们用到了 Objects::nonNull




          问题来了,Objects::nonNull 过滤的是顶层元素,如果要按顶层元素下的属性进行过滤呢?


          比如,User 对象有一个 user 属性,当我想要把 user 属性不为空的顶层元素过滤出来时,目前只能这样做:

            users.stream()
                    .filter(u -> u.getUser() != null);


            但其实我们只要对 Objects::nonNull 改进一下,提供一个重载的方法,问题就简单解决了:

              <T> Predicate<T> nonNull(Function<T, ?> func) {
              return (T t) -> func.apply(t) != null;
              }

               

              这样使用:

                users.stream()
                .filter(nonNull(User::getName));




                有了以上方法,我们的玩法就多起来。


                比如,当我既想要顶层元素不为 null,又想要 name 属性不为 null 时:

                  // 之前要这么写
                  users.stream()
                  .filter(u -> u != null && u.getName() != null);


                  // 现在只要这么写
                  users.stream()
                  .filter(Objects::nonNull)
                  .filter(nonNull(User::getName));


                  如果要过滤出顶层元素下 user 属性 的 name 不为空的元素,则:

                    // 先前要这样写
                    users.stream()
                    .filter(u -> u.getUser().getName() != null);




                    // 现在可以这样写
                    Function<User, String> extractName =
                    f(User::getUser).andThen(User::getName);
                    users.stream()
                    .filter(nonNull(extractName));



                    其中 f 是一个工具函数:

                      // 将 method reference 转换为 Function 接口
                      <T, R> Function<T, R> f(Function<T, R> f) {
                      return f;
                      }




                      你喜欢这个设计吗?

                      文章转载自背井,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                      评论