Java 8相当于Streams的getLineNumber()

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

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

result = Files.lines(Paths.get(fileName)) .filter(w -> w.contains(word)) .collect(Collectors. toList()); 

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

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

 List 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 lineNumbers = IntStream.range(0, list.size()) .filter(i -> list.get(i).contains(word)) .mapToObj(i -> i + 1) .collect(toList()); 

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

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

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

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

 LineNumberReader numberRdr = new LineNumberReader(Files.newBufferedReader(Paths.get("file"))); List linesNumbers = numberRdr.lines() .filter(w -> w.contains(word)) .map(w -> numberRdr.getLineNumber()) .collect(toList()); 

如果你想保持Stream s的高效惰性(即如果你只想找到第一个匹配项,则不读取整个文件),你必须自己构建流。 这不是太难,唯一的障碍是没有元组类型来携带两者,行号和行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; } } 

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

 public static Stream lines(Path p) throws IOException { BufferedReader b=Files.newBufferedReader(p); Spliterator sp=new Spliterators.AbstractSpliterator( Long.MAX_VALUE, Spliterator.ORDERED|Spliterator.NONNULL) { int line; public boolean tryAdvance(Consumer 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); }}); } 

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

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

或收集所有这些

 List all=lines(path).filter(nl->nl.getLine().contains(word)) .map(NumberedLine::getNumber) .collect(Collectors.toList()); 

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

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

RESP。

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

我想在这种情况下,你能做的最简单的事情就是从流中获取一个迭代器,并进行旧式搜索:

  Iterator iterator = Files.lines(Paths.get(fileName)).iterator(); int lineNumber = 1; while (iterator.hasNext()) { if(iterator.next().contains(word)) { break; } lineNumber++; } 

使用此解决方案,您无法将整个文件读入内存,以便能够使用流操作。