如何在Java8流api中惰性初始化collector.toList()?
我想根据过滤器收集项目。但如果没有找到匹配项,则不应初始化结果列表。我更喜欢空列表而不是空列表如何在Java8流api中惰性初始化collector.toList()?,java,java-8,java-stream,Java,Java 8,Java Stream,我想根据过滤器收集项目。但如果没有找到匹配项,则不应初始化结果列表。我更喜欢空列表而不是空列表 List<String> match = list .stream() .filter(item -> item.getProperty == "match") .collect(Collectors.toList()); if (match != null && !match.isEmpty(
List<String> match = list
.stream()
.filter(item -> item.getProperty == "match")
.collect(Collectors.toList());
if (match != null && !match.isEmpty()) {
//handle seldom match
}
List match=List
.stream()
.filter(项目->项目.getProperty==“匹配”)
.collect(Collectors.toList());
if(match!=null&&!match.isEmpty()){
//句柄很少匹配
}
问题:大多数时候我都没有匹配项,导致集合为空。这意味着即使我不需要它,大多数时候列表都是实例化的。Collecto.toList()
使用ArrayList::new
分配一个list
,这是一个非常便宜的操作,因为ArrayList
实际上在插入元素之前不会分配支持数组。构造函数只需将内部对象[]
字段初始化为静态创建的空数组的值。只有在插入第一个元素时,才将实际备份数组初始化为其“初始大小”
那么,为什么要经历避免这种建设的痛苦呢?这听起来像是过早的优化
如果您非常担心GC压力,就不要使用流。流和收集器本身创建的成本可能比列表要高出很多。我只考虑一个情况,即除
Collector.toList()
之外的其他东西计算成本较高,否则使用:
... collect(Collectors.collectingAndThen(list -> {
list.isEmpty() ? null: list;
}))
但请记住,如果缺少元素,使用该列表的人很可能会期望一个空列表,而不是空列表
创建一个空的ArrayList
非常便宜,在这里懒惰只会让事情变得更糟
否则,如果您真的想要,这里有一个变量可以推迟到null:
private static <T> List<T> list(Stream<T> stream) {
Spliterator<T> sp = stream.spliterator();
if (sp.getExactSizeIfKnown() == 0) {
System.out.println("Exact zero known");
return null;
}
T[] first = (T[]) new Object[1];
boolean b = sp.tryAdvance(x -> first[0] = x);
if (b) {
List<T> list = new ArrayList<>();
list.add(first[0]);
sp.forEachRemaining(list::add);
return list;
}
return null;
}
私有静态列表(流){
Spliterator sp=stream.Spliterator();
如果(sp.getExactSizeIfKnown()==0){
System.out.println(“精确零已知”);
返回null;
}
T[]first=(T[])新对象[1];
布尔b=sp.tryAdvance(x->first[0]=x);
如果(b){
列表=新的ArrayList();
列表。添加(第一个[0]);
sp.foreachleveling(列表::添加);
退货清单;
}
返回null;
}
是否可能有多个匹配项,或者您是否只关心找到的第一个匹配项?也许您不需要收集到列表中。那么String match=List.stream().filter(item->“match.equalsIgnoreCase(item.getProperty())).findFirst().orElse(null)如何代码>我关心找到的所有匹配项。这就是为什么我要收集到一个列表,而不是使用.anyMatch()
。ArrayList::new
是否意味着构造函数new ArrayList()
分配了10个初始容量?查看ArrayList
@Nikolas的源代码的实际实现。构造函数中未分配10的容量。只有在添加第一个元素时才会分配后备数组。@Nikolas afaik,这是Java 8中引入的一种优化,在观察到空的ArrayList
实例到处飞来飞去是很常见的之后。@Holger从OpenJDK的JDK6和JDK7源代码看,似乎你是对的。estimateSize()
之所以这样命名是因为它是一个估计值,而不是一个精确已知的大小,因此当estimateSize()==0
时,它可能仍然有元素。除此之外,构造一个单元素数组并不比构造一个空的ArrayList
便宜,因此在不改进空的情况下,你会使非空的情况变得更昂贵…@Holger同意第一种观点,第二次我想我清楚地表明,无论如何,在ArrayList
的情况下这样做可能没有意义。谢谢你的评论