[英]Combine the Two Lines of code initializing and populating a List into a Single Statement in Java 8?
I have a list of user id pmUserIds
.我有一个用户 ID pmUserIds
的列表。 For each id in the list I'm making a call getUserByUserId()
and placing the result in a list of type List<Optional<User>>
.对于列表中的每个id ,我都会调用getUserByUserId()
并将结果放入List<Optional<User>>
类型的列表中。
I want to combine these 2 lines into a single statement:我想将这两行合并为一个语句:
List<Optional<User>> pmUsers = new ArrayList<>();
pmUserIds.forEach(userId -> pmUsers.add(userRepository.getUserByUserId(userId)));
Something like that wouldn't work:像这样的东西是行不通的:
List<Optional<User>> pmUsers = pmUserIds.forEach(userId -> pmUsers.add(userRepository.getUserByUserId(userId)));
It will say that pmUsers
not have been initiated.它会说pmUsers
尚未启动。 Is there any way we could do this in single line?有什么办法可以在单行中做到这一点?
Use Stream.map
instead of forEach
, then convert to List
with collect
:使用Stream.map
代替forEach
,然后使用collect
转换为List
:
List<Optional<User>> pmUsers = pmUserIds.stream()
.map(userId -> userRepository.getUserByUserId(userId))
.collect(Collectors.toList());
That's still not one line (except you want a really long line), but it's somewhat clearer what the code does that with separate initialization and forEach
.这仍然不是一行(除非您想要很长的一行),但是代码通过单独的初始化和forEach
做了什么更清楚了。 You may also use a method reference instead of that lambda, ie .map(userRepository::getUserByUserId)
您也可以使用方法参考而不是 lambda,即.map(userRepository::getUserByUserId)
Your second attempt is not viable because method forEach()
is void
.您的第二次尝试不可行,因为方法forEach()
是void
。 To do the job in a single statement, you need a Stream .要在单个语句中完成这项工作,您需要一个Stream 。
But there is more to it.但还有更多。
Storing Optional
objects into a Collection
is an antipattern .将Optional
对象存储到Collection
中是一种反模式。 It almost the same as storing null
references because optional not necessarily contains a value.它与存储null
引用几乎相同,因为可选不一定包含值。
Both null
and empty optional are meant to represent the absence of data and nothing else. null
和空选项都表示没有数据,仅此而已。 If one of them has a separate meaning in your application (apart from "no value" ), it's a smell.如果其中一个在您的应用程序中具有单独的含义(除了"no value" ),那就是一种气味。
If you need to fire a particular action when a call getUserByUserId()
returns an empty optional , then do it right after receiving the optional instead of placing it to the list (and by the way, Stream is not the right tool when you need to perform some side-effects along the way, it would be better to stick with plain loops).如果您需要在调用getUserByUserId()
返回一个空的 optional时触发特定操作,那么在接收到optional后立即执行此操作,而不是将其放入列表中(顺便说一下,Stream 不是您需要时的正确工具在此过程中执行一些副作用,最好坚持使用普通循环)。
Here's a small quote from the answer by @Stuart Marks , Java and OpenJDK developer:这是@Stuart Marks 、Java 和 OpenJDK 开发人员的回答中的一小段引述:
I'm sure somebody could come up with some contrived cases where they really want to store an
Optional
in a field or a collection , but in general, it is best to avoid doing this .我敢肯定,有人可能会想出一些人为的情况,他们真的想将Optional
存储在field或collection中,但总的来说,最好避免这样做。
I suggest you to check the presence of value in the Optional
right on the spot (in the stream) and then "unpack" non-empty optional objects .我建议您当场(在流中)检查Optional
右侧的值是否存在,然后“解包”非空可选对象。
That's how it might look like:这就是它的样子:
List<User> pmUsers = pmUserIds.stream()
.map(userRepository::getUserByUserId) // Stream<Optional<User>>
.filter(Optional::isPresent)
.map(Optional::get) // Stream<User>
.toList(); // for Java 16+ or .collect(Collectors.toList()) for earlier versions
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.