Худшая часть вашего кода - следующая часть
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(path);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Scanner s = new Scanner(inputStream);
Таким образом, когда файл отсутствует, вы напечатаете трассировку стека FileNotFoundException
и продолжите ввод потока null
, что приведет к NullPointerException
. Вместо того, чтобы требовать от вызывающей стороны иметь дело с ложным NullPointerException
, вы должны объявить FileNotFoundException
в сигнатуре метода. В противном случае верните пустой поток в ошибочном регистре.
Но вам вообще не нужно создавать FileInputStream
, поскольку Scanner
предлагает конструкторам, принимающим File
или Path
. Объедините это с возможностью возврата потока совпадений (начиная с Java 9), и вы получите:
private Stream<String> getWordsStream(String path) {
try {
Scanner s = new Scanner(Paths.get(path));
return s.findAll("([a-zA-Z]{3,})").map(mr -> mr.group().toUpperCase());
} catch(IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
return Stream.empty();
}
}
или предпочтительно
private Stream<String> getWordsStream(String path) throws IOException {
Scanner s = new Scanner(Paths.get(path));
return s.findAll("([a-zA-Z]{3,})").map(mr -> mr.group().toUpperCase());
}
Вам даже не нужно .useDelimiter("([^a-zA-Z])")
здесь, поскольку пропуск всех несоответствующих элементов является поведением по умолчанию.
Закрытие возвращенного Stream
также закроет Scanner
.
Так что вызывающий должен использовать это так
try(Stream<String> s = getWordsStream("path/to/file")) {
s.forEach(System.out::println);
}