String to Int in java - Likely bad data, need to avoid exceptions

前端 未结 16 1709
迷失自我
迷失自我 2020-12-04 18:02

Seeing as Java doesn\'t have nullable types, nor does it have a TryParse(), how do you handle input validation without throwing an exceptions?

The usual way:

相关标签:
16条回答
  • 2020-12-04 18:32

    If you can avoid exceptions by testing beforehand like you said (isParsable()) it might be better--but not all libraries were designed with that in mind.

    I used your trick and it sucks because stack traces on my embedded system are printed regardless of if you catch them or not :(

    0 讨论(0)
  • 2020-12-04 18:35

    For user supplied data, Integer.parseInt is usually the wrong method because it doesn't support internationisation. The java.text package is your (verbose) friend.

    try {
        NumberFormat format = NumberFormat.getIntegerInstance(locale);
        format.setParseIntegerOnly(true);
        format.setMaximumIntegerDigits(9);
        ParsePosition pos = new ParsePosition(0);
        int val = format.parse(str, pos).intValue();
        if (pos.getIndex() != str.length()) {
            // ... handle case of extraneous characters after digits ...
        }
        // ... use val ...
    } catch (java.text.ParseFormatException exc) {
        // ... handle this case appropriately ...
    }
    
    0 讨论(0)
  • 2020-12-04 18:37

    The above code is bad because it is equivalent as the following.

    // this is bad
    int val = Integer.MIN_VALUE;
    try
    {
       val = Integer.parseInt(userdata);
    }
    catch (NumberFormatException ignoreException) { }
    

    The exception is ignored completely. Also, the magic token is bad because an user can pass in -2147483648 (Integer.MIN_VALUE).

    The generic parse-able question is not beneficial. Rather, it should be relevant to the context. Your application has a specific requirement. You can define your method as

    private boolean isUserValueAcceptable(String userData)
    {
       return (    isNumber(userData)    
              &&   isInteger(userData)   
              &&   isBetween(userData, Integer.MIN_VALUE, Integer.MAX_VALUE ) 
              );
    }
    

    Where you can documentation the requirement and you can create well defined and testable rules.

    0 讨论(0)
  • 2020-12-04 18:37

    The exception mechanism is valuable, as it is the only way to get a status indicator in combination with a response value. Furthermore, the status indicator is standardized. If there is an error you get an exception. That way you don't have to think of an error indicator yourself. The controversy is not so much with exceptions, but with Checked Exceptions (e.g. the ones you have to catch or declare).

    Personally I feel you picked one of the examples where exceptions are really valuable. It is a common problem the user enters the wrong value, and typically you will need to get back to the user for the correct value. You normally don't revert to the default value if you ask the user; that gives the user the impression his input matters.

    If you do not want to deal with the exception, just wrap it in a RuntimeException (or derived class) and it will allow you to ignore the exception in your code (and kill your application when it occurs; that's fine too sometimes).

    Some examples on how I would handle NumberFormat exceptions: In web app configuration data:

    loadCertainProperty(String propVal) {
      try
      {
        val = Integer.parseInt(userdata);
        return val;
      }
      catch (NumberFormatException nfe)
      { // RuntimeException need not be declared
        throw new RuntimeException("Property certainProperty in your configuration is expected to be " +
                                   " an integer, but was '" + propVal + "'. Please correct your " +
                                   "configuration and start again");
        // After starting an enterprise application the sysadmin should always check availability
        // and can now correct the property value
      }
    }
    

    In a GUI:

    public int askValue() {
      // TODO add opt-out button; see Swing docs for standard dialog handling
      boolean valueOk = false;
      while(!valueOk) {
        try {
          String val = dialog("Please enter integer value for FOO");
          val = Integer.parseInt(userdata);
          return val; 
        } catch (NumberFormatException nfe) {
          // Ignoring this; I don't care how many typo's the customer makes
        }
      }
    }
    

    In a web form: return the form to the user with a usefull error message and a chance to correct. Most frameworks offer a standardized way of validation.

    0 讨论(0)
  • 2020-12-04 18:42

    Try org.apache.commons.lang.math.NumberUtils.createInteger(String s). That helped me a lot. There are similar methods there for doubles, longs etc.

    0 讨论(0)
  • 2020-12-04 18:43

    Here's how I do it:

    public Integer parseInt(String data) {
      Integer val = null;
      try {
        val = Integer.parseInt(userdata);
      } catch (NumberFormatException nfe) { }
      return val;
    }
    

    Then the null signals invalid data. If you want a default value, you could change it to:

    public Integer parseInt(String data,int default) {
      Integer val = default;
      try {
        val = Integer.parseInt(userdata);
      } catch (NumberFormatException nfe) { }
      return val;
    }
    
    0 讨论(0)
提交回复
热议问题