Skl*_*ogW 4 java java-8 java-stream
我有:一行一行的文本文件.每个String包含一行.
我想要的:使用Java Streams按第一个字符对所有单词进行分组.
到目前为止我所拥有的:
public static Map<Character, List<String>> groupByFirstChar(String fileName)
throws IOException {
return Files.lines(Paths.get(PATH)).
flatMap(s -> Stream.of(s.split("[^a-zA-Z]"))).
map(s -> s.toLowerCase()).
sorted((s1, s2) -> s1.compareTo(s2)).
collect(Collectors.groupingBy(s -> s.charAt(0)));
}
Run Code Online (Sandbox Code Playgroud)
问题:我得到一个例外
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 0
at java.lang.String.charAt(String.java:646)
at textana.TextAnalysisFns.lambda$16(TextAnalysisFns.java:110)
at textana.TextAnalysisFns$$Lambda$36/159413332.apply(Unknown Source)
at java.util.stream.Collectors.lambda$groupingBy$196(Collectors.java:907)
at java.util.stream.Collectors$$Lambda$23/189568618.accept(Unknown Source)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.stream.SortedOps$RefSortingSink$$Lambda$37/186370029.accept(Unknown Source)
at java.util.ArrayList.forEach(ArrayList.java:1249)
at java.util.stream.SortedOps$RefSortingSink.end(SortedOps.java:390)
at java.util.stream.Sink$ChainedReference.end(Sink.java:258)
at java.util.stream.Sink$ChainedReference.end(Sink.java:258)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:513)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
at textana.TextAnalysisFns.groupByFirstChar(TextAnalysisFns.java:110)
at textana.SampleTextAnalysisApp.main(SampleTextAnalysisApp.java:95)
Run Code Online (Sandbox Code Playgroud)
问题:为什么我会收到StringIndexOutOfBoundException?
解决方案基于评论中的提示:
public static Map<Character, List<String>> groupByFirstChar(String fileName)
throws IOException {
return Files.lines(Paths.get(PATH)).
flatMap(s -> Stream.of(s.split("[^a-zA-Z]"))).
filter(s -> s.length() > 0).
map(s -> s.toLowerCase()).
collect(Collectors.groupingBy(s -> s.charAt(0)));
}
Run Code Online (Sandbox Code Playgroud)
用户的解决方案Eran会在一开始就给我空字符串,这是我不想要的.
尝试过滤空字符串,""因为它们没有导致charAt(0)抛出此异常的第一个字符.
您可以使用
flatMap(s -> Stream.of(s.split("[^a-zA-Z]"))).
filter(s -> !s.trim().isEmpty()). //add this line
Run Code Online (Sandbox Code Playgroud)
BTW你的方法应该使用它的fileName论点.所以也许可以考虑Paths.get(PATH)换成更像的东西
Paths.get(fileName).
Run Code Online (Sandbox Code Playgroud)
要么
Paths.get(PATH).resolve(fileName)
Run Code Online (Sandbox Code Playgroud)
同样如评论所述,因为您没有更改默认比较顺序,所以您不需要显式写入
sorted((s1, s2) -> s1.compareTo(s2))
Run Code Online (Sandbox Code Playgroud)
但很简单
sorted()
Run Code Online (Sandbox Code Playgroud)
也将工作,因为默认订单将在这里应用.
正如@Alexis C. groupBy所说,将返回HashMap,这意味着您的钥匙将不会被订购.如果您还想保留它们的顺序,您可以使用GROUPBY与LinkedHashMap像
.collect(Collectors.groupingBy(s -> s.charAt(0), LinkedHashMap::new, Collectors.toList()));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2361 次 |
| 最近记录: |