用lambda表达式java实现计数变量

时间:2015-04-24 14:49:09

标签: java lambda java-8 java-stream

我对lambda表达式有疑问。我有一个类Pair,它应该包含一个String和一个int。

Pair从文件中获取String。 并且int表示行号。 到目前为止,我有这个:

 Stream<String> lineNumbers = Files.lines(Paths.get(fileName));
    List<Integer> posStream = Stream.iterate(0, x -> x + 1).limit(lineNumbers.count()).collect(Collectors.toList());
    lineNumbers.close();
    Stream<String> line = Files.lines(Paths.get(fileName));
    List<Pair> pairs = line.map((f) -> new Pair<>(f,1))
            .collect(Collectors.toList());
    pairs.forEach(f -> System.out.println(f.toString()));
    line.close();

我现在如何输入文件编号? 是否有lambda表达式可以执行此操作?或者我还需要其他东西吗?

3 个答案:

答案 0 :(得分:7)

有几种方法可以做到这一点。 Saloparenator's answer建议的计数器技术可以如下实现,使用AtomicInteger作为可变计数器对象并假设明显的Pair类:

List<Pair> getPairs1() throws IOException {
    AtomicInteger counter = new AtomicInteger(0);
    try (Stream<String> lines = Files.lines(Paths.get(FILENAME))) {
        return lines.parallel()
                    .map(line -> new Pair(line, counter.incrementAndGet()))
                    .collect(toList());
    }
}

问题在于,如果流并行运行,则计数器不会以与读取行相同的顺序递增!如果您的文件有几千行,则会发生这种情况。 Files.lines流源将批处理一串线并将它们分派给多个线程,然后将其并行编号,将其调用交错到incrementAndGet()。因此,这些线不会按顺序编号。如果您可以保证您的流不会并行运行,那么它将起作用,但编写可能会顺序返回不同结果的流通常是一个坏主意。

这是另一种方法。由于您无论如何都要将所有行读入内存,只需将它们全部读入列表即可。然后使用流对它们进行编号:

static List<Pair> getPairs2() throws IOException {
    List<String> lines = Files.readAllLines(Paths.get(FILENAME));
    return IntStream.range(0, lines.size())
                    .parallel()
                    .mapToObj(i -> new Pair(lines.get(i), i+1))
                    .collect(toList());
}

答案 1 :(得分:0)

另一种功能方法是使用整数生成器压缩您的流列表

(我可以看到java8还没有它,但它实际上是在一对列表中合并两个列表中的每个单元格,因此很容易实现)

您可以在java8 here

中看到生成器的示例

答案 2 :(得分:-1)

int cnt = 1;
List<Pair> pairs = line.map((f) -> new Pair<>(f,cnt++))
                       .collect(Collectors.toList());

我还没有尝试过但可能有用。