我正在从丑陋的嵌套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());
一个事实是,酒吧总是包含每一个foo,foos基本上只是酒吧的一小部分。
如果有更好的方法(在性能或优雅方面)做那个lambda,请分享。
答案 0 :(得分:5)
如果你想要整整九码:
FooBar
如果您的Bar
构造函数接受.map(FooBar::new)
,那么您可以保存一些行并写入
.findFirst().stream()
Java 9中的FWIW你可以写
List<FooBar> listOfFooBar = foos.stream()
.flatMap(foo -> bars.stream().filter(bar-> bar.getFoo().equals(foo)).findFirst().stream()))
.map(FooBar::new)
.collect(Collectors.toList());
假设一个合适的构造函数,它将缩短为
List<FooBar> listOfFooBar = foos.stream()
.flatMap(foo -> bars.stream().filter(bar-> bar.getFoo().equals(foo)).limit(1)))
.map(FooBar::new)
.collect(Collectors.toList());
修改强>: 使用@Misha的建议你可以进一步缩短它:
<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js'></script>
<SCRIPT type='text/javascript' SRC='https://swx.cdn.skype.com/shared/v/1.1.23.0/SkypeBootstrap.min.js'></SCRIPT>
<TABLE CLASS='test'>
<TR><TD ALIGN=RIGHT><INPUT TYPE=TEXT class=suptabde NAME="username" ID="username" VALUE="" MAXLENGTH=40 style="width:18em">
<INPUT TYPE=PASSWORD class=testtabde NAME="password" VALUE="" MAXLENGTH=40 style="width:18em">
<BUTTON id='signin' class='testtabde' STYLE='text-align:center' VALUE=' Skype Login '>Log in</BUTTON><BUTTON id='signout' class='suptabde' STYLE='text-align:center' VALUE=' Skype Login '>Log out</BUTTON>
</TABLE>
答案 1 :(得分:5)
由于每个Foo只有一个Bar,你可以先创建一个将Foos链接到Bars的地图:
Map<String, Bar> barsByFoo = bars.stream().collect(toMap(Bar::getFoo, b -> b));
如果你有更多的酒吧而不是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解决方案。
答案 2 :(得分:0)
如果@SuppressLint("WrongCall") @Override
public void run()
{
Canvas canvas;
while (m_Running)
{
canvas =null;
try
{
canvas =this.m_SurfaceHolder.lockCanvas();
Rect Source =new Rect(0,0,1024,768);
Rect Dest =new Rect(0,0,m_View.getWidth(),m_View.getHeight());
canvas.drawBitmap(m_SimpleBitmap, 0, 0, null);
canvas.drawBitmap(m_BackBuffer,Source,Dest,null);
}
finally
{
if (canvas!=null) m_SurfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
的构造函数接受FooBar
作为参数:
Bar
然后,你可以这样做:
public class FooBar {
public FooBar(Bar bar) {
// do something with bar, assign it, etc
}
}
这会流式传输您的List<FooBar> fooBars = foos.stream()
.map(foo -> bars.stream()
.filter(bar -> bar.getFoo().equals(foo))
.findFirst()
.map(FooBar::new))
.filter(Optional::isPresent)
.map(Optional::get)
.collect(Collectors.toList());
,并为每个foos
流式传输您的foo
,直到找到与当前bars
匹配的第一个foo
。如果实际找到了foo
,则会从内部流的当前FooBar
创建新的bar
。这为我们留下了Optional<FooBar>
的流,然后将其过滤以仅保留非空的选项。然后,将选项转换为它们包含的值(这是在上一步中创建的FooBar
),最后,这些FooBar
被收集到List<FooBar>
。
编辑:这是我的第一次尝试。使用@ zeroflagL的方法要好得多:
List<FooBar> fooBars = foos.stream()
.flatMap(foo -> bars.stream()
.filter(bar -> bar.getFoo().equals(foo))
.findFirst()
.map(Stream::of).orElse(Stream.empty()))
.map(FooBar::new)
.collect(Collectors.toList());