9 errori da evitare durante la programmazione in Java
Rafal Sawicki
Sviluppatore Java
Quali sono gli errori da evitare durante la programmazione in Java? Nel pezzo che segue rispondiamo a questa domanda.
Java è un linguaggio popolare con una posizione consolidata nel mondo del sviluppo software. È un linguaggio di programmazione forte e versatile. Circa 3 miliardi di dispositivi in tutto il mondo funzionano con Java e, pertanto, sono stati commessi almeno 3 miliardi di errori durante il suo utilizzo. In questo articolo ci concentriamo su come non commetterne altri.
1. Ottenere l'eccezione di modifica concorrente
Questo è di gran lunga l'errore più comune in cui mi sono imbattuto. All'inizio della mia carriera, l'ho fatto anch'io molte volte. Questo errore si verifica quando si cerca di modificare l'insieme mentre si itera attraverso di esso. Il ConcurrentModificationException può essere sollevato anche quando si lavora con più thread, ma per ora concentriamoci su uno scenario di base.
Si supponga di avere un Collezione di utenti, alcuni dei quali sono adulti e altri no. Il vostro compito è quello di filtrare i bambini.
for (User : users) {
if (!user.isAdult()) {
users.remove(user);
}
}
Esecuzione del già citato codice finisce per ottenere ConcurrentModificationException. Dove abbiamo sbagliato? Prima di terminare la nostra iterazione, abbiamo cercato di rimuovere alcuni elementi. È questo che scatena l'eccezione.
Come posso evitarlo?
In questo caso, ci sono un paio di approcci che possono essere utili. In primo luogo, è possibile sfruttare Java La bontà dell'8 - Flusso.
Lista adulti = utenti.stream()
.filter(User::isAdult)
.toList();
Utilizzando un Predicato abbiamo fatto l'inverso della condizione precedente: ora determiniamo gli elementi da includere. Il vantaggio di questo approccio è che è facile concatenare altre funzioni dopo la rimozione, per esempio mappa. Ma per carità, non provate a fare qualcosa di simile a quanto segue:
Potrebbe anche finire nel ConcurrentModificationException perché si sta modificando l'origine del flusso. Può anche dare altre eccezioni che non saranno facili da debuggare.
Per risolvere ConcurrentModificationException in uno scenario a thread singolo. si potrebbe anche passare a usare direttamente Iteratore e il suo rimuovere() oppure si può semplicemente non rimuovere gli elementi durante l'iterazione. Tuttavia, la mia raccomandazione è di usare Flussi - è il 2022.
2. Memorizzazione delle password come stringhe
Dato che mi occupo sempre più di cybersec, non sarei sincero con me stesso se non menzionassi almeno uno dei seguenti elementi Errore Java che può portare a un problema di sicurezza. Memorizzare le password ricevute dagli utenti in un Stringa L'oggetto è esattamente qualcosa di cui si dovrebbe avere paura.
Il problema (o forse il vantaggio) di Stringa è che è immutabile. Nel mondo cibernetico, questo crea una potenziale minaccia, poiché non è possibile cancellare il valore di un oggetto creato una volta. Stringa oggetto. L'aggressore che riesce ad accedere alla memoria del computer può trovarvi le password in chiaro.
In secondo luogo, le stringhe in Java sono internati dalla JVM e memorizzati nello spazio PermGen o nello spazio heap. Quando si crea un oggetto Stringa viene memorizzata nella cache e viene rimossa solo quando il Garbage Collector inizia a fare il suo lavoro. Non è possibile sapere con certezza quando la password viene eliminata dal pool di stringhe, poiché il Garbage Collector lavora in modo non deterministico.
Come evitarlo?
L'approccio consigliato è quello di utilizzare char[] o, meglio ancora, la libreria che supporta la memorizzazione delle password come char[], ad es.Password4j. Il char[] è mutabile e può essere modificato dopo essere stato inizializzato. Dopo aver elaborato una password, è possibile cancellare l'array char[] scrivendo caratteri casuali all'interno dell'array di password. Se gli aggressori riescono ad accedere alla memoria del computer, vedranno solo alcuni valori casuali che non hanno nulla a che fare con le password degli utenti.
3. (Dis)gestire le eccezioni
I neofiti e anche i programmatori più avanzati non sanno come gestire correttamente le eccezioni. Il loro peccato principale è ignorarle e basta. NON È MAI UN BUON APPROCCIO.
Purtroppo non possiamo fornire una soluzione d'argento che si adatti a tutti i casi. Eccezionescenario in cui ci si imbatte. Dovete pensare a ogni caso separatamente. Tuttavia, possiamo darvi alcuni consigli su come iniziare a lavorare su questo argomento.
Come posso evitarlo?
Ignorare Eccezionenon è mai una buona pratica. Eccezionesono inseriti per qualche motivo, quindi non vanno ignorati.
try {...} catch(Exception e) { log(e); } è raramente l'approccio corretto per Eccezione manipolazione.
Lancio Eccezione, mostrare una finestra di dialogo di errore all'utente o almeno aggiungere un messaggio esauriente al registro.
Se avete lasciato le eccezioni non gestite (cosa che non dovreste fare), almeno spiegatevi nei commenti.
4. Utilizzo di null
Sfortunatamente, è abbastanza comune trovare una funzione Java che in alcuni casi restituisce un valore di nullo. Il problema è che una funzione di questo tipo impone al suo client di eseguire un controllo di nullità sul risultato. Senza di esso, il Eccezione NullPointer viene lanciato.
L'altra cosa è passare un oggetto nullo valore. Perché ci avete pensato? In questo caso, la funzione deve eseguire un controllo di nullità. Quando si utilizzano librerie di terze parti, non è possibile modificare l'interno delle funzioni. Cosa succede allora?
Ma soprattutto, gli altri sviluppatori che leggono il vostro codice e vedono che passate nullo probabilmente saranno disorientati dal motivo per cui avete scelto un modo così bizzarro per implementare la vostra funzione.
Come posso evitarlo?
Non restituire un valore nullo valore! Mai! Nel caso in cui la vostra funzione restituisca un qualche tipo di Collezioneè sufficiente restituire un file vuoto Collezione. Se si ha a che fare con oggetti singoli, si può utilizzare il modello di progettazione dell'oggetto null. Dal momento che Java 8, è implementato come Opzionale. A parte questo, l'approccio meno consigliato è quello di sollevare un Eccezione.
5. Concatenazione pesante di stringhe
Si spera che non sia un errore che si commette, visto che è la domanda più popolare (o forse la seconda dopo FizzBuzz) nei colloqui di lavoro. Come ormai dovreste sapere, un Stringa è immutabile in Java - una volta creato, non può essere modificato. Quindi la concatenazione di Stringa letterali comporta un'allocazione di memoria non necessaria. Concatenare Stringa ogni volta richiede la creazione di un file temporaneo Costruttore di stringhe e cambiarlo di nuovo in una stringa. Pertanto, questa soluzione non è assolutamente adatta se si vuole combinare un gran numero di caratteri.
Come posso evitarlo?
Per risolvere questo problema, utilizzare Costruttore di stringhe. Crea un oggetto mutabile che può essere facilmente manipolato. Naturalmente, si può sempre usare StringBuffer se il vostro progetto viene utilizzato in un contesto concorrente.
6. Non utilizzare le soluzioni esistenti
Quando si sviluppa un software, conoscere le basi del linguaggio in cui si scrive è d'obbligo, ma non è sufficiente. Molti problemi algoritmici che si incontrano durante l'implementazione di una nuova funzionalità sono già stati risolti da qualcun altro. Troppe volte ho visto qualcuno implementare un algoritmo di sicurezza da zero. Questo approccio è soggetto a errori. Una sola persona non può testare a fondo una soluzione così complessa. La conoscenza collettiva della squadra che consiste in programmatori di livello medio-avanzato è quasi sempre migliore della grandezza di un prodigio Sviluppatore Java. Non è necessario reinventare la ruota: basta adattare la soluzione esistente alle proprie esigenze.
Come posso evitarlo?
Cercate di trovare librerie che affrontino il problema su cui state lavorando. Cercate di trovare soluzioni simili. Molte delle librerie disponibili sul web sono gratuite e sono state perfezionate e testate da sviluppatori esperti e dall'intera comunità Java. Non abbiate paura di utilizzarle.
7. Non trovare abbastanza tempo per scrivere i test
Si è tentati di credere che il nostro codice funzionerà sempre alla perfezione. Non scrivere test per il codice è il peggior peccato del Java sviluppatori di software. Molti di noi preferiscono i test manuali ed esplorativi invece dei test unitari, il che è assurdo. <Perché perdere tempo a scrivere test quando ci si può concentrare sul fornire il miglior codice del mondo per il proprio progetto, che DEFINITIVAMENTE non ha bug? La realtà è brutale e non possiamo fornire codice di alta qualità senza scrivere test.
Come posso evitarlo?
Dovreste sempre preparare dei test per il vostro codice. So che l'approccio TDD non è così facile da mantenere, ma dovreste almeno fornire test che coprano tutte le condizioni in cui il vostro codice può essere eseguito. Questo include la verifica di situazioni eccezionali. I test unitari sono necessari. Dovete fornirli per ogni caratteristica del vostro progetto, se volete assicurarvi che il vostro codice sia facile da rifattorizzare e da estendere in un ulteriore sviluppo.
Un'altra cosa. Mantenete un elevato standard del vostro codice di test: ne varrà la pena. Questo è il consiglio dello zio Bob, che condivido pienamente.
Inoltre, non dimenticate altri tipi di test. I test di integrazione sono un elemento da considerare in ogni progetto.
8. Dimenticare i modificatori di accesso
Privato e pubblico, giusto? Come possiamo dimenticarci di loro? Si scopre che ce ne sono altri. Quando avete iniziato a imparare Java, avrete sicuramente imparato a conoscere i modificatori di accesso protetto. Possono essere utili in alcuni casi, quindi vale la pena conoscerne l'esistenza.
Sviluppatori Java spesso sembra che ci si dimentichi dell'ambito del pacchetto. È facile non ricordarsi di usarlo, dato che è implicito e non richiede alcun Java parole chiave. L'ambito del pacchetto è importante. Permette di testare un metodo protetto. Gli elementi protetti sono accessibili dal percorso della classe di test, purché il pacchetto sia lo stesso.
Come posso evitarlo?
Ricordate il modificatore protected e che l'ambito del pacchetto consente di testarlo.
9. Utilizzo di JavaEE puro invece di Spring
Il passo successivo all'apprendimento Java SE è imparare a gestire Java sui server, come creare un'applicazione di livello aziendale.
I neofiti spesso cadono nella trappola di imparare JavaEE, dato che esiste un numero enorme di tutorial al riguardo. Anche "Thinking in Java", il Programmatori Java', menziona JavaEE e non dice nulla sulle altre opzioni.
Come posso evitarlo?
JavaEE è una canzone del passato. Al giorno d'oggi, Spring è una cosa da fare e Java EE è solo una cosa da avere. Ogni moderna applicazione di livello aziendale utilizza Spring, quindi dovreste prendere in considerazione l'idea di apprendere qui.