Come fa la JVM a gestire un'eccezione generata dal metodo principale?

10

Capisco le eccezioni, lanciandole, gestendole e propagandole su un metodo più basso nello stack di chiamate (cioè throws ).

Ciò che non capisco è questo:

public static void main(String[] args) throws Exception {
    ...
}

Ora, presumo che nel caso in cui main lanci un Exception , la JVM lo gestisce (corretto?). Se è così, allora la mia domanda è:

In che modo JVM gestisce le eccezioni generate da main ? Che cosa fa?

    
posta Aviv Cohn 25.09.2014 - 00:12
fonte

2 risposte

19

Potresti pensare che il metodo public static void main in Java o la funzione main in C sia il vero punto di ingresso del tuo programma, ma non lo è. Tutti i linguaggi di alto livello (incluso C) dispongono di un runtime di lingua che inizializza il programma e quindi trasferisce il flusso di controllo al punto di ingresso. Nel caso di Java, l'inizializzazione includerà:

  • impostazione della JVM
  • caricamento delle classi richieste
  • esecuzione di blocchi di inizializzazione statici. Questo può eseguire il codice definito dall'utente prima che venga richiamato main . Questi blocchi non dovrebbero generare eccezioni.

Esistono diversi modi per implementare la gestione delle eccezioni, ma ai fini di questa domanda, possono essere tutti visualizzati come una scatola nera. La cosa importante tuttavia è che il runtime della lingua deve sempre fornire un gestore di eccezioni più esterno che raccolga tutte le eccezioni che non sono catturate dal codice utente. Generalmente questo gestore di eccezioni stamperà una traccia dello stack, spegnerà il programma in modo ordinato e uscirà con un codice di errore. Chiudere correttamente il programma include distruggere il grafico dell'oggetto, richiamare i finalizzatori e liberare risorse come memoria, handle di file o connessioni di rete.

A scopo illustrativo, puoi eseguire l'imaging del runtime avvolgendo tutto il codice in un gigantesco try-catch che assomiglia a

try {
    loadClasses();
    runInitializers();
    main(argv);
    System.exit(0);
} catch (Throwable e) {
    e.printStackTrace();
    System.exit(-1);
}

eccetto che non è necessario che una lingua esegua effettivamente un codice come questo. La stessa semantica può essere implementata nel codice per throw (o equivalente) che cerca il primo gestore di eccezioni applicabile.

    
risposta data 25.09.2014 - 01:03
fonte
9

Tutto il codice Java viene eseguito nel contesto di un thread . Il JavaDoc collegato spiega i criteri di gestione degli errori e di uscita, ma ecco il succo:

  • La JVM si gira e prepara l'ambiente di esecuzione.
  • La JVM crea un thread che eseguirà il metodo main() utilizzando qualsiasi parametro della riga di comando applicabile.
  • La JVM imposta un gestore di eccezioni non interrogato di default che stampa l'eccezione all'errore standard e termina.
  • La JVM esegue il thread.

Nel caso di un'eccezione non rilevata, il programma muore efficacemente per il terzo elemento sopra. Questo comportamento è ulteriormente specificato nella Specifica del linguaggio Java, Sezione 11.3

Informazioni aggiuntive

Altri hanno menzionato blocchi statici e come vengono eseguiti prima di main() . Tuttavia, questo richiede un po 'più di spiegazione per capire correttamente.

Quando si carica una classe, il programma di caricamento classi deve inizializzare tutto lo stato static final ed eseguire tutti i blocchi static prima la classe può essere utilizzata, per includere istanze di istanza della classe (a parte: creare una classe Java in cui una costante di classe viene inizializzata in un blocco statico dopo creando un'istanza della classe e il costruttore fa riferimento alla costante Boom!). Tuttavia, tutto ciò avviene nella logica del programma di caricamento prima che qualsiasi codice possa fare riferimento alla classe . Inoltre, la classe viene caricata in qualsiasi thread a cui si fa riferimento nella classe.

Ciò significa che se la classe contenente main() fa riferimento a un'altra classe (ad esempio costante di classe), allora quella classe deve essere caricata prima che main() venga eseguita per includere i blocchi statici. Altrimenti, i blocchi statici sono eseguiti come sopra. Se la classe non riesce a caricare, anche la classe contenente main() non verrà caricata e il programma verrà terminato.

Un'altra FYI: i blocchi statici possono lanciare. Errors viene lanciato così com'è. Exceptions è vietato (errore in fase di compilazione). RuntimeExceptions sono racchiusi in ExceptionInInitializerError . Questi vengono gestiti per il gestore di eccezioni non rilevate, che in genere uccide il thread o l'applicazione (thread principale) a meno che non si avvolga accuratamente il riferimento di classe (e il caricamento) in try - catch .

    
risposta data 25.09.2014 - 02:59
fonte

Leggi altre domande sui tag