使用
现在我想到了以下解决方案:
Stream.forEach()
时,我在想是否有可能在流不为空时添加预动作和后动作。例如,在打印列表时,可以在流为空时添加一些内容或写入其他内容。现在我想到了以下解决方案:
private static <T> void forEach(Stream<T> stream, Consumer<? super T> action,
Runnable preAction, Runnable postAction, Runnable ifEmpty) {
AtomicBoolean hasElements = new AtomicBoolean(false);
Consumer<T> preActionConsumer = x -> {
if (hasElements.compareAndSet(false, true)) {
preAction.run();
}
};
stream.forEach(preActionConsumer.andThen(action));
if (hasElements.get()) {
postAction.run();
} else {
ifEmpty.run();
}
}
对于顺序流,这应该可以工作,不是吗?这种方法是否正确,是否有“好主意”使用这种方法或者是否有任何注意事项?
对于并行流,这种方法不起作用,因为preAction
可能比执行action
的另一个线程慢,但是正确实现它而不借助于synchronized或其他破坏并行流目的的并发工具可能不容易...
编辑:添加用例。使用正则表达式从文件中读取搜索整数,并将它们写入另一个文件。使用这种方法,我不必在内存中创建一个字符串,然后将其写入某个文件。(显然,对于我的实际任务,我使用更复杂的正则表达式。)
public static void main(String[] args) throws IOException {
Stream<String> lines = Files.lines(Paths.get("foo.txt"));
Pattern findInts = Pattern.compile("(\\d+)");
Path barFile = Paths.get("bar.txt");
try (BufferedWriter writer = Files.newBufferedWriter(barFile , StandardOpenOption.CREATE_NEW)) {
lines.flatMap(x -> findInts.matcher(x).results())
.forEach(x-> convertCheckedIOException(() -> {
writer.write(x.group(1));
writer.newLine();
})
);
}
}
public static void convertCheckedIOException(Run r) {
try {
r.run();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
interface Run {
void run() throws IOException;
}
isEmpty
如果 Stream 不为空,则为true
... - tobias_kforEach
明显是走错了方向。还有许多其他终端操作可能适合您的特定实际任务,例如Collectors.joining
允许指定前缀和后缀。如果您能想象到的唯一适合实际任务的操作是forEach
,则流 API 可能不是该特定工作的正确工具。 - HolgerpreAction
。你可以尝试看看它是否适用于你。 - Malte Hartwig