本文尝试以一种渐进的方式,谈谈怎么对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行的解释:该方法存在的目的是为了作为 Predicate 给 filter 使用。
对于如下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进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




