首先,从
Collectors.toList()
的文档中提取相关内容如下:
[...] 返回的List的类型、可变性、可序列化性或线程安全性没有任何保证;如果需要更多对返回的List的控制,请使用toCollection(Supplier)
现在,让我们更深入地了解收集器的
特征;我们找到了这个:
public static final Collector.Characteristics CONCURRENT
表明此收集器是并发的,这意味着结果容器可以支持从多个线程同时调用累加器函数与相同结果容器。
如果CONCURRENT收集器不是UNORDERED,则只有在应用于无序数据源时才能并发评估。
现在,没有什么保证
Collectors.toList()
返回的收集器是
Concurrent
的。
尽管启动您的新类可能需要一些时间,但在这里可以放心地假设此收集器
不是并发的。但幸运的是,我们可以使用一个并发收集器,如Java文档中所提到的。因此,让我们尝试一下:
.collect(
Collector.of(CopyOnWriteArrayList::new,
List::add,
(o, o2) -> { o.addAll(o2); return o; },
Function.<List<String>>identity(),
Collector.Characteristics.CONCURRENT,
Collector.Characteristics.IDENTITY_FINISH
)
)
这可能会加快速度。
现在,你又有一个问题。你没有关闭流。
这是鲜为人知的,但是
Stream
(无论是任何类型的流还是 {Int, Double, Long}Stream)都实现了
AutoCloseable
接口。你需要关闭那些 I/O 绑定的流,而
Files.lines()
就是这样一种流。
所以,试一下这个:
final List<MyClass> list;
try (
final Stream<String> lines = Files.lines(...);
) {
list = lines.parallel().map(MyClass::new)
.collect(seeAbove);
}
.close()
你的流:Files.lines()
是受I/O限制的。 - fgeArrays.asList(Files.lines(...)...toArray(MyClass[]::new))
代替.collect(Collectors.toList())
。然而,拥有MCVE会更好。 - Tagir Valeev