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

时间:2015-05-13 09:44:57

标签: java foreach java-stream line-numbers

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();
    }

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

3 个答案:

答案 0 :(得分:45)

您可以使用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();
                        }
                    }
            );
        }
    }
}

答案 1 :(得分:13)

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

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

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();
}

答案 2 :(得分:6)

Java doc中所述:

  

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

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

我相信您也可以使用只有一个值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();
    }
}