53 votes

Sortie déroutante d'une récursion infinie dans try-catch

Considérons le code suivant.

public class Action {
private static int i=1;
public static void main(String[] args) {
    try{
        System.out.println(i);
        i++;
        main(args);
    }catch (StackOverflowError e){
        System.out.println(i);
        i++;
        main(args);
    }
 }

}

Je suis arriver j'ai de la valeur à 4338 correctement. Après la capture de l' StackOverflowError sortie se câblés comme suit.

4336
4337
4338 // up to this point out put can understand 
433943394339 // 4339 repeating thrice  
434043404340
4341
434243424342
434343434343
4344
4345
434643464346
434743474347
4348
434943494349
435043504350

Envisager de Vivre démo ici. Il fonctionne correctement jusqu'à i=4330. En fait comment cela se fait?

FYI:

Je n'ai code suivant pour comprendre ce qui se passe ici.

public class Action {

    private static int i = 1;
    private static BufferedWriter bw;

    static {
        try {
            bw = new BufferedWriter(new FileWriter("D:\\sample.txt"));
        } catch (IOException e) {
           e.printStackTrace();
        }
    }

    public static void main(String[] args) throws IOException {
        bw.append(String.valueOf(i)+" ");
        try {
            i++;
            main(args);
        } catch (StackOverflowError e) {
            bw.append(String.valueOf(i)+" ");
            i++;
            main(args);
        }
    }

}

Maintenant précédente question n'est pas là. maintenant, la valeur de i jusqu'à 16824744 correcte et et fonctionne encore. Je suis hopping cela peut s'exécute jusqu'à la valeur de i=2,147,483,647(max valeur de type int) sans problème.

Il y a un problème avec println(). Il existe des réponses ci-dessous. Mais pourquoi?

Quelle sera la réelle raison?

52voto

axtavt Points 126632

Notez l'absence de caractères de saut de ligne en 433943394339. Il indique que quelque chose de mauvais arrive à l'intérieur d' System.out.println().

Le point essentiel ici est que l' System.out.println() nécessite un certain espace de pile, de manière à ce qu' StackOverflowError est levée à partir de System.out.println().

Voici votre code avec marqué des points:

public static void main(String[] args) {
    try{
        System.out.println(i); // (1)
        i++;
        main(args); // (2)
    }catch (StackOverflowError e){
        System.out.println(i); // (3)
        i++;
        main(args); // (4)
    }
}

Imaginons ce qui se passe au niveau N de la récursivité lorsque i = 4338:

  • L'énoncé (1) au niveau N imprime 4338. Sortie 4338\n
  • i est incrémenté d' 4339
  • Contrôle de flux entre le niveau N + 1 (2)
  • L'énoncé (1) au niveau N + 1 tente d'imprimer 4339, mais System.out.println() jette un StackOverflowError avant qu'il imprime un caractère de saut de ligne. Sortie 4339
  • StackOverflowError est pris au niveau N + 1, l'énoncé (3) essaie d'imprimer 4339 et échoue pour la même raison, encore une fois. Sortie 4339
  • Exception est interceptée au niveau de la N. À ce stade, il n'y a plus d'espace de pile disponible, donc le point (3) essaie d'imprimer 4339 et réussit (retour à la ligne est imprimée correctement). Sortie 4339\n
  • i est incrémenté et le contrôle de flux entre le niveau N + 1 est de nouveau à (4)

Après ce point, la situation se répète avec une 4340.

Je ne sais pas pourquoi certains numéros sont imprimés correctement entre les séquences sans retours à la ligne, peut-être liées à un travail interne de l' System.out.println() et tampons qu'elle utilise.

17voto

Martijn Courteaux Points 33836

Ce que je soupçonne d'être passe, c'est ceci:

  1. J'ai l'impression
  2. Impression de retour à la ligne
  3. J'
  4. Entrée principale
  5. J'ai l'impression
  6. Impression de retour à la ligne
  7. J'
  8. Entrée principale
  9. J'ai l'impression
  10. StackOverflow suis jeté (au lieu de print newline)
  11. Retour à la page principale, maintenant dans le catch
  12. J'ai l'impression
  13. StackOverflow suis jeté à nouveau (au lieu de print newline)
  14. Retour à la page principale, dans un autre attraper corps.
  15. J'ai l'impression
  16. Imprimer retour à la ligne (maintenant ne s'agit pas plus, parce que nous sommes deux niveaux plus haut)
  17. Entrée principale, et de revenir à 1.

4voto

Pooja Kansal Points 6049

Selon mon test:

Quand une Exception est levée par Bloc try, i a la même valeur quand il s'agit dans le bloc catch (comme sa pas incrémenté en raison de l'exception)

et puis à l'intérieur de bloc catch même exception est levée et qui est à nouveau pris par bloc catch !

J'ai essayé le Code Suivant

try {
            System.out.println("Try " + i);
            i++;
            main(args);
        } catch (StackOverflowError e) {
            System.out.println("\nBefore");
            System.out.println("Catch " + i);
            i++;
            System.out.println("After");
            main(args);

        }

Sortie :

Try 28343
Try 28344
Before
Before
Before
Before
Catch 28344
After
Try 28345
Try 28346
Try 28347
Try 28348
Before
Before
Before
Before
Catch 28348
After
Try 28349

lorsque le bloc try throws exception, il est capturé par bloc catch mais quand il va à l' System.out.println("Catch " + i); nouveau Exception est levée 4 fois (dans mon eclipse), Sans l'impression d' System.out.println("Catch " + i);

Comme ci-dessus sortie, je l'ai testé par l'impression "Avant", le Texte qui est imprimé quatre fois avant de l'imprimer System.out.println("Catch " + i);

1voto

Matthias Points 2510

Comme les autres réponses déjà expliquer qu'il a à faire avec le Système..println nécessitant davantage d'espace sur la pile, et donc de se jeter d'un StackOverflowError.

Essayez ce code ici pour voir quelques différences de comportement qui montre qu'à un certain point, il y a des exceptions étant jetés partout dans l'endroit de sorte que i++ ne peut pas se produire plus.

public class Action {
  private static int i = 1;

  private static StringBuffer buffer = new StringBuffer();

  public static void main(String[] args) {
    try {
      print();
      main(args);
    }
    catch (StackOverflowError e) {
      print();
      main(args);
    }
  }

  private static void print() {
    buffer.append(i).append("\n");
    i++;
    if (i % 1000 == 0) {
      System.out.println("more: " + buffer);
      buffer = new StringBuffer();
    }
  }
}

L'important lession d'apprendre est de ne Jamais rattraper les Erreurs qu'ils ont vraiment indiquent qu'il y a quelque chose de grave avec votre JVM qui ne peuvent pas être traitées normalement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X