Innanzitutto c'è una questione fondamentale: nella classe di una eccezione non va mai fatta alcuna interazione con l'utente ... tanto meno con una message box. Quindi rivedi e ripensa bene il tutto.![]()
Innanzitutto c'è una questione fondamentale: nella classe di una eccezione non va mai fatta alcuna interazione con l'utente ... tanto meno con una message box. Quindi rivedi e ripensa bene il tutto.![]()
Ultima modifica di andbin; 30-03-2015 a 23:30
Andrea, Senior Java developer – SCJP 5 (91%) • SCWCD 5 (94%)
Java Versions Cheat Sheet
Ho pensato di eliminare
inserendo un controllo sul valore di ritorno della classe, per esempio:codice:throw new DatiMeseInvalidiException("Identificatore non presente");
e quindi se String == null, mi mostra il warning message..che ne dici?codice:private String parseString(final BufferedReader reader, final String name1, final String name2, final boolean skipLast) throws DatiMeseInvalidiException { try { final String input = reader.readLine(); if (input != null && !input.trim().isEmpty() && (input.startsWith(name1) || input.startsWith(name2))) { int index = input.indexOf(":"); if (index < 0) { return null; } if (skipLast) { int indexV = input.indexOf(","); return input.substring(index + 1, indexV); } else { return input.substring(index + 1); } } return null; } catch (IOException ex) { Logger.getLogger(ApriFileMese.class.getName()).log(Level.SEVERE, null, ex); } return null; }
Perché una eccezione è solamente un semplice oggetto che viene istanziato, lanciato e poi catturato altrove, potenzialmente anche molto più a monte di dove è stata scatenata la eccezione. Non è la classe della eccezione che deve interagire con l'utente!
Una eccezione può eventualmente contenere informazioni extra, pertinenti al motivo della eccezione. Prendi come esempio una ipotetica ConfigurationKeyNotFoundException, una informazione extra potrebbe essere appunto la 'key' che non è stata trovata. Quindi potrebbe essere una cosa tipo:
codice:public class ConfigurationKeyNotFoundException extends Exception { private String key; public ConfigurationKeyNotFoundException(String key) { super(String.format("Configuration key '%s' not found", key)); this.key = key; } public String getKey() { return key; } }
Questo va bene, è assolutamente appropriato.
Ma le eccezioni, in generale:
- Non devono essere usate solo per "passare" informazioni da un punto ad un altro (più a monte) giusto solo perché farebbe comodo (sarebbe un abuso e non è quello l'obiettivo delle eccezioni).
- Non devono fare I/O in generale, a meno che sia pertinente alla eccezione, ad esempio per "localizzare" il messaggio.
- Non devono interagire con l'utente in alcun modo, meno che mai con delle message-box grafiche.
Se la eccezione è "importante" e oltretutto checked, dovrà essere catturata e gestita prima o poi da qualche parte a monte, e se dove gestisci la eccezione c'è una nozione chiara del contesto e di come deve avvenire l'interazione con l'utente, allora lì sì, puoi aprire una message-box di errore.
Già ... il problema è appunto tenere ben separati i concetti. Quel tuo metodo 'parseString' dove è messo? Visto che hai un file da gestire e con un formato ben preciso, mi aspetterei che tu abbia fatto una classe a sé stante che si occupa solo della lettura/parsing del file. Hai fatto così? O hai fatto un bel miscuglio di concetti in una unica classe?
Non, è peggio! Innanzitutto un 'null' molte volte è ambiguo e perlomeno dovresti documentare (senza che qualcuno debba per forza guardarsi il tuo codice e capire la logica) cosa significa un null restituito da parseString. Poi comunque la possibilità di un null, forza il chiamante a fare almeno un test, quindi ... più codice.
Inoltre null è solo uno, non hai altri valori speciali, quindi se ci sono diverse problematiche da segnalare, usare sempre e solo "null" è ovviamente molto restrittivo.
E infine, il fatto che a parseString passi un BufferedReader, dà abbastanza (a me perlomeno) l'idea che stai ragionando poco "ad oggetti".
E tutto questo che stai dicendo è quasi certamente un segno delle tue parole dei giorni scorsi: "Purtroppo non riesco ancora ad entrare nella logica del linguaggio ad oggetti...ma ci riuscirò"![]()
Ultima modifica di andbin; 31-03-2015 a 09:47
Andrea, Senior Java developer – SCJP 5 (91%) • SCWCD 5 (94%)
Java Versions Cheat Sheet
Questa è la classe che utilizza il metodo e che comprende il metodo per parsare le stringhe:
Come è visibile nella classe vado a parsare le righe del file txt per estrarne le informazioni utili. A questo punto, devo valutare il caso in cui il file è vuoto o parzialmente vuoto o comunque non riesco ad estrare le informazioni che mi servono.codice:public class ApriFileIrraggiamento { public Irraggiamento apriFiles(File directory) throws FileNotFoundException, IOException, DatiMeseInvalidiException { FileReader f = new FileReader(directory + File.separator + "Radiation.txt"); BufferedReader b = new BufferedReader(f); Irraggiamento irraggiamento = new Irraggiamento(); CalcolaMediaIrraggiamentoAnnuale mediaAnnuale = new CalcolaMediaIrraggiamentoAnnuale(); List<RegistrazioniIrraggiamenti> registrazioni = new ArrayList<>(); try { String latitude = parseString(b, "Lat", "Lati", true); String longitude = parseString(b, "Long", "Longi", false); b.readLine();// Potenza nominale del sistema FV String inclinazione = parseString(b, "Incli", "Inclin", false); String azimuth = parseString(b, "Orie", "Orient", false); b.readLine(); // empty b.readLine(); // Angolo fisso String[] intestazione = b.readLine().split("\\s+"); // intestazione if (intestazione.length >= 1) { int i; for (i = 0; i < intestazione.length; i++) { System.out.print(intestazione[i] + "\t"); } System.out.println(); } Coordinate coordinate = new Coordinate(latitude.trim(), longitude.trim(), inclinazione.trim(), azimuth.trim()); irraggiamento.setCoordinate(coordinate); String linea = b.readLine(); int i; for (i = 0; i < 12; i++) { if (linea != null && !linea.equals("")) { RegistrazioniIrraggiamenti registro = new RegistrazioniIrraggiamenti(linea.trim(), intestazione, intestazione.length); registrazioni.add(registro); linea = b.readLine(); } } irraggiamento.setRegistrazioniAnno(registrazioni); double mediaHm = mediaAnnuale.calcolaMediaIrraggiamentoAnno(irraggiamento); irraggiamento.setIrraggiamentoAnnualeHm(mediaHm); } finally { try { b.close(); } catch (IOException e) { } } return irraggiamento; } private String parseString(final BufferedReader reader, final String name1, final String name2, final boolean skipLast) throws DatiMeseInvalidiException { try { final String input = reader.readLine(); if (input != null && !input.trim().isEmpty() && (input.startsWith(name1) || input.startsWith(name2))) { int index = input.indexOf(":"); if (index < 0) { throw new DatiMeseInvalidiException("Identificatore non presente"); } if (skipLast) { int indexV = input.indexOf(","); return input.substring(index + 1, indexV); } else { return input.substring(index + 1); } } throw new DatiMeseInvalidiException("Identificatore non presente"); } catch (IOException ex) { Logger.getLogger(ApriFileMese.class.getName()).log(Level.SEVERE, null, ex); } return null; } }
Che consiglio mi daresti? Come dovrei procedere?
Grazie
Ultima modifica di roquentin; 31-03-2015 a 10:44
Il fatto di aver creato una classe a parte (ApriFileIrraggiamento) solo per la gestione del file, ok, è buono.
Se Irraggiamento rappresenta tutto il file (e mi pare di capire che è così), allora il fatto che parseString riceva il BufferedReader, tutto sommato potrebbe anche andare bene, perché tutta la gestione è in apriFiles e quindi per forza glielo deve passare.
Ma se ci pensi, e ragioni, parseString legge solo una riga e fa il parsing di quella riga. Quindi NON è affatto necessario che parseString riceva il BufferedReader. Basta che riceva la stringa.
Il parseString viene chiamato 4 volte da apriFiles e tu per evitare 4 readLine(), per questo hai passato il BufferedReader. Ma potevi fare es.
codice:String latitude = parseString(b.readLine(), "Lat", "Lati", true); ......
Che costava molto poco ....
Quello che va meno bene è che in parseString catturi IOException, fai un log (e questo va bene) ma poi finisce lì. No, quel IOException dovrebbe poter uscire da parseString e anche da apriFiles.
Ah, qui ad esempio:
String[] intestazione = b.readLine().split("\\s+"); // intestazione
non è molto buono: se readLine() restituisce null, ti becchi NullPointerException. Ma se ti dà null, vuol dire che sei a fine file e se quella riga te la aspettavi, vuol dire che il file è "malformato" e lo devi segnalare opportunamente.
Dovresti valutare questo aspetto in generale, anche per le altre readLine()
Ultima modifica di andbin; 01-04-2015 a 09:53
Andrea, Senior Java developer – SCJP 5 (91%) • SCWCD 5 (94%)
Java Versions Cheat Sheet
In effetti hai pienamente ragione ed ho fatto così:
Passando non il buffereader ma la singola stringa a ParseString, mi segnalava errore sulla catch causecodice:private String parseString(final String input, final String name1, final String name2, final boolean skipLast) { if (input != null && !input.trim().isEmpty() && (input.startsWith(name1) || input.startsWith(name2))) { int index = input.indexOf(":"); if (skipLast) { int indexV = input.indexOf(","); return input.substring(index + 1, indexV); } else { return input.substring(index + 1); } } return null; }
Infatti ho notato che se mi restituisce null, ho NullPointerException se non trova quella riga ma non capisco cosa vuoi dire concodice:exception IOException is never thrown in body of corresponding try statement