如何使用 Java 8 避免多个 Stream
我有以下代码
trainResponse.getIds().stream()
.filter(id -> id.getType().equalsIgnoreCase("Company"))
.findFirst()
.ifPresent(id -> {
domainResp.setId(id.getId());
});
trainResponse.getIds().stream()
.filter(id -> id.getType().equalsIgnoreCase("Private"))
.findFirst()
.ifPresent(id ->
domainResp.setPrivateId(id.getId())
);
,这里我正在迭代/流式传输 Id
对象列表 2
次。
两个流之间的唯一区别在于 filter()
操作。
如何在单次迭代中实现它,以及什么是最佳方法(就时间和空间复杂度< /strong>)这样做?
I am having the below code
trainResponse.getIds().stream()
.filter(id -> id.getType().equalsIgnoreCase("Company"))
.findFirst()
.ifPresent(id -> {
domainResp.setId(id.getId());
});
trainResponse.getIds().stream()
.filter(id -> id.getType().equalsIgnoreCase("Private"))
.findFirst()
.ifPresent(id ->
domainResp.setPrivateId(id.getId())
);
Here I'm iterating/streaming the list of Id
objects 2
times.
The only difference between the two streams is in the filter()
operation.
How to achieve it in single iteration, and what is the best approach (in terms of time and space complexity) to do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您可以使用 Stream IPA 一次通过给定的数据集来实现这一点,并且不会增加内存消耗(即结果将仅包含具有所需属性的 id ) )。
为此,您可以创建一个自定义的
Collector
,它需要一个要查找的Collection
属性作为其参数,以及一个负责提取该属性的Function
来自流元素。这就是这个通用收集器的实现方式。
main()
- 演示(虚拟Id
类未显示)输出
注意,在键集变为空(即已获取所有结果数据)流的其他元素将被忽略,但仍然需要处理所有剩余数据。
You can achieve that with Stream IPA in one pass though the given set of data and without increasing memory consumption (i.e. the result will contain only
id
s having required attributes).For that, you can create a custom
Collector
that will expect as its parameters aCollection
attributes to look for and aFunction
responsible for extracting the attribute from the stream element.That's how this generic collector could be implemented.
main()
- demo (dummyId
class is not shown)Output
Note, after the set of keys becomes empty (i.e. all resulting data has been fetched) the further elements of the stream will get ignored, but still all remained data is required to be processed.
IMO,两个流解决方案是最可读的。它甚至可能是使用流的最有效的解决方案。
IMO,避免多个流的最佳方法是使用经典循环。例如:
目前尚不清楚执行一次迭代或两次迭代是否更有效。这将取决于
getIDS()
和迭代代码返回的类。带有两个标志的复杂内容是您如何在2个流解决方案中复制
findfirst()
的短路行为。我不知道是否可以使用一个流才能完全这样做。如果可以的话,它将涉及一些非常狡猾的代码。但是,正如您可以看到2流的原始解决方案显然比上面更容易理解。
使用流的要点是使您的代码更简单。这与效率无关。当您尝试做复杂的事情以提高流的效率时,您可能首先会击败使用流的(真)目的。
IMO, the two streams solution is the most readable. And it may even be the most efficient solution using streams.
IMO, the best way to avoid multiple streams is to use a classical loop. For example:
It is unclear whether that is more efficient to performing one iteration or two iterations. It will depend on the class returned by
getIds()
and the code of iteration.The complicated stuff with two flags is how you replicate the short circuiting behavior of
findFirst()
in your 2 stream solution. I don't know if it is possible to do that at all using one stream. If you can, it will involve something pretty cunning code.But as you can see your original solution with 2 stream is clearly easier to understand than the above.
The main point of using streams is to make your code simpler. It is not about efficiency. When you try to do complicated things to make the streams more efficient, you are probably defeating the (true) purpose of using streams in the first place.
对于您的 ID 列表,您可以只使用地图,然后在检索后分配它们(如果存在)。
如果你想测试它,你可以使用以下内容:
编辑为只允许检查某些类型
如果你有两种以上的类型,但只想检查某些类型,你可以这样做接下来。
contains
检查是否正在处理其中一种类型。测试类似,只是需要包含其他类型。
2
,以允许在退出循环之前检查两种以上的类型。For your list of ids, you could just use a map, then assign them after retrieving, if present.
If you want to test it, you can use the following:
Edited to allow only certain types to be checked
If you have more than two types but only want to check on certain ones, you can do it as follows.
Set
of allowed types.contains
.Testing is similar except that additional types need to be included.
2
to permit more than two types to be checked before exiting the loop.您可以按类型分组并检查生成的地图。
我认为
ids
的类型是IdType
。You can group by type and check the resulting map.
I suppose the type of
ids
isIdType
.我建议使用传统的 for 循环。除了易于扩展之外,这还可以防止您多次遍历集合。
您的代码看起来像是将来会被推广的代码,因此是我的通用方法。
这是一些伪代码(有错误,只是为了说明)
I'd recommend a traditionnal for loop. In addition of being easily scalable, this prevents you from traversing the collection multiple times.
Your code looks like something that'll be generalised in the future, thus my generic approch.
Here's some pseudo code (with errors, just for the sake of illustration)
沿着这些线路可能会起作用,但是它会贯穿整个流,并且在第一次发生时不会停止。
但是,假设每种类型的小流和一个ID只有一个ID,为什么不呢?
Something along these lines can might work, it would go through the whole stream though, and won't stop at the first occurrence.
But assuming a small stream and only one Id for each type, why not?
从Java 9开始,我们可以使用
Collectors.filtering
来根据条件收集值。对于这种情况,我更改了如下代码
并从
results
Map 获取id
。We can use the
Collectors.filtering
from Java 9 onwards to collect the values based on condition.For this scenario, I have changed code like below
And getting the
id
fromresults
Map.