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 String
s
- 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
}
}