Java 如何将计数器插入 Stream<String> .forEach()?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30211153/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 09:20:03  来源:igfitidea点击:

How to insert a counter into a Stream<String> .forEach()?

javaforeachjava-streamline-numbers

提问by Vega

FileWriter writer = new FileWriter(output_file);
    int i = 0;

    try (Stream<String> lines = Files.lines(Paths.get(input_file))) {
        lines.forEach(line -> {
            try {
                writer.write(i + " # " + line + System.lineSeparator());
            } catch (Exception e) {
                e.printStackTrace();
            }   
        }
                    );
        writer.close();
    }

I need to write the line with the line number, so I tried to add a counter into the .forEach(), but I can't get it to work. I just don't know where to put the i++; into the code, randomly screwing around didn't help so far.

我需要用行号写一行,所以我试图在 .forEach() 中添加一个计数器,但我无法让它工作。我只是不知道把 i++ 放在哪里;进入代码,随机乱搞到目前为止没有帮助。

采纳答案by Erik Vesteraas

This is a good example of where you should rather use a good old fashioned for loop. While Files.lines()specifically gives a sequential stream, streams can be produced and processed out of order, so inserting counters and relying on their order is a rather bad habit to get into. If you still really want to do it, remember that anywhere you can use a lambda you can still use a full anonymous class. Anonymous classes are normal classes, and can as such have state.

这是一个很好的例子,你应该使用一个好的老式 for 循环。虽然Files.lines()专门给出了一个顺序流,但流可以无序地生成和处理,因此插入计数器并依赖它们的顺序是一个相当糟糕的习惯。如果您仍然真的想这样做,请记住,在任何可以使用 lambda 的地方,您仍然可以使用完整的匿名类。匿名类是普通类,因此可以具有状态。

So in your example you could do like this:

所以在你的例子中,你可以这样做:

FileWriter writer = new FileWriter(output_file);

try (Stream<String> lines = Files.lines(Paths.get(input_file))) {
    lines.forEach(new Consumer<String>() {
        int i = 0;
        void accept(String line) {
            try {
                writer.write((i++) + " # " + line + System.lineSeparator());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
    writer.close();
}

回答by OldCurmudgeon

You can use an AtomicIntegeras a mutable finalcounter.

您可以将AtomicInteger用作可变final计数器。

public void test() throws IOException {
    // Make sure the writer closes.
    try (FileWriter writer = new FileWriter("OutFile.txt") ) {
        // Use AtomicInteger as a mutable line count.
        final AtomicInteger count = new AtomicInteger();
        // Make sure the stream closes.
        try (Stream<String> lines = Files.lines(Paths.get("InFile.txt"))) {
            lines.forEach(line -> {
                        try {
                            // Annotate with line number.
                            writer.write(count.incrementAndGet() + " # " + line + System.lineSeparator());
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
            );
        }
    }
}

回答by akhil_mittal

As stated in Java doc:

正如Java 文档中所述

Any local variable, formal parameter, or exception parameter used but not declared in a lambda expression must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.

任何使用但未在 lambda 表达式中声明的局部变量、形式参数或异常参数必须声明为 final 或有效 final (§4.12.4),否则在尝试使用时会发生编译时错误。

It means your variable has to be final or effectively final. You want to add a counter into forEachand for that you can use an AtomicIntegeras suggested by OldCurumudgeon which is IMO a preferred approach.

这意味着您的变量必须是最终的或有效的最终变量。您想添加一个计数器forEach,为此您可以使用AtomicIntegerOldCurumudgeon 的建议,这是 IMO 的首选方法。

I believe you can also use an array having only one value 0which you can use as counter. Check and let me know if the following example works for you:

我相信您也可以使用只有一个值的数组0作为计数器。检查并让我知道以下示例是否适合您:

public void test() throws IOException {
    FileWriter writer = new FileWriter("OutFile.txt");
    final int[] count = {0};

    try (Stream<String> lines = Files.lines(Paths.get("InFile.txt"))) {
        lines.forEach(line -> {
            try {
                count[0]++;
                writer.write(count[0] + " # " + line + System.lineSeparator());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        );
        writer.close();
    }
}