Newsgroup: it.comp.java
Titolo: domanda banale sul NullPointerException e condizioni

Ciao,
una cosa mi chiedo: mettiamo di avere un oggetto Persona con un 
attributo privato cognome, accedibile dall'esterno con il metodo getCognome.
Se io sono in un metodo in cui viene passata un'istanza di Persona (di 
cui non so nulla) e, prima di elaborarne il cognome, devo verificare se 
l'istanza non è null e successivamente anche se il cognome non è null, 
posso scrivere così?
if (persona != null  &&  persona.getCognome() != null){
     //tutto ok!
}
oppure rischio di avere una NullPointerException nel caso in cui persona 
sia null? In altre parole, la valutazione della condizione si ferma alla 
prima condizione (visto che è falsa e siamo in un AND) oppure viene 
valutata sempre anche la seconda (provocando una NullPointerException)?
Devo per forza scrivere così?
if (persona != null){
     if (persona.getCognome() != null){
         //tutto ok!
     }
}
Grazie.
-- 
SigiTM
Togli 'NOSPAMMM' per rispondermi.
http://it.youtube.com/profile_videos?user=sigitm

 sia null?
Usando l'operatore '&&' (AND condizionale) se la prima condizione è 
falsa la seconda non viene valutata.
Quindi se persona è null non viene controllato il valore di 
persona.getCognome().
Ciao.

 [...]
Dualmente nel valutare da sinistra a destra l'espressione A || B (con A 
e B booleani), se A ï¿œ true il risultato ï¿œ true senza bisogno di valutare B.
Per questo tipo di comportamento gli operatori && e || sono conosciuti 
anche col nome di short-circuit logical operators per differenziarli dai 
non short-circuit logical & e | che valutano sempre entrambi gli 
operandi, e per questo non sono efficienti.
Tarin
-- 
Tarin Gamberini
www.taringamberini.com

 Devo per forza scrivere così?
La cosa migliore sarebbe avere la certezza che i metodi non ti
restituiscano null e se devono protestare per qualche cosa lancino
un'eccezione.
-- 
-riko

 operandi, e per questo non sono efficienti.
No. Non è una questione di efficienza. Short-circuited evaluation ->
branch. Ovvero una delle cose fottutamente più costose per un processore
odierno. Poi sono d'accordo che questo si veda più in C che in Java, ma
il motivo non è l'efficienza: è la praticità della semantica.
if(p && p[0]) {
}
e simili sono il motivo per la loro esistenza. 
-- 
-riko

 Poi sono d'accordo che questo si veda più in C che in Java, 
?


 ?
Il punto è che le short-circuited operations sono nate ben prima di
Java. E vederle in C è più semplice.
-- 
-riko

Sottoscrivo il post di Enrico
citando anche
Robert C. Martin
1. "Prefer Exceptions to Returning Error Codes" e
SPECIAL CASE PATTERN [Fowler]
2. "Don’t Return Null" ma anche
3. "Don’t Pass Null"
luca 'neuromancer' lopomo.
On Nov 29, 7:59 pm, 
r...@despammed.com
 (Enrico Franchi) wrote:



Tra l'altro e' curioso come in Java che e' un linguaggio che
sintatticamente nasconde i puntatori ti ritorna un bel
NullPointerException....:)
luca

 luca 'neuromancer' lopomo.
Maybe. I prefer a more wise: beware how you behave.
--
ac

Enrico Franchi ha scritto:

Non sempre il null e' una protesta. Talvolta e' un modo educato di 
segnalarti e di segnalare qualcosa di utile. Ne faccio uso.
--
ac

 ac
è buona norma avere comunque valori di default e non null.
La regola indicata(per cui non bisogna usare null) è comunque valida.
Sono nati dei costrutti appositi per creare un nullObject, un oggetto
identico a quello vero, che non punta a niente, su cui posso
richiamare i metodi regolarmente, senza avere eccezioni, metodi che in
questo caso non fanno nulla (o ritornano un valore fisso).
Anche a me a volte capita di usare null, non sempre voglio duplicare
le classi e creare il nullObject. tutto dipende da cosa devi fare e
soprattutto considera che controllare continuamente se un valore è
null non è una buona cosa.

 segnalarti e di segnalare qualcosa di utile. Ne faccio uso.
E che cosa rappresenta il fatto di ritornare 'null'? null e' qualcosa su
cui non posso fare nulla salvo eventualmente testare che sia nulle e
poco altro. Pensa al valore semantico di una cosa chiamata
ElementNotFound.
Oltretutto se ogni metodo potesse realmente ritornare null, ci
troveremmo ad una sovrappopolazione di if(...) per controllare i valori
di ritorno [ sia per controllare che non sia successo qualcosa --
segnalazione --, sia per controllare che il valore ritornato non sia per
l'appunto null ].
No, decisamente non mi piace: mischia la gestione dell'errore (o degli
avvertimenti) con il flusso di codice normale. Capisco quando se sei in
C dove puoi fare poco altro, ma in Java... Oltretutto porta a metodi con
troppi costrutti di controllo, magari troppo lunghi. 
Penso sia accettabile solo in codice di basso livello molto incapsulato
da codice applicativo di livello piu' alto.
D'altra parte e' tutta roba nota e stranota da un bel po' di tempo: ci
sono quelli cui piace, e ci saranno sempre, figurati.
-- 
-riko

 Sottoscrivo il post di Enrico
Si beh, non e' una cosa che mi sono svegliato un giorno e l'ho detta io,
eh. :P
Sono familiare con i testi da te citati. Apprezzo moltissimo Martin, in
effetti.
-- 
-riko

 null non è una buona cosa.
E' piu' o meno cio' che sostengo. L'uso delle cose e' funzione del 
contesto. Null ha un suo ben preciso significato (anche sui DB) e trovo 
che sia indispensabile. Il null si controlla quando e' uno dei possibili 
valori di ritorno e lo ritengo piu' visibile ed "ecumenico" di un 
qualsiasi default o metodo di controllo.
L'utilizzo di "istanze" vergini e' fondamentale quando sono oggetti che 
contengono una struttura dati complessa, struttura che deve essere 
analizzata in modo dettagliato, in questo caso l'oggetto vuoto e', 
oserei dire, necessario.
Ti faccio un esempio banale. Cerchi una chiave che puo' esistere o meno. 
Puoi fare due cose, o un metodo di exist e torni true/false oppure fai 
una chiamata che puo' ritornarti un null. Uso entrambi i metodi e quando 
non  mi va di scrivere uso il secondo, probabilmente anche piu' 
"performante".
--
ac

 NullPointerException....:)
infatti se non lo facesse ti genererebbe un segmentation fault.

 è buona norma avere comunque valori di default e non null. 
questo è molto opinabile.
inizializzare con dei valori di default diversi da null ti pone di fronte 
al problema di sapere, in seguito, se quella reference contiene un valore 
significativo oppure no. il valore null è certamente non significativo.

 significativo oppure no. il valore null č certamente non significativo.
Concordo, anche se a volte ho dovuto far ricorso ad un metodo isValid() che, 
in pratica,
mi consentiva di stabilire se il mio oggetto fosse da considerare 
inizializzato correttamente
o meno.
Scorpio 


Un buon programma ad oggetti non dovrebbe avere controlli del tipo
if (object == null)
visto che comunque sono stati fatti molti sforzi proprio per evitare
proprio una roba del genere (pensa ai valori di default comunque
documentati, pensa ai nullObject, pensa a rendere obbligatorio
costruttore).
Il mio prof di programmazione ci diceva sempre: se fai numerosi
controlli a null, vuol dire che non stai programmando ad oggetti.
Tenendo in mente questo, ho imparato ad usare controlli del tipo
if (obj == null)
solo nei casi in cui era EFFETTIVAMENTE necessario.
L'inizializzazione dell'oggetto è SEMPRE prevista, tant'è che se
nessun costruttore è presente, se ne aggiunge uno di default (che non
fa niente) proprio per evitare valori di null alle variabili.
Se poi come variabili si hanno altri oggetti, è il programmatore che
deve curarsi di non creare nullPointerException.
Ti ricordo anche che per i tipi primitivi è comunque previsto un
valore di default, che tu o ricordi o puoi leggere dalla
documentazione.
Tu dici come mi ricordo i  valori di default? la documentazione a cosa
serve? In tutte le API che ho visto fin'ora, sono pochi i casi in cui
il valore di default o il valore non-sense viene indicato con null. So
che può essere noioso compilare la documentazione, ma 5 secondi persi
alla creazione della classe evitano numerosi errori in seguito.
@Scorpio
il controllo isValid() è un'altra cosa (se proprio vogliamo fare i
pignoli). Se il controllo ritorna "true" o "false" vuole dire che
l'oggetto è già VALIDO dal punto di vista riferimento (non ho un
riferimento a null) e tu vuoi controllare se è LOGICAMENTE valido per
la tua applicazione.
Hai spostato la validità su un altro piano.
Di solito dovresti fare 2 controlli per ogni oggetto che usi:
1. controllo a null (riferimento valido?)
2. controllo logico (oggetto valido per l'applicazione?)
prevedere valori di default e il costruttore che non sia quello di
default, consente di saltare nel 90% dei casi il controllo 1. Non è
indifferente il vantaggio che ottieni a livello di esecuzione (con
tutto ciò che consegue ogni salto condizionato), in java come in
qualsiasi altro linguaggio.
Dal mio punto di vista, da qualsiasi angolazione guardi il problema,
l'unica conclusione logica è USA IL MENO POSSIBILE NULL COME VALORE DI
DEFAULT!!!
Buon anno nuovo a tutti :-)
Valentina

 evitare valori di null alle variabili. 
si ma questo vale solo per le proprietà. le variabili però possono avere 
tanti scope, non solo di istanza. con le variabili locali, ad esempio, 
come ti comporti? proprio su quelle il compilatore ti *obbliga* a 
inizializzarle prima dell'uso, non solo, ma ti obbliga a farlo per tutti 
i percorsi di codice raggiungibile. classico esempio quello del try/catch/
finally e della java.sql.Connection che valorizzare dentro il try, 
chiudere dentro il finally e quindi dichiarare (e inizializzare, 
obbligatoriamente) fuori dal blocco, come la inizializzi? 

 chiarezza, linearita'.
Il punto e' che chiarezza e linearita' sono due valori *fondamentali*
nell'estetica del codice. C'e' codice che puzza e codice che colpisce
per la sua pulizia formale, per quanto trasuda di intenzione.
Generalmente preferiamo leggere il secondo, per cui direi anche che
cerchiamo di scriverlo.
Poi non siamo d'accordo sul fatto che l'uso di null renda spesso e
volentieri il codice meno lineare (e meno chiaro) e conseguentemente
meno bello. Direi che nulla che io possa dire potrebbe convincerti che
sia una cosa da usare in modo piuttosto eccezionale. Non e' nemmeno
detto che io abbia ragione, nota bene. Dubito viceversa che tu riesca a
convincermi che il codice che usa valori di ritorno per specificare
"errori" sia piu' pulito (e di fatto non ci hai provato, in effetti).
Nota, passare un null ad una funzione, per te cosa rappresenta?
-- 
-riko

 obbligatoriamente) fuori dal blocco, come la inizializzi?
in genere esiste sempre un costruttore di default che non fa NIENTE:
come vedi il costruttore risolve il problema dell'inizializzazione
(alla fine in un linguaggio di programmazione ad oggetti il
costruttore nasce proprio con quello scopo). Per quanto riguarda i
casi di sql o di variabili inizializzate all'interno del blocco try
catch cerca di comprimere le operazioni su quella variabile
all'interno del blocco e non hai bisogno del controllo a null. In
genere sono poche le operazioni che si riferiscono a var di quel tipo,
quindi comprimerle nel blocco non crea problemi, quello che guadagni
togliendole dal blocco, lo perdi nei continui controlli a null (e di
fatto complichi la lettura del codice).
Direte ma devi mettere tante cose dentro un blocco. Alla fine ho
imparato a fare li dentro solo lo stretto necessario, non ponendomi il
problema di controllare ogni 2 secondi se il valore è null o meno.
I modi per evitare le cose ci sono.
Nel caso di connessioni sql ci sono diversi modi di risolvere la
questione. quello che io trovo più comodo, non è detto che sia
corretto, ma ho un solo controllo a null (e sul result set non posso
giocare molto, se la query è andata male mi restituisce null) è
dichiarare le variabili all'esterno del blocco, all'interno stabilire
la connessione, eseguire la query, leggere il risultato. In generale x
lettura del risultato ti limiti a valorizzare una serie di oggetti,
CHE DOPO passi ad analizzare. Che so, fai una select per conoscere lo
stato del db e poi stamparlo: all'interno istanzi una serie di oggetti
e li valorizzi, stop. CI sono select particolari, in cui restituisce
un solo valore (e leggerlo è niente). Oppure query di insert o di
modifica o di cancellazione, che ritornano un solo valore (indicando
lo stato dell'operazione): roba che leggerla dentro al blocco non crea
problemi. Prepari il tutto fuori dal blocco e dentro devi fare solo la
query, comodo no?
In alcuni casi, se si prevedono continue operazioni, anzichè stabilire
la connessione ogni volta che serve, la stabilisci all'avvio del
programma. In questo caso sei sempre sicuro di avere una connessione
attiva (quindi la tua variabile conn non sarà mai null). Mi dirai, e
se dall'altro lato hanno chiuso? beh, si lancia un'eccezione, cosa che
puoi gestire dal programma principale, non dal metodo che tenta
l'accesso o con un controllo a null,
Ripeto, non è detto che la mia è una logica corretta, è quello che a
me più piace perchè elimina i fastidiosi controlli a null (rendendo
scorrevole il codice) e soprattutto quella che facilita la riusabilità
del codice.
Ovviamente qui si scatenano i flame, considerando la contemporaneità
dell'operazione fatta da utenti differenti, che possono variare il
risultato ecc. Non voglio di certo scatenare flame, la scelta va fatta
tenuto conto del contesto dell'applicazione e in alcuni contesti,
quella è la soluzione migliore.
Poi in tutti i programmi di un certo livello (che ho visto sia presso
l'azienda nella quale ho fatto tirocinio, sia presso l'azienda presso
cui adesso lavoro) i controlli del tipo
if (obj == null)
sono, in percentuale rispetto alle linee di codice scritte, prossimi a
zero, fatti solo in casi particolari, in cui non si possono evitare
(non c'è un valore di default o un valore logico che consenta di
eliminarli).
Poi sono pareri, tu mi dirai che fare al contrario è meglio. Bye

 Nota, passare un null ad una funzione, per te cosa rappresenta?
Evitare un "insensato overloading"?
Mea culpa, lo faccio! (certe volte passo un "empty")
String: 16 costruttori, salute! Solo per leggerli mi ci vuole 1/2 giornata.
Comunque grazie per il tuo punto di vista. Non credo che siamo cosi' 
distanti come puo' apparire.
Saluti.
--
ac
--
ac

 e' il *sugo* della faccenda.
In teoria il null dovrebbe essere _sempre_ un'eccezione ma solo quando 
non viene gestito [1].
Poi per comodità (e soprattutto prestazioni) si è scelto di usare 
un'eccezione unchecked per cui il try(null) è diventato if(null).
Personalmente ritengo preferibile usare il null (e relativi if) che:
a) è standard e uguale per tutti gli oggetti (a differenza dei vari 
metodi con oggetti istanziati, es. length, length(), size(), 
hasNext()... etc.);
b) è più semplice e leggibile;
c) distingue la dichiarazione dell'oggetto dalla sua creazione;
d) diventa indispensabile quando uso "oggetti" esterni (JNI, database).
Vero comunque che lo standard spingerebbe nella direzione opposta 
(evitare il null ove possibile) ma a quel punto avrebbe (avuto) più 
senso usare una checked exception, no?
Ciao.
[1] Gosling (The Java Programming Language): "Unchecked runtime 
exceptions represent conditions that, generally speaking, reflect errors 
in your program's logic and cannot be reasonably recovered from at run 
time."

 non viene gestito [1].
Il "ma" voleva essere un "non" :)

 distanti come puo' apparire.
Bene.
-- 
-riko

 time."
Questo ammesso di considerare le checked exceptions una buona idea, il
che ormai dovrebbe essere piuttosto chiaro che non e'. ;)
Anche perche' per fare null una checked exceptions bisognerebbe cambiare
il typesystem (e avere tipi *non* nullabili) oppure si avrebbe comunque
la proliferazione di strutture di controllo, che siano try e non if,
poco importa.
-- 
-riko

 Ciao.
Quoto!
--
a.c.
P.S.: Ho un particolare affetto verso gli asini. Animali di 
"intelligenza" superiore.

 foo(null)
Puo' succedere.
[cut]
saluti
--
ac

 "intelligenza" superiore.
Pensa che io li tengo in giardino. Ora col freddo hanno scassinato la 
serratura del garage e si son trasferiti lì, col risultato che ho l'auto 
ricoperta di neve.

 che ormai dovrebbe essere piuttosto chiaro che non e'. ;)
Probabilmente uno dei più grossi limiti del linguaggio.
IMVHO.