What is the proper way to handle a NumberFormatException when it is expected?
Asked Answered
F

8

21

I'm running into this situation where I need to parse a String into an int and I don't know what to do with the NumberFormatException. The compiler doesn't complain when I don't catch it, but I just want to make sure that I'm handling this situation properly.

private int getCurrentPieceAsInt() {
    int i = 0;
    try {
        i = Integer.parseInt(this.getCurrentPiece());
    } catch (NumberFormatException e) {
        i = 0;
    }
    return i;
}

I want to just simplify my code like this. The compiler doesn't have a problem with it, but the thread dies on the NumberFormatException.

private int getCurrentPieceAsInt() {
    int i = 0;
    i = Integer.parseInt(this.getCurrentPiece());
    return i;
}

Google CodePro wants me to log the exception in some way, and I agree that this is best practice.

private int getCurrentPieceAsInt() {
    int i = 0;
    try {
        i = Integer.parseInt(this.getCurrentPiece());
    } catch (NumberFormatException e) {
        i = 0;
        e.printStackTrace();
    }
    return i;
}

I want this method to return 0 when the current piece is not a number or cannot be parsed. When I don't catch the NumberFormatException explicitly, does it not assign the variable i? Or is there some default value that Integer.parseInt() returns?

General style says that if I catch an exception, I should log it somewhere. I don't want to log it. It's normal operation for this exception to be thrown sometimes, which also doesn't sit well with me. I cannot find a function, however, which will tell me if Integer.parseInt() will throw an exception. So my only course of action seems to be to just call it and catch the exception.

The javadoc for parseInt doesn't help much.

Here are the specific questions I'd like to know:

  • Is there a method that I can call that will tell me if Integer.parseInt() will throw a NumberFormatException before calling it? Then I would have no problem logging this, since it should never happen.
  • If I simply do not catch the exception, will the valiable not get assigned? Then I will simply initialize it to the value that I want when it's not a number and not catch the exception.
  • Is there a way to mark the exception somehow explicitly that I don't care about it? I'm thinking this would be something similar to AWTEvent.consume(). If so, then I will do this so that Google CodePro doesn't see this as "unlogged".
Fake answered 10/12, 2010 at 15:1 Comment(3)
"If I simply do not catch the exception, will the valiable not get assigned? Then I will simply not catch the exception." - if you're unsure about whether this is a viable option, I suggest you try it (and walkthrough with a debugger) to be 100% sure you understand what happens in this case. I don't mean to sound like I'm talking down, but I feel that having a solid understanding of exceptions is important.Aquinas
I'm not a Java programmer but in C#, Integer has a TryParse() method which tries the parse the int and returns a bool on whether it was successful. Surely thats better than expecting an exception.Peafowl
I would love it if there was a tryParse() method. I think I understand why there's not one, since it basically means doing the work twice. Also, when I try it, the uncaught NumberFormatException kills the thread on the spot. I updated the question to reflect this.Fake
B
14
  • Is there a method that I can call that will tell me if Integer.parseInt() will throw a NumberFormatException before calling it? Then I would have no problem logging this, since it should never happen.

Sadly, no. At least not in the core Java API. It's easy to write one, however - just modify the code below.

  • If I simply do not catch the exception, will the valiable not get assigned? Then I will simply initialize it to the value that I want when it's not a number and not catch the exception.

If you do not catch the exception then the stack will unwind until it hits a catch block that will handle it, or it will unwind completely and halt the thread. The variable will, in fact, not be assigned but this is not exactly what you want.

  • Is there a way to mark the exception somehow explicitly that I don't care about it? I'm thinking this would be something similar to AWTEvent.consume(). If so, then I will do this so that Google CodePro doesn't see this as "unlogged".

There may be a way to tell CodePro to ignore this particular warning. Certainly with tools like FindBugs and Checkstyle you can turn off warnings in specific locations. (EDIT: @Andy has pointed out how to do this.)

I suspect what you want is something like the Commons lang package mentioned by @daveb. It's pretty easy to write such a function:

int parseWithDefault(String s, int def) {
    try {
        return Integer.parseInt(s);
    }
    catch (NumberFormatException e) {
        // It's OK to ignore "e" here because returning a default value is the documented behaviour on invalid input.
        return def;
    }
}
Bujumbura answered 10/12, 2010 at 15:19 Comment(1)
CodePro is incorrect in requiring logging for every catch. In this case it's perfectly okay to eat the exception since that is the desired and documented behavior of the method.Alixaliza
B
10

There is NumberUtils.toInt(String, int) in commons lang which will do exactly what you want.

NumberUtils.toInt("123", 42) ==> 123
NumberUtils.toInt("abc", 42) ==> 42
Birthplace answered 10/12, 2010 at 15:7 Comment(4)
Can't I do this in some way without importing Apache Commons?Fake
Yep, but many projects use commons lang so don't need to roll their own impl.Birthplace
I've so far avoided doing either.Fake
NumberUtils just catches it in there. Doesn't get around catching it. :)Keeler
G
3
* Is there a way to mark the exception somehow explicitly that I don't care about it? I'm thinking this would be something similar to AWTEvent.consume(). If so, then I will do this so that Google CodePro doesn't see this as "unlogged".

Yes, you can locally disable a CodePro audit rule for one line of code:

http://code.google.com/javadevtools/codepro/doc/features/audit/locally_disabling_audit_rules.html

That said, it is not necessarily required to include diagnostic logging in every exception catch block. Sometimes, the best action is to take a default course. Sometime it's to interact with the user. It depends.

Grandiloquent answered 10/12, 2010 at 15:25 Comment(0)
A
1

Create your own convenience method for now and future use:

public static int parseInt(final /*@Nullable*/ String s, final int valueIfInvalid) {
    try {
        if (s == null) {
            return valueIfInvalid;
        } else {
            return Integer.parseInt(s);
        }
    } catch (final NumberFormatException ex) {
        return valueIfInvalid;
    }
}

Is there a method that I can call that will tell me if Integer.parseInt() will throw a NumberFormatException before calling it? Then I would have no problem logging this, since it should never happen.

Not that I'm aware of. Keep in mind that if there were, you likely end up parsing the value twice (once to validate and once to parse it). I understand you want to avoid the exception, but in this case, this is catching the exception is the standard idiom in Java and it doesn't provide another (at least that I know of).

If I simply do not catch the exception, will the valiable not get assigned? Then I will simply initialize it to the value that I want when it's not a number and not catch the exception.

You must catch the exception (even if it does nothing) or it will escape the block and throw up through the stack.

Is there a way to mark the exception somehow explicitly that I don't care about it? I'm thinking this would be something similar to AWTEvent.consume(). If so, then I will do this so that Google CodePro doesn't see this as "unlogged".

I don't know of any. I would use the above convenience method (I have something similar in a small collection of general utilities I have available for use on my all projects).

I wouldn't log it if its truly a normal condition that you are handling. I'm not familiiar with Google CodePro, but I would hope there is a way to suppress the warning, e.g. some sort of @SuppressWarnings("xxx") annotation/keyword.


Edit: I wanted to point out these comments in the comments below

This approach still doesn't handle the exception. It's bad form to catch an exception and do nothing with it. This is why I am looking for a better solution

.

... The exception (the situation) is being handled by returning the indicated valueIfInvalid. The "bad form" you are referring to the poor practice of blindly and unthinkingly writing empty catch blocks and never going back to truly consider and address the case. If the exception situation is considered and does the right thing for the situation (even if the right thing is to do nothing), then you've "handled" the exception.

Aquinas answered 10/12, 2010 at 15:8 Comment(6)
This approach still doesn't handle the exception. It's bad form to catch an exception and do nothing with it. This is why I am looking for a better solution.Fake
It's not bad form if you know that you really don't want to do anything with it. It's only bad form to ignore exceptions that you should be doing something useful with.Bujumbura
@Erick - I concur with @Cameron. The exception (the situation) is being handled by returning the indicated valueIfInvalid. The general notion of "unhandled exception" is referring to the poor practice of blindly and unthinkly writing empty catch blocks and never going back to truly consider and address the case. If the exception situation is considered and does the right thing for the situation (even if the right thing is to do nothing), you've "handled" the exception.Aquinas
@Bert F- what does final exception mean?Outride
@Alaa - final keyword - just a habit of mine - just means the ex variable will never be assigned another value. See #138368Aquinas
@ Steve Kuo- final can nerver be clutterOutride
D
0

You should catch the Exception as you are doing. It is annoying, but the best approach.

There is no Java API method that will return 0 when the string is not a valid int.

When the string is not an int, an exception will be thrown so your int variable will not be set unless you catch the exception as you are doing.

Diseased answered 10/12, 2010 at 15:2 Comment(1)
Then what do I do with it after I catch it? I don't want to log it, because it is normal. It's not an exception case. Leaving it unlogged works, but catching an exception and doing nothing with it is bad form. I am looking for a better answer.Fake
A
0

Your first code block is correct. i won't be implicitly converted to 0 when an exception occurs and you have to catch that exception. Setting i to 0 inside catch is correct; although you can simply replace i = 0; with return 0;. You cannot avoid exception handling in this case.

To clarify, you can use this:

private int getCurrentPieceAsInt() {
    int i = 0;
    try {
        i = Integer.parseInt(this.getCurrentPiece());
    } catch (NumberFormatException e) {
        // log that an exception occured if it's needed
        return 0;
    }
    return i;
}
Anhinga answered 10/12, 2010 at 15:5 Comment(2)
What can I do with the exception to explicitly mark it as handled? It is bad form to catch an exception and do nothing with it, so I am seeking a better solution.Fake
no, it's not bad form to catch an exception and do nothing with it. The point of checked exceptions is so that you can catch them and handle them how your application needs to - sometimes that involves logging or recovery, but sometimes you know that it doesn't matter.Wolfe
D
0

If its not clear how you should handle it from the getter, you shouldn't catch it and let the caller deal with it instead. If you know how it should be handled you should just do that. Logging it may not be required or very useful in this case.

Logging an exception is more useful if you don't know how to handle the exception and you are leaving it to the person reading the logs.

Decuple answered 10/12, 2010 at 15:9 Comment(1)
Precisely. This is why I am seeking a way to mark the exception as handled without logging it.Fake
R
0

As others have mentioned, there is not a built-in core Java API method you can call to validate an integer, but you can use the Character class to validate your input without using exception handling. For example:

package com.example.parseint;

public class ValidateIntExample {
    public static boolean isInteger(String s) {
        if (s == null) {
            return false;
        }

        s = s.trim();

        if (s.length() == 0) {
            return false;
        }

        int start = 0;
        if (s.charAt(0) == '-') { // handle negative numbers
            if (s.length() == 1) {
                return false;
            }
            else {
                start = 1;
            }
        }

        for (int i = start; i < s.length(); i++) {
            if (! Character.isDigit(s.charAt(i))) {
                return false;
            }
        }

        return true;
    }
}

In fact, parseInt itself uses Character.isDigit internally, which you can verify in the JRE source code. (Sorry, I would have included the parseInt method here, but I'm not sure if I'm allowed under the license terms.) If you're using Eclipse and you have the JRE source code attached to your project, you can right-click on the method Integer.parseInt in your code and click Open Declaration.

Romaine answered 12/12, 2012 at 23:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.