Interpreter-Fehler StringIndexOutOfBoundsException

Dancger

Mitglied
Heyho zusammen ;)

Ich bin gerade daran, ein Programm von VB.Net auf Java umzuschreiben. Das schlussendliche Produkt ist ein Diagramm.

Die Daten für das Diagramm erhalte ich über eine Textdatei, welche ich zuvor einlese. Danach muss ich die Daten zurecht basteln, um sie verarbeiten zu können.

Und genau hier passiert der Fehler. Während der Laufzeit erhalte ich eine "StringIndexOutOfBoundsException", welche meiner Meinung nach merkwürdig ist, weil ich keinen Fehler sehen kann (auch nicht im Debugger).

Folgender Code:
Java:
	public boolean readdatafromfile(String pth){
		
		//Textinhalt holen
		String[] input = fc.GetFileContentAsLines(pth);
		
		//Inhalt prüfen
		if (input.length == 0){
			return false;
		}
		
		//Aktuelle Daten löschen
		datalist.clear();
		
		//Aktuellen Pfad ändern
		currentpath = pth;
		System.out.println(currentpath);
		
		//Variablen
		int idx_firstnumber = 0;
		int idx_lastnumber = 0;
		boolean bl_readpolicies = false;
		
		//Auslesen
		for (int idx = 0; idx < input.length;idx++){
			
			//Zeile bestimmen
			lne = "";
			lne = input[idx];
			
			
			//Index oder Daten lesen
			if (!bl_readpolicies){
								
				//Index LastNumber lesen
				if (lne.trim().contains("AVG")){
					idx_lastnumber = (int) lne.substring(0, lne.indexOf("AVG")).length();
				}
				
				//Index FirstNumber lesen
				if (lne.trim().startsWith("01")){ //contains
					idx_firstnumber = (int) lne.substring(0,lne.indexOf("01")).length();
				}
				
				//Anfangspunkt suchen
				if (lne.startsWith("----------")){
					bl_readpolicies = true;
				}
								
			} else {
				
				//Abbrechen wenn keine Daten mehr kommen
				if (lne.trim() == ""){
					break;
				}

				//Neue SpezialListe erstellen
				String spl_name = (String) input[idx].substring(0, idx_firstnumber).trim();
				SpecialList spl = new SpecialList(spl_name);
			
				//Alle Einträge auslesen
				for(int idx2 = idx_firstnumber; idx2 <= idx_lastnumber; idx+=3){
					
					//Auslesen der ANzahl Stunden
					String anzstd_string;
					try {
						anzstd_string = lne.substring(idx2, 2);
					} catch (Exception e) {
						break;
					}
					
					//Prüfen ob numerisch
					try {
						
						//Parsen
						int anzstd = Integer.parseInt(anzstd_string);
						
						//Überschritten / Standard
						if (anzstd > 48){
							spl.add(new SpecialListItem(anzstd,enm_valuetyp.limitexceeded));
						} else {
							spl.add(new SpecialListItem(anzstd,enm_valuetyp.standard));
						}
					} catch (Exception e) {
						switch (anzstd_string){
							case "-":
								spl.add(new SpecialListItem(0,enm_valuetyp.error));
								break;
							case "":
								spl.add(new SpecialListItem(0, enm_valuetyp.blank));
								break;
							case "*":
								spl.add(new SpecialListItem(0,enm_valuetyp.unfinished));
								break;
							default:
								System.out.println("Fail AnzStd: " + anzstd_string);
								break;
						}
					}

				}
				
				//Daten einer Reihe hinzufügen
				datalist.add(spl);
				
			}
			
		}
		
		//Erfolgreiche Rückgabe
		return true;
			
	}

Da Code alleine nicht ericht, werde ich kurz die wichtigsten Stellen erklären:
Auf Zeile 4: [JAVA=4]String[] input = fc.GetFileContentAsLines(pth);[/code] kriege ich mein eingelesenes Textfile als Array zurück.

Die eigentliche Arbeit fängt ab Zeile 24 an. Im "IF" lese ich solange die Textdatei ein, bis "Idx_FirstNumber" und "Idx_LastNumber" gesetzt sind. Danach komme ich in den "ELSE" Teil, und hier passiert der Fehler.

Lasse ich mein Programm laufen, stürzt das Programm erst auf Zeile 58 ab. Folgende Fehlermeldung:
Exception in thread "AWT-EventQueue-0" java.lang.StringIndexOutOfBoundsException: String index out of range: 31
at java.lang.String.substring(Unknown Source)
at business.StatsController.readdatafromfile(StatsController.java:111)

StatsController.java:111 entspricht der Zeile 57 im Code oben.

Debugge ich nun, stürzt das Programm direkt auf Zeile 57 ab, mit der gleichen Fehlermeldung.

Die Werte während des debuggens sehen wie folgt aus:

lne = '_VXC_POLICY_ai_b0_cbw_vs_01 2 1 2 2 - - - - 1 1 1 1 1 1 1 1 '
idx_firstnumber = 31

Schlussendlich meine Frage:
Wieso stürzt das Programm auf dieser Zeile ab, wenn ich einen String kürzen will, welcher 127 Zeichen lang ist, ich jedoch nur die ersten 31 Zeichen abschneide? Sollte meiner Meinung nach funktionieren.

Erkentnisse von Analysen:
  • Ersetzte ich im Debugger manuell den Wert von der Variable 'lne' auf "aaa... (127 x 'a'), funktioniert alles
  • Setze ich den Wert von 'idx_firstnumber' manuell auf 31, funktioniert ebenfalls alles

System:
  • Windows 7 Enterprise 32b
  • Installierte Java Versionen: JDK7u5, JRE6u35, JRE7u5, JDK6u34, JavaFX 2.1.1 und SDK davon
  • Projektbiblitohek = Execution environment: JavaSE-1.7 (jre7)

Bin nun echt ratlos, bin seit zwei Tagen (Heute wirds der 3te) am debuggen und finde den Fehler einfach nicht.

Habe ebenfalls schon auf "stackoverflow.com" gepostet, jedoch haben die auch nicht weiter gewusst. :(

Ich hoffe das hier jemand meinen Fehler sieht und mir helfen kann.
Falls weitere Fragen sind (mehr Code, mehr Erklärungen, etc.), werde ich diese Informationen Saspo posten.

Jetzt schon vielen Dank für eure Hilfe, Greez Dancger :D
 
Zuletzt bearbeitet von einem Moderator:

Spin

Top Contributor
Moin,

StringIndexOutOfBoundsException

Thrown by String methods to indicate that an index is either negative or greater than the size of the string. For some methods such as the charAt method, this exception also is thrown when the index is equal to the size of the string.

Deine Logik sieht jetzt nicht sonderlich schwer aus - ach mensch java hat immer so viel boilerplate :autsch:

Dein Quellcode scheint auf den ersten Blick richtig - gibt dir doch einfach mal input aus. Ohne den ganzen Prüf Kram. IndexOfBound bedeuted immer, dass auf ein Index zugriffen wird, zu dem der Wert null ist.

Wenn du also dein Code auskommentierst und einfach mal inupt[idx] komplett für dein File ausgeben lässt, müsste zu jeden index ein Zeile kommen ?!

Vielleicht passiert der Fehler auch schon beim einlesen, weil ein Leerzeichen als null gilt oder wie auch immer. Du kannst ja sonst einfach mal den Kram aus dem Textfile lassen und ein hardcodiertes Array reinpacken. Dann können wir es auch mal kompilieren :)

grüße spin
 

X5-599

Top Contributor
Hmm, hört sich schonmal komisch an. Bastel doch um die substring Zeile ein try catch und fang diese StringIndexOutOfBoundsException ab. Dann kannst du dir ja ausgeben lassen mit: System.out.println(input[idx]) wie die böse Zeile aussieht, die das verursacht hat.

Aber wie gesagt, komisch ists schon. Im Debugger müsste es eigentlich auch nachzuvollziehen sein.

Auch: sollte Zeile 52 nicht eher so aussehen?
Java:
//Abbrechen wenn keine Daten mehr kommen
if (lne.trim().equals("")) {
    break;
}
 

Dancger

Mitglied
gibt dir doch einfach mal input aus. Ohne den ganzen Prüf Kram. IndexOfBound bedeuted immer, dass auf ein Index zugriffen wird, zu dem der Wert null ist.
Hab ich alles ausgegeben, Index sowie Inhalt stimmt. Alle Linien exakt wie im Textfile. Alles vorhanden, jeder Index geht.

Auch: sollte Zeile 52 nicht eher so aussehen?
Java:
//Abbrechen wenn keine Daten mehr kommen
if (lne.trim().equals("")) {
    break;
}
Danke für die Korrektur, hat aber trotzdem schon funktioniert :)

Hmm, hört sich schonmal komisch an. Bastel doch um die substring Zeile ein try catch und fang diese StringIndexOutOfBoundsException ab. Dann kannst du dir ja ausgeben lassen mit: System.out.println(input[idx]) wie die böse Zeile aussieht, die das verursacht hat.[/code]
Ich glaubs net. Sobald ich ein Try-Catch einbaue, läuft der ganze Code exakt, aber wirklich genau so wie es sollte. Anzahl Datensätze stimmen mit der Anzahl der Zeilen überein.

Ich habe nur:
Java:
//Neue SpezialListe erstellen
String spl_name = (String) input[idx].substring(0, idx_firstnumber).trim();
SpecialList spl = new SpecialList(spl_name);

durch

Java:
//Neue SpezialListe erstellen
String spl_name = "";
SpecialList spl = null;
try {
	spl_name = (String) lne.substring(0, idx_firstnumber).trim();
	spl = new SpecialList(spl_name);
} catch (Exception e) {
	System.out.println(e);
}

Jetzt versteh ich die Welt nicht mehr. Könnt ihr mir sagen wieso??

Greez Dancger
 

fastjack

Top Contributor
Der ganze code ist strange und verworren... Ich würde lne nur einmal trimmen, du trimmst andauernd denselben String...

Außderm bau mal vor die Fehlermeldung ein System.out.println(lne); ein, dann sieht man mehr.

Das ist auch komisch:

Code:
//Index FirstNumber lesen
                if (lne.trim().startsWith("01")){ //contains
                    idx_firstnumber = (int) lne.substring(0,lne.indexOf("01")).length();
                }

Wenn der String schon mit 01 beginnt, ist der indexOf 0, also wird dort ein substring(0, 0) aus lne genommen, wieder strange...
 

Dancger

Mitglied
Der ganze code ist strange und verworren... Ich würde lne nur einmal trimmen, du trimmst andauernd denselben String...
Ich brauch den String manchmal getrimmt, manchmal nicht. Erklärung weiter unten.

Außderm bau mal vor die Fehlermeldung ein System.out.println(lne); ein, dann sieht man mehr
Hab ich schon, war alles richtig.

Das ist auch komisch:

Code:
//Index FirstNumber lesen
                if (lne.trim().startsWith("01")){ //contains
                    idx_firstnumber = (int) lne.substring(0,lne.indexOf("01")).length();
                }

Wenn der String schon mit 01 beginnt, ist der indexOf 0, also wird dort ein substring(0, 0) aus lne genommen, wieder strange...
Erklär mir bitte warum und poste doch ein paar Verbesserungsvorschläge. Bin bereit zu lernen, wenn man mir's erklärt.

Zum Code, der Input sieht so aus: (Super, der Editor verschluckt aufeinander folgende Leerzeichen)
" 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 "
Textuelle Erklärtung: [31 mal ein Leerzeichen, danach folgt die Nummerierung von 01 bis 31 mit jeweils einem Leerzeichen dazwischen]

Wenn also 'lne' getrimmt wird, ist "01" die erste Zeichenfolge. Wenn ich jedoch den Index ohne Trim Abfrage, gibt es 31. Und genau diese Zahl muss ich haben, da ich nicht weiss, wieviele Leerzeichen zwischen dem Start und der ersten "01" liegen.

Greez Dancger
 
Zuletzt bearbeitet:

fastjack

Top Contributor
Wenn Du weist, das ein String mit 01 beginnt, weist Du auch den index des ersten 01, oder?

Du mußt nur einmal trimmen, z.B. lne = lne.trim();

Ist die Anzahl an Leerzeichen zwischen den Elementen immer 1?, als "01 05 06" oder gibt es auch sowas: "01 06 07 08 09"?
 

Dancger

Mitglied
Grund: du hast im else Zweig Werte aus dem vorherigen Schleifendurchlauf!
Naja eigentlich logisch. Aber die werden aber ja beim nächsten Durchlauf überschrieben, was dann keine Rolle mehr spielen sollte, oder seh ich das falsch? (Meinst du eine bestimmte Variable?)

Wenn Du weist, das ein String mit 01 beginnt, weist Du auch den index des ersten 01, oder?

Du mußt nur einmal trimmen, z.B. lne = lne.trim();

Ist die Anzahl an Leerzeichen zwischen den Elementen immer 1?, als "01 05 06" oder gibt es auch sowas: "01 06 07 08 09"?
Nein, eben nicht. Da die Anzahl der Leerzeichen zwischen dem Zeilenanfang und dem ersten "01" variieren kann. Ich glaube ohne Beispiel wird das nix:
bsp.png

Wie du siehst muss ich die Position der "01" ohne Trim haben, da ich sonst einen falschen Index bekomme, um den Servernamen (VXC_...) auszulesen.

Greez Dancger
 
B

bone2

Gast
Warum castest du ints auf int und Strings auf String?
 
Zuletzt bearbeitet von einem Moderator:

Dancger

Mitglied

fastjack

Top Contributor
Ich würde es so machen: (ist natürlich nur ein kleines beispiel ohne echte Daten)

Code:
    public boolean foo() {
        //Textinhalt holen
        String[] input = new String[]{
                "                 01 02 03 04 05 06 07 08 09 AVG ",
                "-----------------------------------------------",
                "alfons            5  3  -  -  -  -  -  -  8  6 ",
                "bunny             -  5  -  6  -  8  -  -  -  4 ",
        };

        //Inhalt prüfen
        if (input.length == 0){
            return false;
        } else {
            // scan header
            String header = input[0];
            //      get begin
            int begin = header.indexOf("01");
            if (begin < 0) {
                // error no begin
                return false;
            }

            //      get end of data in line
            int endOfData = header.indexOf("AVG");
            if (endOfData < 0) {
                // error no end of data
                return false;
            }

            System.out.printf("offset: %s, endOfData: %s\n", begin, endOfData);

            // scan data
            for (int i = 1; i < input.length; i ++) { // ignore header
                String line = input[i];
                // ignore separator line
                if (!line.startsWith("-----")) {
                    String key = line.substring(0, begin);
                    System.out.printf("key: %s\n", key);
                    int z = 0;
                    for (int ii = begin; ii < endOfData; ii += 3) {
                        z ++;
                        String value = line.substring(ii, ii + 2);
                        System.out.printf("col: %s, value:%s\n", z, value);

                        // translate value to time in hours
                        // create SpecialListItem
                        // add to SpecialList

                    }
                }
            }
        }
        return false;
    }

Ausgabe:

Code:
offset: 17, endOfData: 44
key: alfons           
col: 1, value: 5
col: 2, value: 3
col: 3, value: -
col: 4, value: -
col: 5, value: -
col: 6, value: -
col: 7, value: -
col: 8, value: -
col: 9, value: 8
key: bunny            
col: 1, value: -
col: 2, value: 5
col: 3, value: -
col: 4, value: 6
col: 5, value: -
col: 6, value: 8
col: 7, value: -
col: 8, value: -
col: 9, value: -
 
B

bone2

Gast
was soll das?
Code:
lne.substring(0,lne.indexOf("01")).length()
da kommt das gleiche raus wie bei
Code:
lne.indexOf("01")

poste mal bitte so eine Zeile in [noparse]
Code:
[/noparse] tags damit leerzeichen erhalten bleiben
Code:
       a      a
 

Dancger

Mitglied
was soll das?
Code:
lne.substring(0,lne.indexOf("01")).length()
da kommt das gleiche raus wie bei
Code:
lne.indexOf("01")

poste mal bitte so eine Zeile in [noparse]
Code:
[/noparse] tags damit leerzeichen erhalten bleiben
Code:
       a      a
Hoppla, da war ich wohl nicht mehr frisch, hab zu weit gedacht resp. zu kompliziert gedacht :lol:

Ich würde es so machen: (ist natürlich nur ein kleines beispiel ohne echte Daten)
Wow, danke.
Hab denn Code kurz auf meine Dateien umgeschrieben und den Output kurz überprüft, stimmt bis jetzt alles. Ausserdem ist der so schön kurz ;)

Ich werde denn Code umschreiben und dann ins richtige Programm einbauen. Falls etwas nicht funktioniert, werde ich mich wieder melden.

Danke dir, FastJack :toll:

Greez Dancger
 

Bleiglanz

Gesperrter Benutzer
Naja eigentlich logisch. Aber die werden aber ja beim nächsten Durchlauf überschrieben, was dann keine Rolle mehr spielen sollte, oder seh ich das falsch? (Meinst du eine bestimmte Variable?)
Nicht, wenn du in den else-Zweig gehst (!), dort hat nämlich idx_firstnumber den vorherigen Wert...

überhaupt:
Code:
substring
ist sicher nicht defekt, schau dir halt im Debugger mal genau an, welche werte
Java:
input[idx]
idx_firstnumber
haben wenn der Fehler fliegt
 

Dancger

Mitglied
Nicht, wenn du in den else-Zweig gehst (!), dort hat nämlich idx_firstnumber den vorherigen Wert...

überhaupt:
Code:
substring
ist sicher nicht defekt, schau dir halt im Debugger mal genau an, welche werte
Java:
input[idx]
idx_firstnumber
haben wenn der Fehler fliegt
Idx_FirstNumber wird auch nur einmalig im IF Abzweig gesetzt.

Da mir das auf StackOverflow auch niemand geglaubt hat, dass die Debugwerte stimmen, hab ich 3 Printscreens beim debuggen geschossen, sieh selbst:
http://dancger.pf-control.de/images/step1.png
http://dancger.pf-control.de/images/step2.png
http://dancger.pf-control.de/images/step3.png

Greez
 

Dancger

Mitglied
nein, bei jedem Schleifendurchlauf

wenn !bl_readpolicies dann änderst du diese Werte

wenn bl_readpolicies dann versuchst du substring auf die aktuelle Zeile mit welchem Wert für idx_firstNumber?

Okey, ich poste mal ein vollständiges Beispiel einer Datei. Dann sit der Aufbau klar:
Code:
Some Lines with Text ..
Blabla.. 
Word                           Do Fr Sa So Mo Di Mi Do Fr Sa So Mo Di Mi Do Fr Sa So Mo Di Mi Do Fr Sa So Mo Di Mi Do Fr    AVG
                               01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30    
-------------------------------------------------------------------------------------------------------------------------------
_VXC_POLICY_ai_b0_cbw_vs_01       2        1     2     2        -  -  -  -  1        1     1     1        1     1     1     1  
_VXC_POLICY_ai_b1_cbw_vs_01          65       -     -     27       -     17    25       -  -  -     28       39    46       35 
_VXC_POLICY_ai_a0_ccr_vs_01       4        3     2     1        1     1     1        1     1     1        -     44    23    6

So wird, bevor die richtigen Daten kommen, bl_readpolicies auf true gesetzt, und kommt darum nicht mehr in den If Zweig.

Wert von Idx_FirstNumber ist 31.

Grüsse
 
Zuletzt bearbeitet:

Bleiglanz

Gesperrter Benutzer
ausserdem: step2.png zeigt doch dass alles OK ist, wie schaut den der Konstruktor von
Code:
SpecialList
aus?
 

Dancger

Mitglied
ausserdem: step2.png zeigt doch dass alles OK ist, wie schaut den der Konstruktor von
Code:
SpecialList
aus?
Dafür krachts beim nächsten Schritt, mit der Fehlermeldung von der vorherigen Zeile.. :bahnhof:

SpecialList:
Code:
public class SpecialList {

	//Variablen
	private ArrayList<SpecialListItem> _list = new ArrayList<SpecialListItem>();
	private String listname = "";
	
	//Konstruktor
	SpecialList(String name){
		listname = name;
	}

Grüsse :D
 

Bleiglanz

Gesperrter Benutzer
BTW: den Anfang einer solchen Zeile findest du so:
Java:
        String lne = "_VXC_POLICY_ai_b0_cbw_vs_01 2 1 2 2 - - - - 1 1 1 1 1 1 1 1 ";
        Matcher suchMuster = Pattern.compile(".*?\\b\\s").matcher(lne); 
        suchMuster.find();
        System.out.println(suchMuster.group(0));
du machst schon arg viel substring/indexOf-Gymnastik, das ist oft schwer zu debuggen.
 

Bleiglanz

Gesperrter Benutzer
Warum ist der Konstruktor nicht public?

Aber was sollst: du willst wohl die Zeilen anfangs abschneiden, dann die Zahlen in zugeordnete Listen stecken?

Warum nicht mit einer
Code:
Map<String,List>
, das würde den Code sehr vereinfachen!
 

Dancger

Mitglied
@Bleiglanz
Danke für den Codeschnippsel. Hab ihn eigebaut.
SpecialList aufgrund, weil ich später diverse Spezialfunktionen einbauen muss, und Map ist dann weniger angebracht.

Habe den Fehler jetzt gefunden. Es lag an der Methode, welche das File einliest. Das gab irgendwelche Probleme, obwohl die Ausgabe der Zeilen der eingelesenen Datei richtig war.
Nun funktioniert auch der erste gepostete Code.

Trotzdem ein Danke an alle :toll:

Greez Dancger
 

Ähnliche Java Themen

Neue Themen


Oben