Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 12

Discussione: gestione eccezioni

  1. #1
    Utente di HTML.it
    Registrato dal
    Oct 2014
    Messaggi
    315

    gestione eccezioni

    Sto svolgendo un esercizio sulle eccezioni e vorrei chiarirmi bene le idee.

    Consideriamo queste classi:
    codice:
    public class TestFileSorgente {
        public static void main(String args[])
        {
            FileSorgente file = new FileSorgente("File.java",1,"public class TestFileSorgente ");
            System.out.println(file.getContenuto());
            
            file.aggiungiTesto("{");
            System.out.println(file.getContenuto());
            
            file.aggiungiTesto(null);
            System.out.println(file.getContenuto());
            
            file.aggiungiTesto("}",31);
            System.out.println(file.getContenuto());
            
            file.aggiungiTesto("// testo",31);
            System.out.println(file.getContenuto());
            
        }
    
    }
    codice:
    import java.lang.String;
    
    public class FileSorgente extends File
    {
        private String contenuto;
        
        public FileSorgente(String nome, int tipo, String contenuto)
        {
            super(nome,tipo);
            setContenuto(contenuto);
        }
        
        public void setContenuto(String contenuto)
        {
            this.contenuto = contenuto;
        }
        
        public String getContenuto()
        {
            return contenuto;
        }
    
        public String aggiungiTesto(String testo) throws RuntimeException
        {
            if (contenuto == null)
            {
                contenuto = "";
            }
            if (testo == null)
            {
                throw new RuntimeException();
            }
            contenuto += testo;
            return contenuto;
        }
        
        public String aggiungiTesto(String testo, int posizione)
        {
            try
            {
                if (testo != null)
                {
                    contenuto = contenuto.substring(0, posizione) + testo + contenuto.substring(posizione);
                }
            }
            catch (NullPointerException exc)
            {
                System.out.println("Il contenuto è null : " + exc.getMessage());
                contenuto = "" + testo;
            }
            catch (StringIndexOutOfBoundsException exc)
            {
                System.out.println("L'indice " + posizione + "non è valido : " + exc.getMessage());
                contenuto = (posizione < 0 ? testo + contenuto : contenuto + testo);
            }
            
            return contenuto;
        }
        
        
        public void cercaEsostituisci(String cercato, String parola)
        {
            String stringa = this.getContenuto();
            if(stringa.contains(cercato))
            {
                String risultato = stringa.replace(cercato,parola);
                this.setContenuto(risultato);
            }
            
        }
            
    }
    Veniamo a quello che vorrei capire:
    1) Nel main è corretto che non ci siano blocchi try-catch perchè il main deve rimanere il più "pulito" possibile e quel tipo di controlli vanno effettuati dentro l'implementazione del metodo che si vuole tenere sotto controllo e non dove viene richiamato. Giusto?

    2) Nel caso in cui io volessi creare un file senza contenuto per come ho fatto il metodo aggiungiTesto(testo,posizione) questo dovrebbe generare una NullPointerException perchè appunto il contenuto risulta null.
    Se io però creassi un oggetto di tipo FileSorgente e non specificassi al momento dell'istanziazione la stringa del contenuto mi sarebbe subito segnalato come errore e non mi permetterebbe neanche di compilare. Quindi che senso ha inserire la gestione di una NullPointerException nel metodo aggiungiTesto(testo,posizione) se non riuscirei neanche a compilare il file a causa dell'errore?

    3) Qual è la differenza tra la gestione delle eccezioni nel metodo aggiungiTesto(testo) e la gestione delle eccezioni nel metodo aggiungiTesto(testo,posizione)? Nel primo caso viene usato throws e throw mentre nel secondo i blocchi try-catch ma ad esempio non mi è chiaro dove viene catturata l'eccezione generata nel metodo aggiungiTesto(testo) visto che non c'è una catch.

  2. #2
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,320
    Risposte:

    1) No, la "pulizia" del main non c'entra assolutamente. Nel tuo caso, nel main non ci sono blocchi try/catch perchè il codice che tu usi non può in nessun caso lanciare eccezioni checked. L'unico metodo da te usato che può lanciare eccezioni è il metodo aggiungiTesto(String), che però lancia una eccezione unchecked (RuntimeException). Il compilatore guarda solo a cosa tu invochi: se invochi un metodo che dichiara (throws) di poter lanciare eccezioni checked, allora il compilatore ti costringerà ad usare un blocco try/catch o a rilanciare quella/quelle eccezioni dal metodo in cui possono essere sollevate (che sia nel main o in qualunque altro metodo, al compilatore frega nulla).

    2) Premesso che catturare e gestire una NullPointerException nel 99% dei casi non ha alcun senso (preciso dopo), non è vero che tu non puoi creare un oggetto FileSorgente con contenuto nullo. Prova così:


    codice:
    FileSorgente sorg = new FileSorgente("pippo.java", 1, null);

    Questo codice è perfettamente lecito, compila e ti riporta esattamente nel caso in esame.

    3) Il primo metodo, infatti, non gestisce alcuna eccezione, ma semplicemente ne genera una nel caso in cui vi sia quella particolare condizione. E' il chiamante che (a sua discrezione: poichè è una eccezione unchecked) eventualmente dovrà occuparsi di gestirla. Il secondo metodo, al contrario, si occupa di gestire tutte le eventuali eccezioni che possono sollevarsi durante l'esecuzione del codice: quindi lui non delega a nessuno l'onere di gestire eccezioni; fa tutto lui, si arrangia.


    Precisazione sulla NPE (NullPointerException): a parte casi particolari (programmi che, generalmente, analizzano sorgenti o servono ad aiutare le fasi di sviluppo o usano dati provenienti da librerie/programmi di terze parti), una NullPointerException rappresenta un errore nel programma. E un errore non va "gestito": va corretto. Una NPE viene sollevata quando si cerca di usare un oggetto che è nullo. Quando non si è sicuri della reale istanziazione di un oggetto (perchè proviene da codice esterno, di cui non si ha il controllo) ci si dovrebbe fare carico di controllare prima la non nullità del riferimento; se viene sollevata durante l'esecuzione di un programma, allora ci si deve preoccupare di capire perchè quel tale oggetto in quell'istante è nullo. Da questo ne consegue che non ha nessun senso catturare e gestire una NPE.


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  3. #3
    Utente di HTML.it
    Registrato dal
    Oct 2014
    Messaggi
    315
    Quote Originariamente inviata da LeleFT Visualizza il messaggio
    Risposte:

    1) No, la "pulizia" del main non c'entra assolutamente. Nel tuo caso, nel main non ci sono blocchi try/catch perchè il codice che tu usi non può in nessun caso lanciare eccezioni checked. L'unico metodo da te usato che può lanciare eccezioni è il metodo aggiungiTesto(String), che però lancia una eccezione unchecked (RuntimeException). Il compilatore guarda solo a cosa tu invochi: se invochi un metodo che dichiara (throws) di poter lanciare eccezioni checked, allora il compilatore ti costringerà ad usare un blocco try/catch o a rilanciare quella/quelle eccezioni dal metodo in cui possono essere sollevate (che sia nel main o in qualunque altro metodo, al compilatore frega nulla).
    Se io modificassi il codice in questo modo:
    codice:
    public class TestFileSorgente {
        public static void main(String args[])
        {
            FileSorgente file = new FileSorgente("File.java",1,"public class TestFileSorgente ");
            System.out.println(file.getContenuto());
            
            try
            {
                file.aggiungiTesto("{");
                System.out.println(file.getContenuto());
            
                file.aggiungiTesto(null);
                System.out.println(file.getContenuto());
            
                file.aggiungiTesto("}",31);
                System.out.println(file.getContenuto());
            
                file.aggiungiTesto("// testo",31);
                System.out.println(file.getContenuto());
            }
            catch(NullPointerException exc)
            {
                System.out.println("problema con: " + exc.getMessage());
            }
            catch(StringIndexOutOfBoundsException exc)
            {
                System.out.println("indice di posizione non valido");
            }
        }
    
    }
    codice:
    import java.lang.String;
    
    public class FileSorgente extends File
    {
    ...
    public String aggiungiTesto(String testo) throws NullPointerException
        {
            if (contenuto == null)
            {
                contenuto = "";
            }
            if (testo == null)
            {
                throw new NullPointerException();
            }
            contenuto += testo;
            return contenuto;
        }
    
    public String aggiungiTesto(String testo, int posizione) throws NullPointerException, StringIndexOutOfBoundsException
        {
            int length = contenuto.length();
            if(contenuto==null)
            {
                contenuto="";
            }
            if(testo==null)
            {
                throw new NullPointerException();
            }
            if(posizione < 0 || posizione > length)
            {
                throw new StringIndexOutOfBoundsException();
            }
            
            contenuto = contenuto.substring(0, posizione) + testo + contenuto.substring(posizione);
            
            return contenuto;
        }
    
    ...
    Sarebbe concettualmente corretto? Dico concettualmente perchè sembra funzionare


    Quote Originariamente inviata da LeleFT Visualizza il messaggio
    2) Premesso che catturare e gestire una NullPointerException nel 99% dei casi non ha alcun senso (preciso dopo), non è vero che tu non puoi creare un oggetto FileSorgente con contenuto nullo. Prova così:

    codice:
    FileSorgente sorg = new FileSorgente("pippo.java", 1, null);

    Questo codice è perfettamente lecito, compila e ti riporta esattamente nel caso in esame.
    ah già, è vero. mi era sfuggito. grazie.
    Avrei una domanda però:
    In questo esempio
    codice:
    public PortaMonete(int... valori)
    {
    ...
    }
    codice:
    public class TestMonete
    {
        public static void main(String args[])
        {
            PortaMonete portamonete3 = new PortaMonete();
        }
    }
    la creazione del portamonete3 senza specificare alcun campo nel costruttore non mi segnala errori perchè ho utilizzato i varargs?


    Quote Originariamente inviata da LeleFT Visualizza il messaggio
    Precisazione sulla NPE (NullPointerException): a parte casi particolari (programmi che, generalmente, analizzano sorgenti o servono ad aiutare le fasi di sviluppo o usano dati provenienti da librerie/programmi di terze parti), una NullPointerException rappresenta un errore nel programma. E un errore non va "gestito": va corretto. Una NPE viene sollevata quando si cerca di usare un oggetto che è nullo. Quando non si è sicuri della reale istanziazione di un oggetto (perchè proviene da codice esterno, di cui non si ha il controllo) ci si dovrebbe fare carico di controllare prima la non nullità del riferimento; se viene sollevata durante l'esecuzione di un programma, allora ci si deve preoccupare di capire perchè quel tale oggetto in quell'istante è nullo. Da questo ne consegue che non ha nessun senso catturare e gestire una NPE.


    Ciao.
    Il discorso è chiarissimo. Nell'esempio di sopra l'ho usato per evitare di usare un'eccezione più "generica" (RuntimException) visto che in quel caso era abbastanza chiaro quale tipo di eccezione potesse essere sollevata. Magari però era meglio usare una sola RuntimeException che mi avrebbe gestito anche la StringIndexOutOfBoundsException.
    Ultima modifica di newutente; 19-11-2014 a 11:56

  4. #4
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,320
    Quote Originariamente inviata da newutente Visualizza il messaggio
    Se io modificassi il codice in questo modo:
    [...]
    Sarebbe concettualmente corretto? Dico concettualmente perchè sembra funzionare
    Sì, diciamo che "non sarebbe sbagliato". In realtà, essendo che NullPointerException e StringIndexOutOfBoundsException sono eccezioni unchecked, il try/catch risulta comunque un "di più" lasciato a discrezione del programmatore.

    Avrei una domanda però:
    In questo esempio
    codice:
    public PortaMonete(int... valori)
    {
    ...
    }
    codice:
    public class TestMonete
    {
        public static void main(String args[])
        {
            PortaMonete portamonete3 = new PortaMonete();
        }
    }
    la creazione del portamonete3 senza specificare alcun campo nel costruttore non mi segnala errori perchè ho utilizzato i varargs?
    Sì. Nel caso dei varargs il compilatore è in grado di valutare il tipo di chiamata e, quindi, non segnala alcun errore (poichè, effettivamente, non è un errore: numero variabile di argomenti significa, appunto, da 0 argomenti a N argomenti).


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  5. #5
    Utente di HTML.it
    Registrato dal
    Oct 2014
    Messaggi
    315
    Quindi se parliamo di eccezioni unchecked (tutte le sottoclassi di RuntimeException) è sufficiente utilizzare throw quindi lanciando l'eccezione ma senza preoccuparsi di catturarla tramite il try-catch.

    Quello che non mi è chiaro però è se c'è differenza tra lanciare una eccezione e gestirla altrove oppure lanciarla e gestirla nel metodo stesso.
    Cioè, se questi due frammenti di codice sono equivalenti:
    codice:
    public class Esempio
    {
    ...
        public void aggiungi()
        {
            try
            {
                    ...    
                throw new EccezioneException();
            }
            catch (EccezioneException exc)
            {
                ...
            }
        }
    ...
    }
    codice:
    public class Principale
    {
        public static void main(String args[])
        {
            Esempio esempio = new Esempio();
            
            try
            {
                esempio.aggiungi();
            }
            catch (EccezioniException exc)
            {
                ...
            }
        }
    }
    
    
    
    public class Esempio
    {
    ...
        public void aggiungi() throws EccezioneException
        {
            ...    
            throw new EccezioneException();        
        }
    ...
    }

  6. #6
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,320
    Quote Originariamente inviata da newutente Visualizza il messaggio
    Quindi se parliamo di eccezioni unchecked (tutte le sottoclassi di RuntimeException) è sufficiente utilizzare throw quindi lanciando l'eccezione ma senza preoccuparsi di catturarla tramite il try-catch.
    Non c'entra nulla.
    Le eccezioni unchecked sono eccezioni che il programmatore non è costretto a gestire. Né con try/catch, né con throws. Sono tipi particolari di eccezione che possono essere sollevati a scopo "informativo" per il programmatore dell'applicazione. Se vengono sollevate, il più delle volte significa che il programma non è stato fatto nel modo corretto. Un paio di esempi per chiarire:

    - IndexOutOfBoundsException. Se viene sollevata, significa che si è cercato di sforare l'indice di un array: questo, il più delle volte, non significa che il programmatore debba gestire questa eccezione; significa, piuttosto, che il programmatore, prima di fare sciocchezze, dovrebbe controllare la lunghezza dell'array e evitare di sforarlo.

    - ArithmeticException. Se viene sollevata significa che il programma sta facendo dei calcoli che non può fare. L'esempio classico è la divisione per 0: il programmatore deve evitare di far fare al programma divisioni per zero, non fargliele fare ed, eventualmente, gestire l'eccezione.


    Quello che non mi è chiaro però è se c'è differenza tra lanciare una eccezione e gestirla altrove oppure lanciarla e gestirla nel metodo stesso.
    Cioè, se questi due frammenti di codice sono equivalenti:
    codice:
    public class Esempio
    {
    ...
        public void aggiungi()
        {
            try
            {
                    ...    
                throw new EccezioneException();
            }
            catch (EccezioneException exc)
            {
                ...
            }
        }
    ...
    }
    codice:
    public class Principale
    {
        public static void main(String args[])
        {
            Esempio esempio = new Esempio();
            
            try
            {
                esempio.aggiungi();
            }
            catch (EccezioniException exc)
            {
                ...
            }
        }
    }
    
    
    
    public class Esempio
    {
    ...
        public void aggiungi() throws EccezioneException
        {
            ...    
            throw new EccezioneException();        
        }
    ...
    }
    Da nessuna parte (se non nei libri e, comunque, nel materiale didattico) troverai mai del codice come il primo. Semplicemente perchè non ha alcun senso (dal punto di vista pratico e logico). Ben diverso è il caso del secondo esempio. Lì c'è un metodo che può essere potenzialmente richiamato da più parti del codice (addirittura da codice esterno). Quel metodo sta dicendo: io faccio il mio lavoro, ma se succede qualcosa di anomalo, lo segnalo ma non mi preoccupo di gestirlo. E i motivi per una scelta di questo tipo sono molteplici:

    1) Io, metodo, non sono in grado di gestire quel caso particolare
    2) Io, metodo, non mi voglio sporcare le mani: non ho una visione sufficientemente ampia del contesto in cui sono stato chiamato, quindi è meglio che sia il chiamante a gestire la cosa (che ha una visione più ampia)
    3) Io, metodo, potrei anche gestire l'eccezione, ma forse è meglio non lo faccia perchè il chiamante potrebbe essere interessato a sapere se qualcosa è andato storto.
    4) Io, metodo, gestisco solo una parte delle eccezioni che possono insorgere durante il lavoro, ma il resto lo lascio gestire a chi mi chiama (i casi più gravi)
    5) Io, metodo, gestisco l'eccezione, ma la rilancio al chiamante con delle informazioni in più, che possono tornargli utili per decidere come gestire il caso.

    Se un metodo ha tutte le informazioni per poter gestire un'eccezione, può farlo e non dire nulla a nessuno. Userà un try/catch e finita lì. Altrimenti, se sussistono uno o più dei motivi sopra elencati (non è un elenco esaustivo), semplicemente agirà di conseguenza.


    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  7. #7
    Utente di HTML.it
    Registrato dal
    Oct 2014
    Messaggi
    315
    Forse ho capito.
    Cerco di riassumere sommariamente i concetti:
    - le eccezioni vanno gestite dove vengono invocati i metodi e vanno sollevate nel metodo stesso (secondo esempio fatto prima).

    - quando si crea un oggetto l'eccezione va gestita (blocco try-catch) nel costruttore

    - la parola throws sta ad indicare che in quel metodo sarà lanciata (throw) una eccezione ma sarà gestita (blocco try-catch) altrove (nel metodo che chiama il metodo in questione - es. nel main)

    - SOLO nel caso di eccezioni unchecked (tutto le sottoclassi di RuntimeException) si può tranquillamente lanciare (throw) l'eccezione ma senza la necessità di gestirla (blocco try-catch) quindi non serve mettere throws.
    Volendo il programmatore può decidere comunque di gestire l'eccezione e lo può fare liberamente nel metodo stesso, quindi con blocco try-catch, oppure indicando throws e inserendo il blocco try-catch altrove (nel metodo che chiama il metodo in questione - es. nel main).

    Spero di non aver sbagliato.

  8. #8
    Moderatore di Programmazione L'avatar di LeleFT
    Registrato dal
    Jun 2003
    Messaggi
    17,320
    Quote Originariamente inviata da newutente Visualizza il messaggio
    - le eccezioni vanno gestite dove vengono invocati i metodi e vanno sollevate nel metodo stesso (secondo esempio fatto prima).
    Non necessariamente. Dipende sempre da ciò che si può/vuole fare e dal tipo di eccezione.
    Le eccezioni unchecked possono essere gestite oppure no. A discrezione del programmatore
    Le eccezioni checked devono essere gestite in qualche modo: o si gestiscono con un try/catch o si demanda la gestione al chiamante con un throws sulla firma del metodo.
    La seconda parte di questa frase ha poco senso: tutte le eccezioni vengono sollevate nel punto in cui c'è un throw (che sia codice del programmatore o della JVM).


    - quando si crea un oggetto l'eccezione va gestita (blocco try-catch) nel costruttore
    Non necessariamente. Anche qui, sta al programmatore decidere se nel costruttore di un oggetto il contesto è sufficientemente chiaro da poter gestire eventuali eccezioni oppure no. Anche i costruttori, come i metodi, possono sollevare eccezioni e, nel caso di eccezioni checked, le dichiarano con la clausola throws.


    - la parola throws sta ad indicare che in quel metodo sarà lanciata (throw) una eccezione ma sarà gestita (blocco try-catch) altrove (nel metodo che chiama il metodo in questione - es. nel main)
    Ni. La clausola throws significa che quel metodo può sollevare quel tipo di eccezioni (le eccezioni, lo dice il nome, sono qualcosa di "eccezionale", non la regola). Chi usa quel metodo deve (nel caso di eccezioni checked) provvedere al trattamento: con try/catch o con altro throws.


    - SOLO nel caso di eccezioni unchecked (tutto le sottoclassi di RuntimeException) si può tranquillamente lanciare (throw) l'eccezione ma senza la necessità di gestirla (blocco try-catch) quindi non serve mettere throws.
    Volendo il programmatore può decidere comunque di gestire l'eccezione e lo può fare liberamente nel metodo stesso, quindi con blocco try-catch, oppure indicando throws e inserendo il blocco try-catch altrove (nel metodo che chiama il metodo in questione - es. nel main).
    Sì.

    Ciao.
    "Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
    Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza

  9. #9
    Utente di HTML.it
    Registrato dal
    Feb 2007
    Messaggi
    4,157
    Quote Originariamente inviata da LeleFT Visualizza il messaggio
    Non necessariamente. Anche qui, sta al programmatore decidere se nel costruttore di un oggetto il contesto è sufficientemente chiaro da poter gestire eventuali eccezioni oppure no. Anche i costruttori, come i metodi, possono sollevare eccezioni e, nel caso di eccezioni checked, le dichiarano con la clausola throws.
    in realtà con il costruttore bisognerebbe fare attenzione e vedere se non è possibile fare in altro modo.
    Intanto l'oggetto non è correttamente inizializzato, che fai continui? vai in eccezione? L'oggetto è pronto per essere finalizzato, ma quando interviene il gc?

    Dal punto di vista della sicurezza, queste possono essere anche back door (è sicuramente pronto per il gc, implementi finalize e fai quello che ti pare).

    In generale quindi per le eccezioni dal costruttore chiediti se è davvero necessario averle (e in caso prendi opportuni provvedimenti per garantire integrità e sicurezza)
    RTFM Read That F*** Manual!!!

  10. #10
    Utente di HTML.it
    Registrato dal
    Oct 2014
    Messaggi
    315
    ok, capito. grazie.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.