通常,使用列表我会遇到如下情况(假设用户包含 ID 和名称):
List<User> users = loadFromDb();
List<User> lookingForIdResultList = user.stream()
.filter( u -> u.getId() == 1234)
.collect(Collectors.toList())
if(lookingForIdResultList.size() == 0) throw UserNotFoundException()
if(lookingForIdResultList.size() > 1) throw MultipleIdsNotPermittedExcpetion()
User searchedUser = lookingForIdResultList.get(0);
System.out.println("Username is "+ searchedUser.getName())
有没有办法使用 Java Stream API 来缩短验证时间?
这只是一个过于简单的例子,问题是普遍的。我不想从数据库加载用户。
Guava 库有 Collectors
toOptional()
和 onlyElement()
正是针对此用例:
// throws exception if there is not exactly 1 matching user
User searchedUser = users.stream()
.filter(u -> u.getId() == 1234)
.collect(MoreCollectors.onlyElement());
如果您想在代码中进行验证,那么它不会变得更短,但您可以使代码更具可读性。
一个小的优化是使用
count()
而不是 collect()
:
users.stream().filter(...).count();
一般来说,我会构建一些辅助函数来完成这项工作,这样你的代码就会看起来更干净、更具可读性:
List<User> users = loadFromDb();
validateUsers(users); // throws exception
如果您在多个地方需要类似的功能,则可以进一步抽象
validateUsers
方法:
static void validateUsers(List<User> users) {
validateListHasExactlyOne(users, user -> user.getId() == 1234);
}
static <T> void validateListHasExactlyOne(List<T> list, Predicate<T> pred) {
long count = list.stream().filter(pred).count();
if(count == 0) throw ...
if(count > 1) throw ...
}
请注意,流可能并不总是最好的选择。普通的旧 for 循环可能更容易阅读和编写,而且速度也更快(至少如果您不使用
parallelStream()
)。
static <T> T exactMatch(List<T> list, Predicate<T> predicate) {
T result = null;
for(T element : list) {
if( predicate.test(element) ) {
if(result != null) throw new DuplicateException(); //or some other exception
result = element;
}
}
if( result == null ) throw new NoSuchElementException();
return result;
}
这看起来更长,但它有一些优点:
但有一个缺点:它是单线程的。如果需要并行化,您可能最好使用
parallelStream()
。
如果您还需要能够指定异常,您可以尝试类似的操作(特定异常要么未经检查,要么从基本异常继承):
static <T> T exactMatch(List<T> list, Predicate<T> predicate,
Supplier<D extends RuntimeException> duplicateSupplier,
Supplier<N extends NoSuchElementException> noElementSupplier) {
//same as above but using "throw duplicateSupplier.get()" etc.
}
您还可以进行重载以使用标准异常,例如
static <T> T exactMatch(List<T> list, Predicate<T> predicate) {
return exactMatch(list, predicate, DuplicateException::new, NoSuchElementException::new);
}