Question

I am getting java.util.NoSuchElementException error. We get this error for the following reasons.

  1. If we don't check if the file has next line before reading it, then it throws exception after reading last line since it is trying to read a line which doesn't exist.
  2. Format of the file is messed up

I think that the format of the file I m using is correct and I am also checking for next line before reading it but I am still getting the error.

When I debug it using print statement, it prints all the line and throws java.util.NoSuchElementException error after reading last line.

Please help me out

Here is the code :

 public static void InterpretMessageFromFile() throws FileNotFoundException{

    File inputfile = new File("filepath");
    Scanner reader = new Scanner(inputfile);

   try {
        while (reader.hasNextLine()) {              
            String MessageType = reader.next();
            int IsAdd = MessageType.compareToIgnoreCase("A");
            int IsCancel = MessageType.compareToIgnoreCase("X");
            int IsDelete = MessageType.compareToIgnoreCase("D");
            int IsExecute = MessageType.compareToIgnoreCase("E");
            int IsReplace = MessageType.compareToIgnoreCase("U");

            //if the type of order is add order to existing Order Book
            if (IsAdd == 0) {
                String retrieve_ts = reader.next();
                int ts = Integer.parseInt(retrieve_ts);

                String retrieve_id = reader.next();
                int id = Integer.parseInt(retrieve_id);

                String or_side = reader.next();
                String retrieve_share = reader.next();
                int share = Integer.parseInt(retrieve_share);

                String retrieve_price = reader.next();
                int price = Integer.parseInt(retrieve_price);

                System.out.println("Add Order : Id is " + id );
                AddOrderToExistingBook.AddNewOrder(id, ts, or_side, share, price);
            }

            //if it is cancel order
            if (IsCancel == 0){
                String retrieve_ts = reader.next();
                int ts = Integer.parseInt(retrieve_ts);

                String retrieve_id = reader.next();
                int id = Integer.parseInt(retrieve_id);
                System.out.println("Cancel Order : Id is " + id + " time stamp is : " + ts );

                CancelOrder.CancelPartOfOrder(id, ts);
            }
            }
        } 
    }
    finally {
        reader.close();
    }
}

Exception (copied from comments):

Exception in thread "main" java.util.NoSuchElementException at java.util.Scanner.throwFor(Scanner.java:907) at java.util.Scanner.next(Scanner.java:1416) at OrderBook.InterpretOrderBookUpdateMessage.InterpretMessageFromFile(InterpretOrde‌​rBookUpdateMessage.java:20) at OrderBook.MainMethod.main(MainMethod.java:50)

Was it helpful?

Solution

you are trying to consume a token that is not there. you do a number of next() calls without checking if there is next. in your case, I suspect a newline at the end of your file gives you an empty line as input. the scanner will see a new line, but as it doesn't contain tokens, calling "next()" will cause an error.

the same would happen if you have empty lines between blocks in your file.

one thing you can use is:

public boolean hasNext(String pattern) 

instead of

next()

this will let you do a lookahead without consuming a token.

so instead of:

String MessageType = reader.next();
int IsAdd = MessageType.compareToIgnoreCase("A");
int IsCancel = MessageType.compareToIgnoreCase("X");
// .... left out other classes

//if the type of order is add order to existing Order Book
if (IsAdd == 0){
    // .. do stuff
}

you can do something like:

if (reader.hasNext("A") {
    reader.next(); // consume A
    int ts = reader.nextInt(); // get id
    // ... etcetera
} else if (reader.hasNext("X") {

}

I would also recommend you use nextInt() instead of nextString and then calling parseInt

One other thing: you can even make your code better to read by doing:

if (reader.hasNext("A") {
    handleAddition(reader);
}

and then later on define a method that only handles this case. your main method will look like:

try
{
    while (reader.hasNextLine())
    {
        if (reader.hasNext("A")) {
            handleAdd(reader);
        } else if (reader.hasNext("X")) {
            handleCancel(reader);
        } else if (reader.hasNext("D")) {
            handleDelete(reader);
        } else if (reader.hasNext("E")) {
            handleExecute(reader);
        } else if (reader.hasNext("R")) {
            handleReplace(reader);
        } else {
            // unexpected token. pretty sure this is the case that triggers your exeception. 
            // basically log as info and ignore.
            reader.nextLine();
        }
    } 
}
finally
{
    reader.close();
}

Now your method is nice and short, and all the specific actions are taken in methods with their own name.

the only thing I'm not 100% about if it it's good practice to consume A, X, R, etc... inside the main loop, or the actual handler method. I prefer to consume inside the method personally.

hope it helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top