保留原始对象以结束地图和过滤器链

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了保留原始对象以结束地图和过滤器链相关的知识,希望对你有一定的参考价值。

给出以下代码

List<Double> radia = Arrays.asList(1.0, 1.3, 1.6, 1.9);
List<Ball> listOfBalls = new ArrayList<>();        
radia.forEach(radius -> listOfBalls.add(new Ball(radius)));

listOfBalls.stream().map(b -> b.getVolume())
                        .filter(d -> d>10)
                        .forEach(d -> pprint(d));

如何保留最后一个forEach中正在打印的Ball?我希望能够打印出类似的东西

"Ball with radius " b.getRadius() + " has volume" + d
答案

由于lambda不能分配给其范围之外的变量,因此您必须使用较高范围内的对象来存储结果。

需要注意的是,这不是lambdas或流API的预期用途。如果您正在寻找单个最终结果,您应该像这样使用findFirstfindAny

listOfBalls.stream().map(Ball::getVolume)
                        .filter(d -> d>10)
                        .findFirst();

如果你正在寻找ListBalls然后像这样使用Collectors.toList()

List<Ball> result = listOfBalls.stream().map(Ball::getVolume)
                        .filter(d -> d>10)
                        .collect(Collectors.toList());

此时,您可以遍历列表并输出您想要的内容。流在运行时消耗,这意味着在调用forEach后不能使用它们,列表不受此限制的约束。

另一答案

你可以通过不将每个Ball映射到它的音量来实现你想要的,然后根据需要进行过滤:

listOfBalls.stream()
    .filter(b -> b.getVolume() > 10)
    .forEach(b -> System.out.println(
         "Ball with radius " + b.getRadius() + " has volume " + b.getVolume()));

根据the comment编辑:

如果不需要两次调用Ball.getVolume方法(由于昂贵的计算或DB访问),您可以将该方法的结果与流中相应的Ball实例一起传递。如果您使用的是Java 9+:

listOfBalls.stream()
    .map(b -> Map.entry(b, b.getVolume())) // perform expensive call here
    .filter(e -> e.getValue() > 10)
    .forEach(e -> System.out.println(
         "Ball with radius " + e.getKey().getRadius() + " has volume " + b.getValue()));

如果您使用的是Java 8,则可以使用new AbstractMap.SimpleEntry<>(...)而不是Map.entry(...)

以上是关于保留原始对象以结束地图和过滤器链的主要内容,如果未能解决你的问题,请参考以下文章

在方向更改时保留列表片段中的列表

如何保留原始文件压缩后的时间戳?

iOS - 在创建核心图像过滤器循环时保留原始图像

Realm保留一个已删除的对象

iOS - 创建核心图像过滤器循环时保留原始图像

在地图片段上添加按钮以在地图上执行操作