通常,使用列表我会遇到如下情况(假设用户包含一个 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 streams api 来缩短验证时间?
这只是一个过于简单的例子,问题是普遍的。我不想从数据库加载用户。
坦克!
Guava 库有收集器
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);
}