【问题标题】:How to insert a counter into a Stream<String> .forEach()?如何将计数器插入 Stream<String> .forEach()?
【发布时间】:2015-07-24 12:34:48
【问题描述】:
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++ 放在哪里;进入代码,到目前为止,随意乱搞并没有帮助。

【问题讨论】:

  • 在循环外声明一个int,设置为0,每次迭代增加。
  • @Stultuske 这行得通吗?你试过了吗?请注意,这里没有任何循环,但有一个 lambda。
  • 这就是问题所在,我有一个 int i = 0;在 lambda 之外,但我不能让它在每个 for.Each() 循环中增加。 Stultuske 既不阅读代码也不阅读问题,只阅读主题。
  • 你试过 writer.write(i++ + " # " + line + System.lineSeparator());
  • 我这里没有安装 Java 8,所以无法尝试。但应该有办法让它发挥作用。

标签: java foreach java-stream line-numbers


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    这是一个很好的例子,说明您应该使用老式的 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();
    }
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 2023-03-31
        • 2014-04-20
        • 2021-03-14
        • 2014-07-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多