问题描述
我有以下案例:有一个对象列表 - ProductData包含几个字段:
I have following case: there is a list of objects - ProductData which contains several fields:
public class ProductData
{
....
private String name;
private String xref;
//getters
//setters
}
并且有API返回以下对象的列表:
and there is API which returns list of following objects:
public class RatingTableRow
{
private String planName;
private String planXref;
private int fromAge;
private int toAge;
private int ratingRegion;
//constructor
//getters
//setters
}
但它返回具有空计划名称字段的对象,因为在提取此对象期间不允许这样做。我需要通过外部参照将产品数据与RatingTableRow链接,以便将计划名称设置为RatingTableRow,因为我需要稍后使用此对象,所以我创建了以下代码来执行此操作:
but it returns objects with empty plan name field because it's not allowed during extraction of this object. I need to link product data with RatingTableRow by the xref in order to set plan name into the RatingTableRow because I need to use this object later so I created following code to do that:
Map<String, ProductData> productByXref = plans.stream()
.collect(toMap(ProductData::getInternalCode, Function.identity()));
return getRatingTableRows(...).stream
.filter(ratingRow -> productByXref.containsKey(ratingRow.getPlanXref()))
.peek(row -> {
ProductData product = productByXref.get(row.getPlanXref());
row.setPlanName(product.getName());
})....;
我知道java文档说 peek
不符合这些需求,但希望得到关于如何以更正确的方式完成此任务的建议。
I know that java docs say that peek
doesn't fit these needs but want to get your suggestions on how to make this task in more correct way.
推荐答案
有原因 peek
被记录为主要用于调试目的。
最终在 peek
内处理的东西可能根本没有资格进行终端操作并且会执行流只能通过终端操作。
Something that ends up being processed inside peek
might not be eligible for the terminal operation at all and streams are executed only by a terminal operation.
首先假设一个简单的例子:
Suppose a trivial example first:
List<Integer> list = new ArrayList<>();
List<Integer> result = Stream.of(1, 2, 3, 4)
.peek(x -> list.add(x))
.map(x -> x * 2)
.collect(Collectors.toList());
System.out.println(list);
System.out.println(result);
一切看起来都不错吧?因为在这种情况下, peek
将运行所有元素。但是当你添加一个过滤器
时会发生什么(并忘记 peek
做了什么):
Everything looks fine right? Because peek
will run for all elements in this case. But what happens when you add a filter
(and forget about what peek
did):
.peek(x -> list.add(x))
.map(x -> x * 2)
.filter(x -> x > 8) // you have inserted a filter here
你正在为每个元素执行 peek
,但不收集任何。你确定你想要吗?
You are executing peek
for every element, but collecting none. You sure you want that?
这可能变得更加棘手:
long howMany = Stream.of(1, 2, 3, 4)
.peek(x -> list.add(x))
.count();
System.out.println(list);
System.out.println(howMany);
在java-8中填充列表,但是在jdk-9 中根本没有调用 peek
。由于您没有使用过滤器
或 flatmap
,因此您不会修改Stream的大小和 count
只需要它的大小; 因此peek根本不被调用。因此,依赖 peek
是一个非常糟糕的策略。
In java-8 the list is populated, but in jdk-9 peek
is not called at all. Since you are not using filter
or flatmap
you are not modifying the size of the Stream and count
only needs it's size; thus peek is not called at all. Thus relying on peek
is a very bad strategy.
这篇关于Java 8偷看vs地图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!