我正在从丑陋的嵌套 for 循环转变为 java 中设计精美的 lambda 表达式。
这是我的实际代码
for (String foo : foos) {
for (Bar bar : bars) {
if (bar.getFoo().equals(foo)) {
FooBar fooBar = new FooBar();
fooBar.setBar(bar);
listOfFooBar.add(fooBar);
break;
}
}
}
我实际的 lambda 代码来替换上面的代码
foos.forEach(i -> bars.stream().filter(p -> p.getFoo().equals(i)).findFirst().ifPresent(p -> {
FooBar s = new FooBar();
fooBar.setBar(bar);
listOfFooBar.add(fooBar);
}));
我的问题是,有没有办法用某种 collect() 方法填充 listOfFooBar
?
类似listOfFooBar = foos.forEach(.....).collect(Collectors.toList());
一个事实是,bars 将始终包含每个 foo,foos 基本上是 bars 的一小部分。
如果有更好的方法(在性能或优雅方面)来执行该 lambda,请分享。
最佳答案
由于每个 Foo 只有一个 Bar,您可以从创建一个将 Foos 链接到 Bars 的 map 开始:
Map<String, Bar> barsByFoo = bars.stream().collect(toMap(Bar::getFoo, b -> b));
如果 bars 比 foos 多很多,你可以过滤:
Map<String, Bar> barsByFoo = bars.stream()
.filter(b -> foos.contains(b.getFoo()))
.collect(toMap(Bar::getFoo, b -> b));
然后可以编写嵌套的 for 循环:
List<FooBar> listOfFooBar = foos.stream()
.map(barsByFoo::get)
.filter(Objects::nonNull)
.map(FooBar::new)
.collect(toList());
这假设有一个 FooBar(Bar)
构造函数。
或者您可以从另一侧解决问题并使用(我认为)等效算法(在这种情况下您可能会受益于使用 Set<Foo>
):
List<FooBar> listOfFooBar = bars.stream()
.filter(bar -> foos.contains(bar.getFoo()))
.map(FooBar::new)
.collect(toList());
无论哪种方式,它通常都有助于退出初始循环,因为不同的算法/方法通常有利于干净的 lambda 解决方案。
关于java - 在消费者方法中创建的 Lambda Collect 元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32632155/