Uitzondering gegooid in vangst en ten slotte clausule

Op een vraag voor Java op de universiteit stond dit codefragment:

class MyExc1 extends Exception {}
class MyExc2 extends Exception {}
class MyExc3 extends MyExc2 {}
public class C1 {
    public static void main(String[] args) throws Exception {
        try {
            System.out.print(1);
            q();
        }
        catch (Exception i) {
            throw new MyExc2();
        }
        finally {
            System.out.print(2);
            throw new MyExc1();
        }
    }
    static void q() throws Exception {
        try {
            throw new MyExc1();
        }
        catch (Exception y) {
        }
        finally {
            System.out.print(3);
            throw new Exception();
        }
    }
}

Ik werd gevraagd om de output te geven. Ik heb 13Exception in thread main MyExc2beantwoord, maar het juiste antwoord is 132Exception in thread main MyExc1. Waarom is dat? Ik begrijp gewoon niet waar MyExc2naartoe gaat.


Antwoord 1, autoriteit 100%

Op basis van het lezen van uw antwoord en het zien van hoe u het waarschijnlijk hebt bedacht, denk ik dat u denkt dat een “uitzondering in uitvoering” “voorrang” heeft. Onthoud:

Als een nieuwe uitzondering wordt gegooid in een catch-blok of uiteindelijk blokdat zich uit dat blok zal voortplanten, wordt de huidige uitzondering afgebroken (en vergeten) aangezien de nieuwe uitzondering is naar buiten gepropageerd. De nieuwe uitzondering begint de stapel af te wikkelen, net als elke andere uitzondering, waarbij het huidige blok wordt afgebroken (de vangst of uiteindelijk blok) en onderhevig aan eventuele toepasselijke vangsten of uiteindelijk blokkades.

Houd er rekening mee dat toepasselijke vangst of definitieve blokkadeshet volgende omvatten:

Als er een nieuwe uitzondering in een catch-blok wordt gegooid, is de nieuwe uitzondering nog steeds onderhevig aan de uiteindelijke blokkering van die vangst, indien van toepassing.

Herhaal nu de uitvoering en onthoud dat, wanneer u op throwdrukt, u het traceren van de huidige uitzondering moet afbreken en moet beginnen met het traceren van de nieuwe uitzondering.


Antwoord 2, autoriteit 28%

Uitzonderingen in het definitieve blok vervangen uitzonderingen in het catch-blok.

Java-taalspecificatie

Als het catch-blok abrupt wordt voltooid om reden R, dan is de final
blok wordt uitgevoerd. Dan is er een keuze:

  • Als het final-blok normaal wordt voltooid, wordt het try-statement abrupt voltooid om reden R.

  • Als het blok final abrupt eindigt om reden S, dan wordt het try-statement abrupt voltooid om reden S (en reden R wordt weggegooid).


Antwoord 3, autoriteit 22%

Dit is wat Wikipediazegt over de definitieve clausule:

Meer gebruikelijk is een verwante clausule
(eindelijk, of ervoor zorgen) dat wordt uitgevoerd
of er een uitzondering is opgetreden of niet,
meestal om middelen vrij te geven
verworven in het lichaam van de
blokkering voor het afhandelen van uitzonderingen.

Laten we uw programma ontleden.

try {
    System.out.print(1);
    q();
}

Dus, 1wordt op het scherm weergegeven, waarna q()wordt aangeroepen. In q()wordt een uitzondering gegenereerd. De uitzondering wordt dan opgevangen door Exception ymaar doet niets. Een finallyclausule wordt dan uitgevoerd (het moet), dus 3wordt op het scherm afgedrukt. Omdat (in methode q()er een uitzondering wordt gegenereerd in de finallyclausule, geeft ook de q()methode de uitzondering door aan de bovenliggende stapel ( door de throws Exceptionin de methodedeclaratie) new Exception()wordt gegooid en opgevangen door catch ( Exception i ), MyExc2-uitzondering gegenereerd (voeg deze voorlopig toe aan de uitzonderingsstapel), maar een eindelijkin het main-blok wordt eerst uitgevoerd.

Zo binnen,

catch ( Exception i ) {
    throw( new MyExc2() );
} 
finally {
    System.out.print(2);
    throw( new MyExc1() );
}

Een finallyclausule heet…(vergeet niet, we hebben zojuist Exception iopgevangen en MyExc2gegooid) in wezen, 2wordt op het scherm afgedrukt…en nadat de 2op het scherm is afgedrukt, wordt een MyExc1-uitzondering gegenereerd. MyExc1wordt afgehandeld door de methode public static void main(...).

Uitvoer:

“132Uitzondering in hoofdthread MyExc1”

Docent heeft gelijk! 🙂

In wezen, als je een finallyin een try/catch-clausule hebt, zal er een final worden uitgevoerd (nahet vangen van de uitzondering voordatde betrapte uitzondering weggooit)


Antwoord 4, autoriteit 12%

Ten slotte wordt de clausule uitgevoerd, zelfs als er een uitzondering wordt gegenereerd vanaf een willekeurige plek in het try/catch-blok.

Omdat het de laatste is die wordt uitgevoerd in de mainen het een uitzondering genereert, is dat de uitzondering die de bellers zien.

Vandaar het belang om ervoor te zorgen dat de finally-clausule niets genereert, omdat het uitzonderingen van het try-blok kan slikken.


Antwoord 5, autoriteit 5%

Een methodkan niet throwtwee uitzonderingen tegelijk. Het zal altijd de laatst gegenereerde Exceptiongenereren, wat in dit geval altijd het blok is van het finally-blok.

Als de eerste uitzondering van de methode q()wordt gegenereerd, wordt deze gevangen en vervolgens opgeslokt door de laatste uitzondering die wordt gegenereerd door blokkering.

q() ->gegooid new Exception->maincatch Exception->thrownew Exception->finallygooi een nieuwe Exception(en die uit de catchis “verloren”)


Antwoord 6, autoriteit 2%

class MyExc1 extends Exception {}
class MyExc2 extends Exception {}
class MyExc3 extends MyExc2 {}
public class C1 {
    public static void main(String[] args) throws Exception {
        try {
            System.out.print("TryA L1\n");
            q();
            System.out.print("TryB L1\n");
        }
        catch (Exception i) {
            System.out.print("Catch L1\n");                
        }
        finally {
            System.out.print("Finally L1\n");
            throw new MyExc1();
        }
    }
    static void q() throws Exception {
        try {
            System.out.print("TryA L2\n");
            q2();
            System.out.print("TryB L2\n");
        }
        catch (Exception y) {
            System.out.print("Catch L2\n");
            throw new MyExc2();  
        }
        finally {
            System.out.print("Finally L2\n");
            throw new Exception();
        }
    }
    static void q2() throws Exception {
        throw new MyExc1();
    }
}

Bestelling:

TryA L1
TryA L2
Catch L2
Finally L2
Catch L1
Finally L1        
Exception in thread "main" MyExc1 at C1.main(C1.java:30)

https://www.compilejava.net/


Antwoord 7, autoriteit 2%

De gemakkelijkste manier om hieraan te denken is door je voor te stellen dat er een globale variabele is voor de hele applicatie die de huidige uitzondering bevat.

Exception currentException = null;

Als elke uitzondering wordt gegenereerd, wordt “currentException” op die uitzondering ingesteld. Wanneer de toepassing eindigt, als currentException != null is, rapporteert de runtime de fout.

Ook worden de blokken tenslotte altijd uitgevoerd voordat de methode wordt afgesloten. U kunt het codefragment dan opnieuw vragen aan:

public class C1 {
    public static void main(String [] argv) throws Exception {
        try {
            System.out.print(1);
            q();
        }
        catch ( Exception i ) {
            // <-- currentException = Exception, as thrown by q()'s finally block
            throw( new MyExc2() ); // <-- currentException = MyExc2
        }
        finally {
             // <-- currentException = MyExc2, thrown from main()'s catch block
            System.out.print(2);
            throw( new MyExc1() ); // <-- currentException = MyExc1
        }
    }  // <-- At application exit, currentException = MyExc1, from main()'s finally block. Java now dumps that to the console.
    static void q() throws Exception {
        try {
            throw( new MyExc1() ); // <-- currentException = MyExc1
        }
        catch( Exception y ) {
           // <-- currentException = null, because the exception is caught and not rethrown
        }
        finally {
            System.out.print(3);
            throw( new Exception() ); // <-- currentException = Exception
        }
    }
}

De volgorde waarin de toepassing wordt uitgevoerd is:

main()
{
  try
    q()
    {
      try
      catch
      finally
    }
  catch
  finally
}

Antwoord 8

De logica is duidelijk totdat het afdrukken van 13is voltooid. Vervolgens wordt de uitzondering die in q()wordt gegenereerd, opgevangen door catch (Exception i)in main()en een new MyEx2()is klaar om te worden gegooid. Voordat de uitzondering wordt gegenereerd, moet echter eerst het blok finallyworden uitgevoerd. Dan wordt de uitvoer 132en finallyvraagt ​​om nog een uitzondering new MyEx1()te genereren.

Omdat een methode niet meer dan één Exceptionkan genereren, zal deze altijd de laatste Exceptiongenereren. Met andere woorden, als zowel catchals finallyblokken proberen om Exceptionte gooien, dan is de Exceptionin catch geslikten alleen de uitzondering in finallywordt gegenereerd.

Dus in dit programma wordt Uitzondering MyEx2ingeslikt en MyEx1wordt gegenereerd. Deze uitzondering wordt uit main()gegooid en niet langer gevangen, dus JVM stopt en de uiteindelijke uitvoer is 132Exception in thread main MyExc1.

In wezen, als je een finallyin een try/catch-clausule hebt, wordt een finallyuitgevoerd NA het vangen van de uitzondering, maar VOORDAT er een betrapte uitzondering wordt gegooid, en ALLEEN de laatste uitzondering wordt uiteindelijk gegooid.


Antwoord 9

Het is algemeen bekend dat het final-blok wordt uitgevoerd na de try and catch en altijd wordt uitgevoerd….
Maar zoals je hebt gezien, is het soms een beetje lastig, kijk eens naar dat codefragment hieronder en je zult dat doen
de return- en throw-statements doen niet altijd wat ze zouden moeten doen in de volgorde die we van het thema verwachten.

Proost.

/////////////Return dont always return///////
try{
    return "In Try";
}
finally{
    return "In Finally";
}
////////////////////////////////////////////
////////////////////////////////////////////    
while(true) { 
    try {
        return "In try";
   } 
   finally{
        break;     
    }          
}              
return "Out of try";      
///////////////////////////////////////////
///////////////////////////////////////////////////
while (true) {     
    try {            
        return "In try";    
     } 
     finally {   
         continue;  
     }                         
}
//////////////////////////////////////////////////
/////////////////Throw dont always throw/////////
try {
    throw new RuntimeException();
} 
finally {
    return "Ouuuups no throw!";
}
////////////////////////////////////////////////// 

Antwoord 10

Ik denk dat je gewoon de finallyblokken moet lopen:

  1. Druk “1” af.
  2. finallyin qdruk “3” af.
  3. finallyin mainprint “2”.

Antwoord 11

Om dit soort situaties aan te pakken, d.w.z. het afhandelen van de uitzondering die is gegenereerd door eindelijk blokkeren. Je kunt het laatste blok omringen met een try-blok: kijk naar het onderstaande voorbeeld in python:

try:
   fh = open("testfile", "w")
   try:
      fh.write("This is my test file for exception handling!!")
   finally:
      print "Going to close the file"
      fh.close()
except IOError:
   print "Error: can\'t find file or read data"

Antwoord 12

Ik denk dat dit het probleem oplost:

boolean allOk = false;
try{
  q();
  allOk = true;
} finally {
  try {
     is.close();
  } catch (Exception e) {
     if(allOk) {
       throw new SomeException(e);
     }
  }
}

Other episodes