Fehlerbehebung innerhalb Try/Catch

Nicht zu findender Fehler in einem try/catch Block

Schönen guten Abend liebe Community,

ich habe vor Kurzem mit meinem ersten Projekt - Galgenmännchen mit “Visualisierung” durch Strings in der Konsole - angefangen, es funktioniert auch alles wunderbar, vom Starten des Spiels über die Überprüfung, ob das zufällig gewählte Wort richtig ist oder nicht zum Spielende.

Was mir allerdings Kopfschmerzen bereitet, ist die Tatsache, dass folgende Methode nicht will, wie ich will:

    package hangman;
     
    import java.io.*;
     
    public class WORTAUSWAHL{  
            public static String selectWord(int wortLaenge)  {    
            try {                                                   // Fehlerhandling
                String word = "";
                boolean ende;
                double randomZahl;
                do{
                    ende = false;
                    randomZahl = Math.random();
                    randomZahl *= 91681;                                    // Da Math.random nur zwischen 0 und 1, *91000 (grob die Anzahl der Wörter im Wörterbuch)
                    randomZahl = new Double(randomZahl).intValue();         // Math.random gibt auch kommazahlen, also cast nach int
                                try (FileReader fr = new FileReader("wordlist.txt") // Lade "wordlist.txt". Im selben Verzeichnis lagern!
                                ) {
                                    BufferedReader br = new BufferedReader(fr);         // Lese aus dem File
                                   
                                    for(int i=1;i<randomZahl;i++){                  // Lese eine zufällige Anzahl an Wörtern, damit
                                        br.readLine();                              // der "Lesekopf" an der richtigen Stelle steht
                                    }
                                    do{
                                        word = br.readLine();                       // Nun das Wort auch speichern, falls
                                        if(word == null){                           // das Wort nicht -Nichts- ist (Ende der Liste) und ....
                                            ende = true;
                                            break;                                          // break verhindert eine Exception durch Erreichen des Listenendes
                                        }
                                    }                                               // .... das Wort die geforderte Anzahl an Buchstaben hat,
                                    while(word.length() != wortLaenge);                     // wenn nicht, nächstes Wort lesen usw.
                                   
                                    br.close();                                         // Buffer müssen auch wieder beendet werden,
                                } // Lese aus dem File
                    }
                while (ende);
                return word;  }
               
            catch(IOException c) {                                      // Falls es einen Fehler gibt (datei nicht lesbar usw)
                    String word = "1";                                  // wird word = "1", was später als FehlerZeichen gesehen wird
                    return word;}
                }
    }

Ich habe das Ganze schonmal kommentiert, wenn ich schon da falsch liege, bitte berichtigen. Der “Fehler” ist nun, dass als Wort immer die “Ersatz-Möglichkeit”, nämlich “1” gewählt wird. Ich habe die “wordlist.txt” mit ca. 91000 deutschen Wörtern als “wordlist.txt” im selben package wie die Klasse WORTAUSWAHL abgespeichert.

Wie bekomme ich es hin, dass ein Wort aus diesem .txt-File ausgewählt und an die Hauptklasse zurückgegeben wird?

Ich hoffe auf schnelle Hilfe, weil es nach drei Tagen nun langsam wirklich frustrierend wird,

LG Anta

Die Frage hattest du schon hier gestellt:
[noparse]http://www.java-forum.org/java-basics-anfaenger-themen/160916-findender-fehler-try-catch-block.html[/noparse]

Bei unheimlich vielen Wörtern würde ich speichersparend was ganz anderes vorschlagen:

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

public final class WordList {
	private static final RandomAccessFile LIST;
	private static final Map<Integer, List<Long>> INDEX;

	static {
		File f = new File("./wordlist.txt");
		try {
			LIST = new RandomAccessFile(f, "r");
			INDEX = new TreeMap<>();
			long pointer;
			for(;(pointer = LIST.getFilePointer()) < LIST.length();) {
				String word = LIST.readLine();
				int length = word.length();
				List<Long> pointers = INDEX.get(length);
				if(pointers == null) {
					pointers = new ArrayList<>();
					INDEX.put(length, pointers);
				}
				pointers.add(pointer);
			}
		} catch(IOException e) {
			throw new RuntimeException(e);
		}
	}

	public static String nextRandomWord(int length) {
		List<Long> words = INDEX.get(length);
		if(words == null || words.isEmpty()) {
			throw new IllegalArgumentException("no words with length " + length);
		}
		Collections.shuffle(words);
		try {
			LIST.seek(words.get(0));
			return LIST.readLine();
		} catch(IOException e) {
			return null;
		}
	}

	public static void main(String[] args) {
		System.out.println(nextRandomWord(6));
	}
}```
Das hat zwar den Nachteil, dass die Datei ausserhalb des Jars liegen muss und stets geöffnet ist, aber so geht zumindest die Verwaltung schneller. Kannst aber auch versuchen, statt der Word-Addressen (long) die Strings direkt zu speichern, nur wird dann der Speicherverbrauch wesentlich höher.

BTW.: Normalerweise würde ich das auch nicht so statisch implementieren, aber ich halte mich immer an den Stil der Fragenden.

[QUOTE=njans]Die Frage hattest du schon hier gestellt:
Wir wollen doch hier keine Werbung machen - ein Link dahin reicht… ;)[/QUOTE]

Und hier kann er sie nochmal stellen.

zum ursprünglichen Code:
lieber erstmal mit einer einfachen Datei mit 5 Einträgen testen,
genau loggen welche Zufallszahl gewählt wird, welche Zeilen aus der Datei gelesen werden usw.,

wohin der Titel schon geht und die Rückgabe „1“ auch, ist aber aktuell vor allem das catch interessant,
du bekommst Exceptions und weißt nicht weiter?
das ist doch keine tragbare Einstellung zur Programmierung :wink:

gib die Exception aus, wie generell immer und überall zu empfehlen,
du willst etwas wissen, also untersuche es weiter

c.printStackTrace();

@Spacerat Warum nicht einfach die Textfile Line-per-Line einlesen und direkt in einer HashMap storen? Da braucht man auch nicht die ganze Zeit die File geöffnet lassen. Außerdem ist es irrelevant ob die Datei innerhalb oder außerhalb liegt - Bekanntlich ist ja alles möglich :wink:

@Bizarrus : Wie gesagt… Speicherverbrauch! :wink:

wenn wir gerade beim gnadenlosen Analysieren sind :wink: :

  • falls die Wortlänge auf irgendwas humanes maximales wie 1000 einzugrenzen ist, dann vielleicht Array statt Map, kein Autoboxing int zu Integer

  • für einen Zufallswert aus einer Liste doch besser den etwas umständlichen aber behutsamen Weg eines Zufallswertes mit Random,

stattdessen mit Collection.shuffle() die Liste komplett umzubauen kann zigfacher Aufwand sein und ändert die Datenlage:
ein nebenläufiger Zugriff könnte fatal sein,
bisher nicht durch Synchronisation geschützt, bei rein lesenden Zugriff auch gar nicht nötig

[QUOTE=SlaterB]- für einen Zufallswert aus einer Liste doch besser den etwas umständlichen aber behutsamen Weg eines Zufallswertes mit Random,

stattdessen mit Collection.shuffle() die Liste komplett umzubauen kann zigfacher Aufwand sein und ändert die Datenlage:
ein nebenläufiger Zugriff könnte fatal sein,
bisher nicht durch Synchronisation geschützt, bei rein lesenden Zugriff auch gar nicht nötig[/QUOTE]Ok, genehmigt…

dies

                    randomZahl *= 91681;                                    // Da Math.random nur zwischen 0 und 1, *91000 (grob die Anzahl der Wörter im Wörterbuch)
                    randomZahl = new Double(randomZahl).intValue();         // Math.random gibt auch kommazahlen, also cast nach int```
könnte auch so aussehen:```randomZahl=new Random().nextInt(91681);```
bye
TT