Interpreter-Fehler Probleme mit Rekursion - StackOverflowError

Androbin

Bekanntes Mitglied
Hallo Leute,
ich habe eine Methode geschrieben, welche einen long in englischen Text umwandelt (123 ==> "one hundred and twenty-three"),
jedoch kommt es bei Werten von 100.000 oder höher an mancher Stelle zu einem StackOverflowError.
Ich habe gelesen, dass diese Exception häufig im Zusammenhang mit Rekursion auftritt, wie auch ich sie verwende.
Da ich die Methode nicht ohne Rekursion umzusetzen vermag, muss ich einen anderen Weg finden, die Exception zu vermeiden!

Weiß jemand von euch Rat?

Java:
public static String toString( long n ) {
    
    if ( n < 0 ) return "minus " + toString( -n );
    
    String s = String.valueOf( n );
    
    if ( s.length() > 3 ) {
        
        String t = null;
        
        int m = s.length() / 3;
        
        if ( m == 1 )
            t = "thousand";
        else {
            
            int o = m / 2 - 1;
            
            final String[] u = new String[] { "m", "b", "tr", "quadr", "quint", "sext", "sept", "oct" };
            
            t = u[ o ] + "illi" + ( o % 2 == 0 ? "on" : "ard" );
            
        }
        
        int p = s.length() % 3;
        
        int u = Integer.parseInt( s.substring( p, s.length() ) );
        
        return ( p != 0 ? toString( Integer.parseInt( s.substring( 0, p ) ) ) + " " : "" ) + t + ( u != 0 ? " " + toString( u ) : "" );
        
    }
    
    if ( s.length() == 3 ) {
        
        int t = Integer.parseInt( s.substring( 1, s.length() ) );
        
        return toString( Integer.parseInt( s.substring( 0, 1 ) ) ) + " hundred" + ( t != 0 ? " and " + toString( t ) : "" );
        
    }
    
    if ( s.length() == 2 ) {
        
        int a = Integer.parseInt( s.substring( 0, 1 ) );
        int b = Integer.parseInt( s.substring( 1, 2 ) );
        
        if ( a >= 2 ) {
            
            String t = null;
            
            switch ( a ) {
                
                default : t = toString( a ); break;
                
                case 2 : t = "twen"; break;
                case 3 : t = "thir"; break;
                case 4 : t = "for" ; break;
                case 5 : t = "fif" ; break;
                case 8 : t = "eigh"; break;
                
            }
            
            return t + "ty" + ( b != 0 ? "-" + toString( b ) : "" );
            
        } else {
            
            if ( b == 0 ) return "ten"   ;
            if ( b == 1 ) return "eleven";
            if ( b == 2 ) return "twelve";
            
            String t = null;
            
            switch ( b ) {
                
                default : t = toString( b ); break;
                
                case 3 : t = "thir"; break;
                case 5 : t = "fif" ; break;
                case 8 : t = "eigh"; break;
                
            }
            
            return t + "teen";
            
        }
        
    }
    
    if ( s.length() == 1 ) {
        
        int d = Integer.parseInt( s.substring( 0, 1 ) );
        
        String t = null;
        
        switch ( d ) {
            
            case 0 : t = "zero" ; break;
            case 1 : t = "one"  ; break;
            case 2 : t = "two"  ; break;
            case 3 : t = "three"; break;
            case 4 : t = "four" ; break;
            case 5 : t = "five" ; break;
            case 6 : t = "six"  ; break;
            case 7 : t = "seven"; break;
            case 8 : t = "eight"; break;
            case 9 : t = "nine" ; break;
            
        }
        
        return t;
        
    }
    
    return "null";
    
}
 
Zuletzt bearbeitet:
Bisschen unübersichtlich, geh doch einfach in so einem Fall mit dem Debugger durch dann siehst du ja
ob die Methode so durchläuft wie sie soll oder ob sich irgendwo eine Endlosschleife durch die Rekursion ergibt.
Sonst würdest du auch keinen stack trace error bekommen.
 
Bisschen unübersichtlich, geh doch einfach in so einem Fall mit dem Debugger durch dann siehst du ja
ob die Methode so durchläuft wie sie soll oder ob sich irgendwo eine Endlosschleife durch die Rekursion ergibt.
Sonst würdest du auch keinen stack trace error bekommen.
Endlosschleifen gibt es keine, die Exception tritt ja (von Zeit zu Zeit) auch in Zeile 5 (des Posts) auf ("String.valueOf( n )")!
 
Die Rekursion bricht bei 100.000 als Eingabe nicht ab.
In Zeile 29 rufst du toString nämlich wieder mit 100.000 auf.

In solchen Fällen hilft es, am Anfang der Methode den Parameter auf der Konsole auszugeben.
 
Ja aber der Fehler kommt ja nicht von der String.valueOf().
StackOverflow kann ja auch bedeuten, dadurch dass deine Rekursion tonnenweise Methoden
aufgemacht hat (weil sich irgendwo eine Endlosschleife ergibt). Anscheinend merkts dass erst
bei dem Aufruf von der String.valueOf() erst, oder der Platz zum Aufrufen der Methode ist weg.
Wieso willst du nicht einfach reindebuggen und die Steps durchgehen?
Für deine Zahl mit >100.000 sollten es ja noch unter 10 Schritte sein, die wirst du ja durchchecken können.
Oder bau dir ein Zähler ein der mitzählt wie oft die Methode aufgerufen wurde.
 
Die Rekursion bricht bei 100.000 als Eingabe nicht ab.
In Zeile 29 rufst du toString nämlich wieder mit 100.000 auf.

In solchen Fällen hilft es, am Anfang der Methode den Parameter auf der Konsole auszugeben.
Danke für den Hinweis, jetzt sollte es funktionieren:
Java:
int p = s.length() % 3; // Zeile 25

if ( p == 0 ) p = 3;

int u = Integer.parseInt( s.substring( p, s.length() ) );

return toString( Integer.parseInt( s.substring( 0, p ) ) ) + " " + t + ( u != 0 ? " " + toString( u ) : "" );
 
Da waren noch ein paar Fehler hinsichtlich der Variablen m und o!
Java:
public static String toString( long n ) {
    
    if ( n < 0 ) return "minus " + toString( -n );
    
    String s = String.valueOf( n );
    
    if ( s.length() > 3 ) {
        
        String t = null;
        
        int m = ( s.length() - 1 ) / 3;
        
        if ( m == 1 )
            t = "thousand";
        else {
            
            int o = m / 2 - 1;
            
            final String[] u = new String[] { "m", "b", "tr", "quadr", "quint", "sext", "sept", "oct" };
            
            t = u[ o ] + "illi" + ( m % 2 == 0 ? "on" : "ard" );
            
        }
        
        int p = s.length() % 3;
        
        if ( p == 0 ) p = 3;
        
        int u = Integer.parseInt( s.substring( p, s.length() ) );
        
        return toString( Integer.parseInt( s.substring( 0, p ) ) ) + " " + t + ( u != 0 ? " " + toString( u ) : "" );
        
    }
    
    if ( s.length() == 3 ) {
        
        int t = Integer.parseInt( s.substring( 1, s.length() ) );
        
        return toString( Integer.parseInt( s.substring( 0, 1 ) ) ) + " hundred" + ( t != 0 ? " and " + toString( t ) : "" );
        
    }
    
    if ( s.length() == 2 ) {
        
        int a = Integer.parseInt( s.substring( 0, 1 ) );
        int b = Integer.parseInt( s.substring( 1, 2 ) );
        
        if ( a >= 2 ) {
            
            String t = null;
            
            switch ( a ) {
                
                default : t = toString( a ); break;
                
                case 2 : t = "twen"; break;
                case 3 : t = "thir"; break;
                case 4 : t = "for" ; break;
                case 5 : t = "fif" ; break;
                case 8 : t = "eigh"; break;
                
            }
            
            return t + "ty" + ( b != 0 ? "-" + toString( b ) : "" );
            
        } else {
            
            if ( b == 0 ) return "ten"   ;
            if ( b == 1 ) return "eleven";
            if ( b == 2 ) return "twelve";
            
            String t = null;
            
            switch ( b ) {
                
                default : t = toString( b ); break;
                
                case 3 : t = "thir"; break;
                case 5 : t = "fif" ; break;
                case 8 : t = "eigh"; break;
                
            }
            
            return t + "teen";
            
        }
        
    }
    
    if ( s.length() == 1 ) {
        
        int d = Integer.parseInt( s.substring( 0, 1 ) );
        
        String t = null;
        
        switch ( d ) {
            
            case 0 : t = "zero" ; break;
            case 1 : t = "one"  ; break;
            case 2 : t = "two"  ; break;
            case 3 : t = "three"; break;
            case 4 : t = "four" ; break;
            case 5 : t = "five" ; break;
            case 6 : t = "six"  ; break;
            case 7 : t = "seven"; break;
            case 8 : t = "eight"; break;
            case 9 : t = "nine" ; break;
            
        }
        
        return t;
        
    }
    
    return "null";
    
}
 
Jetzt das Ganze nochmal unter Einsatz von BigInteger:
Java:
public static String toString( BigInteger n ) {
    
    if ( n.signum() == -1 ) return "minus " + toString( n.negate() );
    
    String s = String.valueOf( n );
    
    if ( s.length() > 3 ) {
        
        String t = null;
        
        int m = ( s.length() - 1 ) / 3;
        
        if ( m == 1 )
            t = "thousand";
        else {
            
            int o = m / 2 - 1;
            
            final String[] u = new String[] { "m", "b", "tr", "quadr", "quint", "sext", "sept", "oct" };
            
            t = u[ o ] + "illi" + ( m % 2 == 0 ? "on" : "ard" );
            
        }
        
        int p = s.length() % 3;
        
        if ( p == 0 ) p = 3;
        
        BigInteger u = new BigInteger( s.substring( p, s.length() ) );
        
        return toString( new BigInteger( s.substring( 0, p ) ) ) + " " + t + ( u.signum() != 0 ? " " + toString( u ) : "" );
        
    }
    
    if ( s.length() == 3 ) {
        
        int t = Integer.parseInt( s.substring( 1, s.length() ) );
        
        return toString( new BigInteger( s.substring( 0, 1 ) ) ) + " hundred" + ( t != 0 ? " and " + toString( BigInteger.valueOf( t ) ) : "" );
        
    }
    
    if ( s.length() == 2 ) {
        
        int a = Integer.parseInt( s.substring( 0, 1 ) );
        int b = Integer.parseInt( s.substring( 1, 2 ) );
        
        if ( a >= 2 ) {
            
            String t = null;
            
            switch ( a ) {
                
                default : t = toString( BigInteger.valueOf( a ) ); break;
                
                case 2 : t = "twen"; break;
                case 3 : t = "thir"; break;
                case 4 : t = "for" ; break;
                case 5 : t = "fif" ; break;
                case 8 : t = "eigh"; break;
                
            }
            
            return t + "ty" + ( b != 0 ? "-" + toString( BigInteger.valueOf( b ) ) : "" );
            
        } else {
            
            if ( b == 0 ) return "ten"   ;
            if ( b == 1 ) return "eleven";
            if ( b == 2 ) return "twelve";
            
            String t = null;
            
            switch ( b ) {
                
                default : t = toString( BigInteger.valueOf( b ) ); break;
                
                case 3 : t = "thir"; break;
                case 5 : t = "fif" ; break;
                case 8 : t = "eigh"; break;
                
            }
            
            return t + "teen";
            
        }
        
    }
    
    if ( s.length() == 1 ) {
        
        int d = Integer.parseInt( s.substring( 0, 1 ) );
        
        String t = null;
        
        switch ( d ) {
            
            case 0 : t = "zero" ; break;
            case 1 : t = "one"  ; break;
            case 2 : t = "two"  ; break;
            case 3 : t = "three"; break;
            case 4 : t = "four" ; break;
            case 5 : t = "five" ; break;
            case 6 : t = "six"  ; break;
            case 7 : t = "seven"; break;
            case 8 : t = "eight"; break;
            case 9 : t = "nine" ; break;
            
        }
        
        return t;
        
    }
    
    return "null";
    
}
 

Zurück
Oben