Java 8 peek 与地图
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44370676/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java 8 peek vs map
提问by Alex
I have following case: there is a list of objects - ProductData which contains several fields:
我有以下情况:有一个对象列表 - ProductData 包含几个字段:
public class ProductData
{
....
private String name;
private String xref;
//getters
//setters
}
and there is API which returns list of following objects:
并且有返回以下对象列表的 API:
public class RatingTableRow
{
private String planName;
private String planXref;
private int fromAge;
private int toAge;
private int ratingRegion;
//constructor
//getters
//setters
}
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:
但它返回带有空计划名称字段的对象,因为在提取此对象期间不允许这样做。我需要通过外部参照将产品数据与 RatingTableRow 链接,以便将计划名称设置到 RatingTableRow 中,因为我稍后需要使用这个对象,所以我创建了以下代码来做到这一点:
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());
})....;
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.
我知道 java 文档说这peek
不符合这些需求,但想就如何以更正确的方式完成这项任务获得您的建议。
回答by Eugene
There is a reason peek
is documented to be mainly for debugging purposes.
有一个原因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.
最终在内部处理的内容peek
可能根本不符合终端操作的条件,并且流仅由终端操作执行。
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);
Everything looks fine right? Because peek
will run for all elementsin this case. But what happens when you add a filter
(and forget about what peek
did):
一切看起来都不错吧?因为在这种情况下peek
将针对所有元素运行。但是当你添加一个filter
(忘记做了什么peek
)时会发生什么:
.peek(x -> list.add(x))
.map(x -> x * 2)
.filter(x -> x > 8) // you have inserted a filter here
You are executing peek
for every element, but collecting none. You sure you want that?
您正在peek
为每个元素执行,但收集 none。你确定要那个?
This can get even trickier:
这可能会变得更加棘手:
long howMany = Stream.of(1, 2, 3, 4)
.peek(x -> list.add(x))
.count();
System.out.println(list);
System.out.println(howMany);
In java-8 the list is populated, but in jdk-9peek
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 中,列表被填充,但在 jdk-9 中peek
根本没有被调用。由于您没有使用filter
或flatmap
没有修改 Streamcount
的大小而只需要它的大小;因此根本不调用 peek。因此依赖peek
是一个非常糟糕的策略。
回答by Arsalan
Kindly bear with me for posting an answer to an older post. But I have observed that the behaviour of peek()
and map()
is the same if you do not add a terminal operator to the stream. As per the following code:
请耐心等待我发布对旧帖子的回答。但我观察到,如果您不向流中添加终端运算符,则peek()
和的行为map()
是相同的。按照以下代码:
IntStream.range(0, 5).boxed().map(i -> {
System.out.println("I am " + i);
return i;
}).count();
If count()
is removed, there is no output on the console. Suggesting that map()
was not executed.
如果count()
删除,则控制台上没有输出。暗示map()
没有执行。
What I want to point out is that I have to return some value unnecessarily when using map()
when I can just use a one-liner if I use peek()
as shown in the following code
我想指出的是,map()
如果我使用peek()
如下代码所示,当我只能使用单行时,我必须在使用时不必要地返回一些值
IntStream.range(0, 5).boxed().peek(i -> System.out.println("I am " + i)).count();
Appreciate your inputs.
感谢您的投入。
P.S. I am using Java 8 from OpenJDK
PS 我使用的是来自 OpenJDK 的 Java 8