2015-05-03 3 views
4

Что у меня: Текстовый файл, который читается по строкам. Каждая строка содержит строку.группировка слов по первому символу

Что я хочу: Группировать ВСЕ слова по первому символу, используя Java-потоки.

То, что я до сих пор:

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).

Подсказка о том, как его обнаружить: в трассе стека, прочитайте collect и lambda$16.

0
s.charAt(0) 

Проверка s перед выполнением этой инструкции проверяется с ошибкой, чтобы избежать исключения.

Смежные вопросы