Java/Trucchi e consigli
Lunghi if... else if e switch
[modifica | modifica sorgente]È preferibile evitare il più possibile di costruire lunghe sequenze di if... else if; ed è preferibile evitare l'uso dello switch, se si può ricorrere ad alternative più concise ed eleganti. Ad esempio, il seguente codice
int numero = ...;
if (numero == 1)
System.out.println(unaStringa);
else if (numero == 2)
System.out.println(numero);
else if (numero == 3)
System.out.println(true);
else
System.out.println("Errore");
può essere convertito in questo (facendo uso degli array):
int numero = ...;
final Object valori[] = {unaStringa, numero, true},
fallback = "Errore";
System.out.println(
numero < valori.length? valori[numero] : fallback
);
Se un giorno si dovesse modificare l'elenco delle opzioni (aggiungerne o rimuoverne una, oppure riordinarle, cambiando l'associazione tra numero e valore visualizzato a schermo), sarà ora necessario modificare solo una riga. Inoltre, non si è persa la leggibilità del codice, anzi, se ne è acquistata: ora tutte le opzioni sono visibili a colpo d'occhio, in due righe.
In alternativa, se si utilizzasse un identificatore di tipo String, anziché int, si potrebbe utilizzare il seguente codice:
String id = ...;
final Map<String, Object> valori = new HashMap<String, Object>();
valori.put("1", unaStringa);
valori.put("2", numero);
valori.put("3", true);
final String fallback = "Errore";
System.out.println(valori.contains(id)? valori.get(id) : fallback);
Più in generale, con una java.util.Map si può fare uso di qualunque classe che implementi correttamente il metodo equals() di Object.
Ovviamente, le trasformazioni presentate non possono essere applicate sempre; ad esempio, nel caso in cui ci fosse qualche altra istruzione oltre al System.out.println() in qualcuno dei casi previsti dalla catena di if. Queste trasformazioni possono essere ugualmente prese come spunto ed adattate di volta in volta al singolo caso specifico.
Warnings in compilazione
[modifica | modifica sorgente]Sono sempre più diffusi compilatori che controllano che il programmatore abbia realmente scritto quello che intendeva scrivere. Alcuni lo fanno per default; altri lo fanno o no a seconda del valore di certe flag che il programmatore loro passa in qualche modo, in fase di compilazione. Ad esempio, javac è dotato dell'opzione -Xlint:all, che permette di abilitare tutti i controlli.
Esistono anche programmi specializzati nell'analisi del codice (ma che non fanno da compilatori) e che spesso generano una quantità di warning che il compilatore stesso non ha generato.
Alcuni errori che potrebbero essere commessi si trovano alla pagina Errori e miti. Il consiglio è quello di leggere sempre le warnings che vengono segnalate durante la compilazione e, se possibile, di configurare il compilatore in modo da attivare quanti più controlli possibili. Nella maggior parte dei casi, si tratta di errori di distrazione o dell'uso di pattern o pratiche di programmazione sconsigliati. Però, capita anche che il compilatore segnali codice che, nel caso specifico, corrisponde alle reali intenzioni di chi l'ha scritto (non perché si tratti di un "falso positivo", ma perché uno stesso costrutto può risultare utile, se non indispensabile, in un contesto, ma inopportuno in un altro).
Con la terza edizione della specifica di linguaggio (in concomitanza con l'uscita della versione 5 della piattaforma), è stato introdotto un meccanismo volto a favorire l'uso delle warnings: il programmatore può utilizzare l'annotazione @SuppressWarnings per marcare un elemento del programma in cui è contenuto del codice che il compilatore in uso segnala con una warning e che il programmatore sa essere corrispondente ad una propria scelta intenzionale. L'argomento passato all'annotazione indica la categoria a cui appartiene la warning in questione: il compilatore si asterrà dal segnalare warnings relative al codice marcato e appartenenti a tale categoria.
Da ricordare a tale proposito:
- è preferibile annotare sempre e solo l'elemento di programma più piccolo che contiene il codice "problematico". In altre parole, se il codice si trova all'interno di un metodo, è preferibile annotare quel metodo, non l'intera classe. Altrimenti risulterebbero automaticamente marcati anche gli altri metodi (e gli altri membri: classi interne, campi, ecc.) presenti nella classe (si pensi a future modifiche del codice apportate a metodi diversi da quello che contiene il codice "problematico").
Compile-time type
[modifica | modifica sorgente]Quando hai un dubbio su come il compilatore tradurrà una certa istruzione, può esserti utile controllare il tipo che le variabili o le espressioni hanno a tempo di compilazione (compile-time type
). Infatti, una delle proprietà più utili del linguaggio Java è che il compilatore traduce i riferimenti alle variabili a prescindere dai valori che sono stati assegnati (quindi anche a prescindere da come queste variabili sono state inizializzate) e traduce le espressioni a prescindere dalla loro struttura interna o dal valore e dal tipo che avranno a run-time. Questa proprietà si rivela molto utile quando si legge del codice e si cerca di capire il comportamento del compilatore di fronte a quel codice.
Regole di buona programmazione
[modifica | modifica sorgente]Ci sono norme che non è obbligatorio seguire nella scrittura del codice, ma che sono comunque dettate dal buon senso (o dall'esperienza). Molte di esse possono essere anche estese ad altri linguaggi oltre al Java (spesso si tratta di norme di progettazione che sono valide in generale nell'ambito della programmazione). Esempi:
- si vedano Design pattern e Anti-pattern; List of software development philosophies
- in Rete si trovano moltissimi articoli che forniscono idee e linee guida al riguardo; eccone alcuni:
- alcune regole di buona programmazione si trovano nella stessa JLS
- The CERT Oracle Secure Coding Standard for Java