考虑以下课程:
@Setter
@Getter
@EqualsAndHashCode(exclude = "text")
@ToString
public class Foo {
private Long xKey;
private Long yKey;
private String text
}
如果我有List<Foo> fooList
,我必须在其中获取列表元素:
{xKey, yKey} combination is in Map<Long,Long> combination = {{10L,20L},{11L,35L},{4L,1L}}
每次迭代都使用.get()方法:
for(Entry<Long,Long> entry: combination.entrySet()){
Foo tempFoo = new Foo(entry.getKey(),entry.getValue(),null);
Foo actualFoo = fooList.get(tempFoo);
System.out.println(actualFoo);
}
第二种方式是java 8流
combination.foreach((k,v) -> {
Foo actualFoo = fooList.stream()
.filter(f -> f.getXKey.equals(k) && f.getYKey.equals(v))
.findFirst()
.orElse(null);
System.out.println(actualFoo);
})
哪一个在性能和编码实践方面更好?
编辑:在查看评论后发现第一个代码段而不是fooList.get(tempFoo);
出现了错误,应该是fooList.get(fooList.indexOf(tempFoo));
答案 0 :(得分:3)
你可以缩短它:
fooList.stream()
.filter(f -> Objects.equals(f.getYKey(), combination.get(f.getXKey())))
.forEach(System.out::println);
答案 1 :(得分:2)
首先,List<Foo>
显然没有get(Foo)
,这只是list.get(list.indexOf(foo))
之类的描述,以获取模板的实际实例,这意味着与您的Stream变体一样的线性搜索。
在这方面,两者不鼓励,因为它们意味着对Map
进行线性迭代,在列表上执行另一个嵌套线性搜索,而Map
通常具有查找操作比线性搜索更好。
因此,您应该遍历列表并在Map
上执行查找:
for(Foo foo: fooList) {
if(foo.getYKey().equals(combination.get(foo.getXKey()))) {
System.out.println(foo);
}
}
唯一的区别是元素没有以Map
的顺序出现,以防地图 定义的顺序(HashMap
没有)并且它不会为列表中没有相应null
的映射打印Foo
。
当然,您也可以将其写为forEach
操作:
fooList.forEach(foo -> {
if(foo.getYKey().equals(combination.get(foo.getXKey()))) {
System.out.println(foo);
}
});
或流操作
fooList.stream()
.filter(foo -> foo.getYKey().equals(combination.get(foo.getXKey())))
.forEach(System.out::println);
都是等价的。
不所做的事情,是使用Stream搜索操作替换Map.get
之类的内部Collection API查找操作。
答案 2 :(得分:1)
您将列表视为一个集合,因此我建议相应地更改实现。将它作为一个集合,您将获得更好的性能,例如使用HashSet
作为实现。在这种情况下,我还强烈建议不要尝试流式传输新的set实现,因为简单的查找将比索引更快地工作。
答案 3 :(得分:0)
第二种解决方案更具可读性。第一个将无法工作,因为get in list的预期参数是一个int,它是列表的索引。对于循环和聚合操作具有基本相同的复杂性,因此没有真正的性能差异,除非第一个解决方案稍微差一些,因为它正在创建那些临时的Foo对象。