Search code examples
javafile-iobufferedreader

Getting NoSuchElementException


I am trying to make an application that should help making Dungeon and Dragons items easier for the user!

I have 3 lists of different weapons, with different stats etc. 2 of the lists are added to the program just fine, but 1 of them throws the NoSuchElementException. I really don't understand why, as I can't find anything remotely different from that list, compared to the other lists I've got.

A line from the list looks like this:

 Light Melee Weapon,1d4,1d6,x2,10 ft.,Slashing,Axe (Throwing),8 gp, 2lb.

http://pastebin.com/Fb2db0f1 link to the entire list causing problems if you want to have a look.

http://pastebin.com/9Hg0Rw2a also link to a list that works just fine!

I hope the method is not too long for you to look through. I've really done all I could think of to try and fix this. And I am positive that it's the list causing a problem, because as soon as I removing it from the destination it reads from, the program runs just fine!

It runs through the for loop just fine on the lists that work, but that first list just won't work ._.

Exception in thread "main" java.util.NoSuchElementException
at java.util.StringTokenizer.nextToken(StringTokenizer.java:349)
at MainGUI.init(MainGUI.java:60)
at MainGUI.main(MainGUI.java:32)

public HashMap<String,Weapon> init() {
    String path = "base";
    File folder = new File(path);
    File[] listOfFiles = folder.listFiles();
    if(listOfFiles.length == 0) {
        JOptionPane.showMessageDialog(MainGUI.this, "The folder \"base\" was empty"+
                " so no weapons or armor was attempted loaded.", "Warning",
                JOptionPane.WARNING_MESSAGE);
        return new HashMap<>();
    }
    HashMap<String, Weapon> weapons = new HashMap<>();
    BufferedReader r = null;
    for(File f : listOfFiles) {
        if(f.getName().endsWith(".txt")) {
            String line;
            try {
                r = new BufferedReader(new FileReader(f));
                while((line = r.readLine()) != null) {
                    Weapon w;
                    StringTokenizer st = new StringTokenizer(line,",");
                    while(st.hasMoreTokens()) {

                        w = new Weapon(WeaponCategory.fromString(st.nextToken()),
                                st.nextToken(),st.nextToken(),st.nextToken(),
                                st.nextToken(),st.nextToken(),st.nextToken(),
                                st.nextToken(),st.nextToken());
                        weapons.put(w.getName(), w);
                    }
                }
            } catch(FileNotFoundException fnfe) {
                JOptionPane.showMessageDialog(MainGUI.this, "The File "+
                    f.getName() + " was not found.", "Error",
                    JOptionPane.ERROR_MESSAGE);
            } catch(IOException ioe) {
                JOptionPane.showMessageDialog(MainGUI.this, "There was a problem reading "+
                        f.getName() + ".", "Error",
                        JOptionPane.ERROR_MESSAGE);
            }
        }
    }
    try {
        r.close();
    } catch (IOException ex) {
        JOptionPane.showMessageDialog(MainGUI.this, "An error occured while"
                + "closing the File Reader Stream:\n"+ex.getMessage(),
                "Error", JOptionPane.ERROR_MESSAGE);
    }
    return weapons;
}

Solution

  • Code like this

                    while(st.hasMoreTokens()) {
    
                        w = new Weapon(WeaponCategory.fromString(st.nextToken()),
                                st.nextToken(),st.nextToken(),st.nextToken(),
                                st.nextToken(),st.nextToken(),st.nextToken(),
                                st.nextToken(),st.nextToken());
                        weapons.put(w.getName(), w);
                    }
    

    is unsafe as you assume that each input line has 9 items in it. You should check for the number of items and handle invalid lines gracefully (by e.g. writing out the contents of the line to make it easier to identify the problem).

    One simple way to achieve this would be to use String.split() to tokenize the line. It returns a String[] and you can easily check its size before trying to access its elements.