2015-05-03 43 views
4

我擁有的內容:逐行讀取的文本文件。每個字符串都包含一行。按第一個字符分組的單詞

我想要的:使用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))); 
} 

問題:我得到一個異常

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) 

問題:爲什麼我得到一個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))); 
} 

用戶葉蘭的解決方案還必須給我在我不想有開頭空字符串。

+1

順便說一句,你可以跳過排序()操作的參數,因爲你是使用自然順序。 –

回答

6

嘗試過濾空字符串"",因爲它們沒有導致charAt(0)引發此異常的第一個字符。

您可以使用

flatMap(s -> Stream.of(s.split("[^a-zA-Z]"))). 
filter(s -> !s.trim().isEmpty()). //add this line 

BTW你的方法應該使用其fileName說法。因此,也許考慮改變Paths.get(PATH)到更多的東西一樣

Paths.get(fileName). 

Paths.get(PATH).resolve(fileName) 

另外,作爲已經被評論中提及,因爲你並沒有改變默認的比較爲了你不需要明確寫入

sorted((s1, s2) -> s1.compareTo(s2)) 

但簡單

sorted() 

也會工作,因爲默認順序將在此處應用。


正如@Alexis C. GROUPBY提到將返回HashMap這意味着你的鑰匙將不會被訂購。如果您還想保留它們的順序,你可以使用GROUPBY與LinkedHashMap

.collect(Collectors.groupingBy(s -> s.charAt(0), LinkedHashMap::new, Collectors.toList())); 
+1

你甚至可以刪除'sorted',因爲'groupingBy'在幕後使用'HashMap',所以排序的概念無論如何都會丟失。 –

+1

@AlexisC。我們將只丟失鍵的順序,但是如果我沒有弄錯,那麼'List '中的值應該保持有序,這可能是OP在此嘗試實現的。 – Pshemo

+0

啊,是的,你是對的我的壞:-) –

1

您的文件最後可能會有一個空行,可能是您的文本編輯器默默添加的,這會使最後一個s.charAt(0)失敗。

提示如何檢測它:在堆棧跟蹤中,請閱讀collectlambda$16

0
s.charAt(0) 

在執行該指令之前檢查s爲空以避免異常。

相關問題