Aside from the issue with StringTokenizer which could be resolved by additionally checking if token.hasNextToken() before calling each setter in Opera, there are some other issues in the code which need to be refactored:
- Use
try-with-resources to ensure the Scanner instance is closed automatically
- Fix declaration and usage of local variables
- Use
String::split method instead of StringTokenizer
- Implement a helper method to build an instance of
Opera from the array of Strings
- Populate
operas with the read Opera only after the file has been successfully processed - in current implementation existing list is cleared at once and populated afterwards, that is, in case of I/O exception existing data are destroyed.
All the mentioned issues are addressed in the following sample:
public void readFromFile(String file) {
try (Scanner input = new Scanner(new File(file))) { // auto-close Scanner when done
List<Opera> readOperas = new ArrayList<>();
while(input.hasNextLine()) {
String line = input.nextLine();
String[] row = line.split("\\|");
Opera music = buildOpera(row); // create an opera
readOperas.add(music);
}
operas.clear();
operas.addAll(readOperas);
} catch (IOException ioex) {
// log the exception
}
}
static Opera buildOpera(String ... row) {
Opera opera = new Opera();
if (row.length > 0) { opera.setName(row[0]); }
if (row.length > 1) { opera.setComposer(row[1]); }
if (row.length > 2) { opera.setYear(Integer.parseInt(row[2])); }
if (row.length > 3) { opera.setCity(row[3]); }
if (row.length > 4) { opera.setSynopsis(row[4]); }
if (row.length > 5) { opera.setLink(row[5]); }
return opera;
}
Using Java Stream API along with java.nio classes would result in the following implementation (reusing method buildOpera):
public void readFromFile(String file) {
try {
List<Opera> readOperas = Files.lines(Path.of(inputFileName)) // get stream of lines from the input file
.map(s -> s.split("\\|")) // split a line into columns, get Stream<String[]>
.filter(row -> row.length == 6) // make sure a row contains full data
.map(MyClass::buildOpera)
.collect(Collectors.toList());
operas.clear();
operas.addAll(readOperas);
} catch (IOException ex) {
// log IO exception
}
}