Java 8相当于Streams的getLineNumber()

wun*_*jah 8 java java-8 java-stream

Java 8中的Streams是否等同于getLineNumber()?

我想在文本文件中搜索一个单词并将行号返回为Integer.这是我的搜索方法:

result = Files.lines(Paths.get(fileName))
            .filter(w -> w.contains(word))
            .collect(Collectors.<String> toList());
Run Code Online (Sandbox Code Playgroud)

Ale*_* C. 6

我认为没有,因为流不是为了提供对元素的访问而不是集合.

一种解决方法是读取列表中的文件,然后使用a IntStream生成相应的索引,然后您可以从中应用过滤器:

List<String> list =  Files.readAllLines(Paths.get("file"));

//readAllLines current implementation returns a RandomAccessList so 
//using get will not have a big performance impact.
//The pipeline can be safely run in parallel
List<Integer> lineNumbers = 
     IntStream.range(0, list.size())
              .filter(i -> list.get(i).contains(word))
              .mapToObj(i -> i + 1)
              .collect(toList());
Run Code Online (Sandbox Code Playgroud)

当你承担将整个文件的内容加载到列表中以便之后只保留几个元素的风险时,这有点过分了.如果它不满足你,你可以写好for循环,它不是很多代码.

也许你可以对这个问题感兴趣使用JDK8和lambda(java.util.stream.Streams.zip)来压缩流.例如,使用proton-pack库:

List<Long> lineNumbers = 
    StreamUtils.zipWithIndex(Files.lines(Paths.get("file")))
               .filter(in -> in.getValue().contains(word))
               .map(in -> in.getIndex() + 1)
               .collect(toList());
Run Code Online (Sandbox Code Playgroud)

或者你可以创建一个LineNumberReaderBufferedReader,然后调用lines()每行映射到该文件中的行号.请注意,如果管道并行运行,此方法将失败,因此我不建议这样做.

LineNumberReader numberRdr = new LineNumberReader(Files.newBufferedReader(Paths.get("file")));

List<Integer> linesNumbers = numberRdr.lines()
                                      .filter(w -> w.contains(word))
                                      .map(w -> numberRdr.getLineNumber())
                                      .collect(toList());
Run Code Online (Sandbox Code Playgroud)


Hol*_*ger 6

如果你想保持Streams的有效惰性(即如果你只想找到第一个匹配,则不读取整个文件),你必须自己构建流.这不是太难,唯一的障碍是没有元组类型来携带两者,一个行号和一行String.您可以滥用Map.Entry实例或创建专用类型:

static final class NumberedLine {
    final int number;
    final String line;
    NumberedLine(int number, String line) {
        this.number = number;
        this.line = line;
    }
    public int getNumber() {
        return number;
    }
    public String getLine() {
        return line;
    }
    @Override
    public String toString() {
        return number+":\t"+line;
    }
}
Run Code Online (Sandbox Code Playgroud)

那么你可以直接实现一个流:

public static Stream<NumberedLine> lines(Path p) throws IOException {
    BufferedReader b=Files.newBufferedReader(p);
    Spliterator<NumberedLine> sp=new Spliterators.AbstractSpliterator<NumberedLine>(
        Long.MAX_VALUE, Spliterator.ORDERED|Spliterator.NONNULL) {
            int line;
            public boolean tryAdvance(Consumer<? super NumberedLine> action) {
                String s;
                try { s=b.readLine(); }
                catch(IOException e){ throw new UncheckedIOException(e); }
                if(s==null) return false;
                action.accept(new NumberedLine(++line, s));
                return true;
            }
        };
    return StreamSupport.stream(sp, false).onClose(()->{
        try { b.close(); } catch(IOException e){ throw new UncheckedIOException(e); }});
}
Run Code Online (Sandbox Code Playgroud)

使用该方法,您可以搜索第一个匹配项

OptionalInt lNo=lines(path).filter(nl->nl.getLine().contains(word))
                           .mapToInt(NumberedLine::getNumber)
                           .findFirst();
Run Code Online (Sandbox Code Playgroud)

或收集所有这些

List<Integer> all=lines(path).filter(nl->nl.getLine().contains(word))
                             .map(NumberedLine::getNumber)
                             .collect(Collectors.toList());
Run Code Online (Sandbox Code Playgroud)

或者,在生产代码中,您希望确保适当关闭底层资源:

OptionalInt lNo;
try(Stream<NumberedLine> s=lines(path)) {
    lNo=s.filter(nl->nl.getLine().contains(word))
         .mapToInt(NumberedLine::getNumber)
         .findFirst();
}
Run Code Online (Sandbox Code Playgroud)

RESP.

List<Integer> all;
try(Stream<NumberedLine> s = lines(path)) {
    all = s.filter(nl->nl.getLine().contains(word))
            .map(NumberedLine::getNumber)
            .collect(Collectors.toList());
}
Run Code Online (Sandbox Code Playgroud)