Newsgroup: it.comp.java
Titolo: Eccezioni lanciate da costruttori (domanda filosofica)

Ecco una domanda filosofica, che potrebbe anche non esserlo cosi tanto:
secondo voi ha senso lanciare un eccezione applicativa dal costruttore
di un oggetto? Per "eccezione applicativa" intendo una eccezione non di
runtime che esiste all'interno della nostra applicazione.
Confesso che non mi so decidere ;-)
Beh, innanzitutto, diciamo che e' sempre opportuno controllare i
parametri di ingresso di un costruttore per verificare che l'oggetto
venga creato in modo consistente (questo dovrebbe in essere fatto
comunque anche sui metodi). Ma se qualcosa va storto, ed un parametro
e' a null quando non dovrebbe esserlo, normalmente io mi limito a
lanciare una IllegalArgumentException ad indicare che un argomento
passato e' scorretto; lo stesso faccio quando un parametro e' al di
fuori del dominio dei valori accettabili (per esempio un mese che e' <1
o >12). Ma cosa ne pensate se invece di una IllegalArgumentException
(che č una RuntimeException) lanciassi una eccezione applicativa? Ha
senso? Me lo chiedo perche' poche classi nei package Java standard
(almeno fino a 1.1.8)  lo fanno. Ad esempio esiste java.net.URL che
lancia MalformedURLException, ma esistono anche java.io.File che non
lancia un bel tubo di nulla (se non qualche RuntimeException) e
java.util.Hashtable che lancia una IllegalArgumentException (anch'essa
una RuntimeException)
A voi la palla: cosa ne pensate? Mi sono spiegato? C'e' una "rule of
thumb" da seguire? Se si, perchč?
Ciao e grazie in anticipo,
    Bruno.
--
Bruno Bossola, a Java Developer
Sent via Deja.com 
http://www.deja.com/
Before you buy.

 thumb" da seguire? Se si, perchè?
beh, lanciare una eccezione "checked" costringe l'utilizzatore a
"copulare" (la mia personale traduzione di "cope") con l'eccezione ed
evitare errori più difficili da gestire in seguito. Poi ovviamente il
contesto la fa da padrone.
ciao
-- 
Ugo
__________________________________________________________________________
"La perfezione si ottiene non quando non c'è nient'altro da aggiungere, 
 bensì quando non c'è più niente da togliere." Antoine de Saint-Exupéry
__________________________________________________________________________
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Enterprise Java Consulting
@mail: Ugo.L...@Flashnet.it
Home Page: 
http://www.ugolandini.net
Mentoring: 
http://www.projectoo.com
Work Phone: 06/5814740
Fax Phone: 06/233207542 
Cell Phone: 0347/6310749 - 0347/4783580
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

[...]
Ottimo argomento. :)
In sintesi, la penso come Ugo anch'io. Aggiungo che, talvolta, in caso di 
interazioni particolarmente complesse e multi-tier, puo' valer la pena di 
costruire una *gerarchia* di eccezioni, e sollevare nel corpo del 
costruttore sottoclassi dell'eccezione/i di base indicate nella throw. Come 
rule of thumb, io mi baso sulla complessita' del sequence diagram al 
livello di architettura pertinente alla classe in via di definizione - 
business, design, implementazione, eccetera). Pero' se non e' fatto piu' 
che attentamente, lascia il tempo che trova e non aggiunge alcun reale 
vantaggio, come ho imparato a mie spese ;-). Quindi, a meno non sia 
proprio necessario, le mie gerarchie di eccezioni tendono ad essere 
piuttosto piatte.
Un'altro aspetto interessante della questione (ricorrente ad esempio con 
sistemi distribuiti), e' quello della divisione tra eccezioni applicative, 
di libreria, di sistema, eccetera.
L'approccio radicalmente pulito vorrebbe una corrispondenza netta tra 
livello architetturale (come sopra: business, design applicativo, design di 
libreria, framework eccetera) ed eccezione. Il problema e' che in tal caso 
esser radicali costa parecchio, e spesso non da' grossi vantaggi.
Un classico e' "RemoteException". Se succede un guaio all'oggetto remoto, 
per cui non e' in grado di completare un servizio, che si fa? Si solleva 
una RemoteException? Pero' la stessa eccezione e' usata per il livello di 
comunicazione - ad esempio un problema nell'unmarshalling - quindi non e' 
bello. Si estende RemoteException? Okay, pero' si ha un problema di cattiva 
classificazione - usando essenzialmente l'inheritance per riusare 
implementazione, che non e' mai buona cosa.
La mia soluzione al momento e' quella di riservare RemoteException (o 
l'eccezione/i di libreria del caso) a problemi di comunicazione RMI, e 
ridefinire eccezioni applicative tout court, dove pero' "applicative" non 
riguarda la "topologia" dell'applicazione.
Pero' talvolta questo porta a duplicazione di eccezioni sostanzialmente 
identiche (nel senso che incapsulano la stessa situazione) a livelli 
diversi; con scarso vantaggio, dato che il risultato netto finale (la 
"reazione" del codice client) e' spesso lo stesso: per dire, di solito poco 
importa se il mio server fallisce perche' la rete e' giu' tra lui e il 
client o perche' e' giu' tra lui e il servizio su mainframe a cui fa da 
wrapper. E' fallito, e il servizio e' giu'.
Inoltre, in casi complicati, con molte possibili eccezioni applicative, 
questo ha anche lo svantaggio di rendere potenzialmente meno manutenibile 
il codice client. Idee?
(Spero di essere intelleggibile: e' tardi e non ho caffe' a portata di 
mano :)
-- 
God is Real, unless declared Integer.
ObjectZone - 
http://space.tin.it/computer/csadun



> consistente
Allora, cerco di restringere il campo della domanda:
Assumendo il fatto che un costruttore lanci un eccezione per indicare
un errore nell'inizializzazione dell'oggetto, questa eccezione deve
essere di runtime o non di runtime? E in base a cosa effettuare la
scelta?
Come dice Ugo, e' il contesto che la fa da padrone? Io sono ancora
indeciso... non riusciamo ad individuare una regola?
Scusatemi se nel post precedente non sono stato chiaro.
Ciao,
    Bruno.



In progetti semplici come rule of thumb scelgo le classi delle
eccezioni cercando quelle che danno valore e raccogliendo quelle che
invece di valore ne danno poco in una generica "ApplicationException" o
simile.
In progetti complessi tendo ad usare una gerarchia di classi piu'
verticale: allo scendere dell'albero le eccezioni sono sempre +
specifiche ma consegnano valore sempre minore, anche se + ricco di
particolari: questo mi consente dal lato chiamante di catturare le
eccezioni al livello di valore che mi serve.
Effettivamente, comunque, e' un problema spinoso ;-)


 Confesso che non mi so decidere ;-)
Ciao Bruno.
<CHIACCHIERE>
L'idea non mi giunge nuova, avevo sviluppato un piccolo framework qui in
ufficio che lanciava una delle tre eccezioni definite all'interno
dell'applicazione, se un costruttore non andava a buon fine. Invece a casa
mi sto sviluppando una trapplet (termine coniato da me in questo momento,
grazie ad una crisi di sonno che non mi fa ancora connettere a modo, e che
indica genericamente una classe trappolina, ah ah ah) per gestire un
insieme di pool di connessioni (a database differenti, sennò dove sta il
divertimento?) che però mi lancia unicamente InstantiationException e le
altre due eccezioni di Runtime di Class.forName(driver).newInstance().
Anche io molto spesso quando costruisco... ehm... costruttori non saprei
quale eccezione sollevare. L'importante è anche per me sollevare eccezioni,
poi che sia una eccezione applicativa o di Runtime poco mi importa -
probabilmente perchè i miei progetti finora si sono limitati a qualche
decina di classi, e quindi per questo costruirmi una clase che sottoclassi
una eccezione in questi casi mi dà solo noia.
</CHIACCHIERE>
<RISPOSTA>
Forse la cosa migliore sarebbe lasciar passare tutte le eccezioni di
Runtime ed eventualmente lanciare eccezioni applicative dovute a parametri
errati et similia.
</RISPOSTA>
<CHIACCHIERE>
Just my 2 cents, ma essendo un discorso filosofico non potevo che
contribuire con molto fumo... Essendo stamani pure in vena di acronimi,
YMMV, e pure IIETTYWYOMAD (ma occhio che questo è pericoloso se non lo
conosci).
<CHIACCHIERE>
Ciao,
 Stefano
----------
"X WindowSSS, teSSSoro mio... lo odieremo per SSSempre"
Bill Gollum
----------

eccezione applicativa non di runtime?
Scusa, non avevo capito niente. :)
Se i parametri possono "arrivare" solo da codice, di norma io uso eccezioni 
unchecked - RuntimeException o IllegalArgument.
L'idea e' che se il programmatore sbaglia, sta violando il contratto del 
metodo, e quindi e' lecita un'eccezione/errore runtime.
Eccezioni a questo sono casi in cui - per qualunque motivo - un testing 
statisticamente utile e' impossibile o troppo costoso, oppure la robustezza e' 
una priorita' a livello molto alto.
Se i parametri invece arrivano da fonti esterne, per cui l'"errore" e' un 
comportamento ammissibile nel modello, le eccezioni sono checked. Con un 
costruttore, cio' non mi accade quasi mai.
Un parametro "esterno" (ad esempio proveniente da un widget GUI) di norma viene 
trasformato in uno "interno" da un Validator - nel senso che se passa la 
validazione da li' in poi e' considerato corretto, e se e' sbagliato generera' 
un'eccezione runtime, unchecked.
Ho usato spesso quest'approccio e mi trovo in generale benone.
-- 
God is Real, unless declared Integer.
ObjectZone - 
http://space.tin.it/computer/csadun/