Java:使用 lambda 将行号添加到文件的优雅方法

Say*_*iss 5 java lambda java-8

bufferedReader.readLine()很长一段时间以来,我习惯使用 lambda 逐行解析文件(比 lambda 简洁得多)。但今天我遇到了一个问题:为每一行添加一个行号。

它需要一个计数器,但 lambda 中的变量实际上应该是最终的。最后,我用 int 数组破解了它。

代码:

public static void main(String[] args) {
    int[] counter = new int[1];
    counter[0] = 0;
    try (Stream<String> lines = Files.lines(Paths.get("/tmp/timeline.txt"), Charset.defaultCharset())) {
        lines.limit(10).forEachOrdered(line -> {
            line = line.trim();
            counter[0] ++;
            System.out.println("Line " + counter[0] + ": " + line);
        });
    } catch (IOException e) {
        e.printStackTrace();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Line 1: p 5714026 wEkQ
Line 2: v 8235889
Line 3: v 6534726
...
Run Code Online (Sandbox Code Playgroud)

我的问题是,如何避免我的黑客攻击并优雅地解决该问题?

Hol*_*ger 4

对于非功能性任务,没有优雅的功能性解决方案。您可能考虑的第一个,只是求助于普通的匿名内部类:

\n\n
String path = "/tmp/timeline.txt";\ntry(Stream<String> lines = Files.lines(Paths.get(path), Charset.defaultCharset())) {\n    lines.limit(10).forEachOrdered(new Consumer<String>() {\n        int counter = 0;\n        public void accept(String line) {\n            System.out.println("Line " + counter++ + ": " + line.trim());\n        }\n    });\n} catch (IOException e) {\n    e.printStackTrace();\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

优点是它不会在实际情况下假装起作用,并且变量的范围counter具有此任务所需的最小范围。

\n\n
\n\n

如果您要做的不仅仅是打印这些编号行,并且需要一个与所有流操作兼容的解决方案,那么重新实现流源是一个直接的解决方案:

\n\n
static Stream<String> numberedLines(Path path, Charset cs) throws IOException {\n    BufferedReader br = Files.newBufferedReader(path, cs);\n    return StreamSupport.stream(new Spliterators.AbstractSpliterator<String>(\n            Long.MAX_VALUE, Spliterator.ORDERED|Spliterator.NONNULL) {\n        int counter;\n        public boolean tryAdvance(Consumer<? super String> action) {\n            String line;\n            try {\n                line = br.readLine();\n                if(line==null) return false;\n                action.accept("Line " + counter++ + ": " + line.trim());\n                return true;\n            } catch (IOException ex) {\n                throw new UncheckedIOException(ex);\n            }\n        }\n    }, true).onClose(()->{ try { br.close(); }\n        catch (IOException ex) { throw new UncheckedIOException(ex); }\n    });\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

当然,这不像单个 lambda 表达式那么简单,但是使用这种可重用的方法,您可以毫无问题地使用所有流操作,例如

\n\n
String path = "/tmp/timeline.txt";\ntry(Stream<String> lines = numberedLines(Paths.get(path), Charset.defaultCharset())) {\n    lines.skip(10).limit(10).forEachOrdered(System.out::println);\n} catch(IOException e) {\n    e.printStackTrace();\n}\n
Run Code Online (Sandbox Code Playgroud)\n