111

I have a project in which we often use Integer.parseInt() to convert a String to an int. When something goes wrong (for example, the String is not a number but the letter a, or whatever) this method will throw an exception. However, if I have to handle exceptions in my code everywhere, this starts to look very ugly very quickly. I would like to put this in a method, however, I have no clue how to return a clean value in order to show that the conversion went wrong.

In C++ I could have created a method that accepted a pointer to an int and let the method itself return true or false. However, as far as I know, this is not possible in Java. I could also create an object that contains a true/false variable and the converted value, but this does not seem ideal either. The same thing goes for a global value, and this might give me some trouble with multithreading.

So is there a clean way to do this?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Bad Horse
  • 1,113
  • 2
  • 7
  • 4
  • [The characters in the string must all be decimal digits, except that the first character ...](https://docs.oracle.com/javase/7/docs/api/java/lang/Integer.html#parseInt%28java.lang.String%29). Instead of handling exceptions everywhere in the code, just check the string format before calling the parse method. – Lightman Dec 20 '15 at 13:27
  • 1
    It's next to impossible to write a regex that will capture all valid 32-bit signed integers and none of the invalid ones. 2147483647 is a legal `int` while 2147483648 isn't. – Seva Alekseyev Oct 20 '19 at 23:03

27 Answers27

159

You could return an Integer instead of an int, returning null on parse failure.

It's a shame Java doesn't provide a way of doing this without there being an exception thrown internally though - you can hide the exception (by catching it and returning null), but it could still be a performance issue if you're parsing hundreds of thousands of bits of user-provided data.

EDIT: Code for such a method:

public static Integer tryParse(String text) {
  try {
    return Integer.parseInt(text);
  } catch (NumberFormatException e) {
    return null;
  }
}

Note that I'm not sure off the top of my head what this will do if text is null. You should consider that - if it represents a bug (i.e. your code may well pass an invalid value, but should never pass null) then throwing an exception is appropriate; if it doesn't represent a bug then you should probably just return null as you would for any other invalid value.

Originally this answer used the new Integer(String) constructor; it now uses Integer.parseInt and a boxing operation; in this way small values will end up being boxed to cached Integer objects, making it more efficient in those situations.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    How does this help? The call site will require: temp=tryParse(...); if (temp!=Null) { target=temp; } else { do recovery action }; with a probable throw exception in the recovery part. In the original formulation the call site requires try target=(...).parseInt; catch (...) { do recovery action } with a trivial throw exception in the recovery being implemented by simply removing the catch clause. How does the proposed solution make this simpler to understand (it has a magic trick) or reduce the amount of code in any way? – Ira Baxter Sep 28 '09 at 09:53
  • 16
    It's generally cleaner to code to check for `null` references than it is to handle exceptions on a regular basis. – Adam Maras Sep 28 '09 at 09:55
  • It's even cleaner to avoid passing nulls as values but instead somehow indicate that en error has occured; exceptions shouldn't be used for flow control. – Esko Sep 28 '09 at 11:49
  • You should use Integer's factory method valueOf(String s). – Steve Kuo Sep 28 '09 at 17:10
  • 2
    @Steve Kuo: Why? Where's the benefit? They both create a new Integer each time? If anything, I'm tempted to use Integer.parseInt and let autoboxing take care of it, to take advantage of the cache for small values. – Jon Skeet Sep 28 '09 at 18:33
  • @Jon, Yeah like c# has TryParse which I believe doesn't throw an exception right? Wonder if there are some tricks high perf. java apps use? – codecompleting Dec 05 '11 at 18:30
  • @JonSkeet Integer.valueOf not allways instantiate a new object [posted on] (http://tech.puredanger.com/2007/02/01/valueof/) – Omar Hrynkiewicz May 28 '15 at 14:13
  • @OmarHrynkiewicz: Actually, the docs of `Integer.valueOf(String)` suggest that that *could* always return a new `Integer`. (Your link refers to `valueOf(int)`.) I've changed the answer to use `Integer.parseInt` and autoboxing instead, which is guaranteed to use the cache. – Jon Skeet May 28 '15 at 21:06
  • Good thing there is `Optional` today ... you can return Optional. I hope some JDK utilities start giving optionals instead of exceptions soon. – Vlasec Dec 17 '16 at 15:06
  • 1
    @Vlasec And not just Optional, but specialized versions for primitives, like OptionalInt. – Joshua Taylor Jul 19 '18 at 03:38
  • "It's generally cleaner to code to check for null references than it is to handle exceptions on a regular basis." I would disagree on principle. The C/C++ programming paradigm involves more null checks while the Java paradigm involves more exceptions. Both are valid approaches and both have smart developers who swear by their approach. If you want to be flexible, generally use the C++ approach when you can get good behavior from bad input and use the Java approach when you are doing 100 validations and any one of them failing would mean you need to start over from the beginning. – sf_jeff Aug 23 '18 at 16:20
  • @sf_jeff: IMO, in idiomatic Java (and C#) you catch exceptions that you can't easily predict. Exceptions are *also* used for programming errors, e.g. passing in invalid inputs etc - but those exceptions shouldn't be "handled" so much as avoided. Catching NullPointerException is *not* idiomatic Java anywhere I've worked (and usually wouldn't get through code review). IIRC, Josh Bloch talks about this reasonably extensively in Effective Java. – Jon Skeet Aug 23 '18 at 18:53
  • @Jon Skeet - A null check doesn't have to do with catching NullPointerExceptions. A null check occurs when your function tries to return an object and the object being null is used as a signal that the activity failed. If an exception were used, it wouldn't be a nullpointer exception, but would instead point to the root cause of the issue. In Java, it is idiomatic to catch errors sometimes that you *can* easily predict. It is not hard to find these in the Java library. Eg. NumberFormatException, ParseException, etc. As I said, there are smart people who use both approaches. – sf_jeff Aug 28 '18 at 23:08
  • @sf_jeff: Apologies for misunderstanding your initial point. But I think we'll have to agree to disagree at this point. It's not just "one is idiomatic Java, the other is idiomatic C++". – Jon Skeet Aug 29 '18 at 05:27
39

What behaviour do you expect when it's not a number?

If, for example, you often have a default value to use when the input is not a number, then a method such as this could be useful:

public static int parseWithDefault(String number, int defaultVal) {
  try {
    return Integer.parseInt(number);
  } catch (NumberFormatException e) {
    return defaultVal;
  }
}

Similar methods can be written for different default behaviour when the input can't be parsed.

Community
  • 1
  • 1
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
35

In some cases you should handle parsing errors as fail-fast situations, but in others cases, such as application configuration, I prefer to handle missing input with default values using Apache Commons Lang 3 NumberUtils.

int port = NumberUtils.toInt(properties.getProperty("port"), 8080);
Bryan W. Wagner
  • 867
  • 1
  • 12
  • 13
18

To avoid handling exceptions use a regular expression to make sure you have all digits first:

//Checking for Regular expression that matches digits
if(value.matches("\\d+")) {
     Integer.parseInt(value);
}
BharathRao
  • 1,846
  • 1
  • 18
  • 28
Daddyboy
  • 1,412
  • 13
  • 19
  • thank you for your answer. i read through most of the answers on this page, i personally had written the try/catch solution. however here's my issue, albeit small, with that solution. most IDEs will choke with analysing the flow of your code when you have a try/catch inside a loop. that's why a solution without the try/catch was what i needed. – victor n. Mar 02 '14 at 03:58
  • 7
    Be careful. The regex with match an integer starting with 0 which will then throw a NumberFormatException. Try this ^(?:[1-9]\d*|0)$ from http://stackoverflow.com/questions/12018479/javascript-regex-for-integer-only-not-to-start-with-0-but-allow-0 – Goose Oct 31 '14 at 11:10
  • 8
    This particular regex wouldn't handle negative numbers. – Brad Cupit Oct 06 '16 at 01:45
  • 9
    also this doesn't cover number ranges that is out of integer bounds – Mohammad Yahia Apr 10 '17 at 09:03
15

There is Ints.tryParse() in Guava. It doesn't throw exception on non-numeric string, however it does throw exception on null string.

Deekshith
  • 1,544
  • 2
  • 14
  • 15
husayt
  • 14,553
  • 8
  • 53
  • 81
4

May be you can use something like this:

public class Test {
public interface Option<T> {
    T get();

    T getOrElse(T def);

    boolean hasValue();
}

final static class Some<T> implements Option<T> {

    private final T value;

    public Some(T value) {
        this.value = value;
    }

    @Override
    public T get() {
        return value;
    }

    @Override
    public T getOrElse(T def) {
        return value;
    }

    @Override
    public boolean hasValue() {
        return true;
    }
}

final static class None<T> implements Option<T> {

    @Override
    public T get() {
        throw new UnsupportedOperationException();
    }

    @Override
    public T getOrElse(T def) {
        return def;
    }

    @Override
    public boolean hasValue() {
        return false;
    }

}

public static Option<Integer> parseInt(String s) {
    Option<Integer> result = new None<Integer>();
    try {
        Integer value = Integer.parseInt(s);
        result = new Some<Integer>(value);
    } catch (NumberFormatException e) {
    }
    return result;
}

}
Lal
  • 14,726
  • 4
  • 45
  • 70
Nikolay Ivanov
  • 8,897
  • 3
  • 31
  • 34
4

After reading the answers to the question I think encapsulating or wrapping the parseInt method is not necessary, maybe even not a good idea.

You could return 'null' as Jon suggested, but that's more or less replacing a try/catch construct by a null-check. There's just a slight difference on the behaviour if you 'forget' error handling: if you don't catch the exception, there's no assignment and the left hand side variable keeps it old value. If you don't test for null, you'll probably get hit by the JVM (NPE).

yawn's suggestion looks more elegant to me, because I do not like returning null to signal some errors or exceptional states. Now you have to check referential equality with a predefined object, that indicates a problem. But, as others argue, if again you 'forget' to check and a String is unparsable, the program continous with the wrapped int inside your 'ERROR' or 'NULL' object.

Nikolay's solution is even more object orientated and will work with parseXXX methods from other wrapper classes aswell. But in the end, he just replaced the NumberFormatException by an OperationNotSupported exception - again you need a try/catch to handle unparsable inputs.

So, its my conclusion to not encapsulate the plain parseInt method. I'd only encapsulate if I could add some (application depended) error handling as well.

Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
2

You could also replicate the C++ behaviour that you want very simply

public static boolean parseInt(String str, int[] byRef) {
    if(byRef==null) return false;
    try {
       byRef[0] = Integer.parseInt(prop);
       return true;
    } catch (NumberFormatException ex) {
       return false;
    }
}

You would use the method like so:

int[] byRef = new int[1];
boolean result = parseInt("123",byRef);

After that the variable result it's true if everything went allright and byRef[0] contains the parsed value.

Personally, I would stick to catching the exception.

2

I know that this is quite an old question, but I was looking for a modern solution to solve that issue.

I came up with the following solution:

public static OptionalInt tryParseInt(String string) {
    try {
        return OptionalInt.of(Integer.parseInt(string));
    } catch (NumberFormatException e) {
        return OptionalInt.empty();
    }
}

Usage:

@Test
public void testTryParseIntPositive() {
    // given
    int expected = 5;
    String value = "" + expected;

    // when
    OptionalInt optionalInt = tryParseInt(value);

    // then
    Assert.assertTrue(optionalInt.isPresent());
    Assert.assertEquals(expected, optionalInt.getAsInt());
}

@Test
public void testTryParseIntNegative() {
    // given
    int expected = 5;
    String value = "x" + expected;

    // when
    OptionalInt optionalInt = tryParseInt(value);

    // then
    Assert.assertTrue(optionalInt.isEmpty());
}
Andi
  • 21
  • 1
1

My Java is a little rusty, but let me see if I can point you in the right direction:

public class Converter {

    public static Integer parseInt(String str) {
        Integer n = null;

        try {
            n = new Integer(Integer.tryParse(str));
        } catch (NumberFormatException ex) {
            // leave n null, the string is invalid
        }

        return n;
    }

}

If your return value is null, you have a bad value. Otherwise, you have a valid Integer.

Adam Maras
  • 26,269
  • 6
  • 65
  • 91
  • The OP wants the conversion result (as a reference) plus an indication that the conversion was successful (or not). – yawn Sep 28 '09 at 09:29
  • 1
    @yawn: And a null reference gives exactly that indication. – Jon Skeet Sep 28 '09 at 09:33
  • @John Skeet: correct but I read his intent differently. He wrote something like using an intermediate object to differentiate between success/failure + value. Coming from a C++ background I figured if he wanted to use null (instead of an object) he would not have asked the question in the first place. – yawn Sep 28 '09 at 09:36
  • There's a major difference between "value" and "object". A null reference is a clean value, but not an object. – Jon Skeet Sep 28 '09 at 10:09
  • 1. There's no `Integer.tryParse` in the standard Java `Integer` class. 2. Doing `new Integer` is unnecessary (and recommended against) as Java does boxing and unboxing automatically. _Your Java is not just a little rusty, it's very rusty._ – ADTC Dec 12 '17 at 19:02
1

The answer given by Jon Skeet is fine, but I don't like giving back a null Integer object. I find this confusing to use. Since Java 8 there is a better option (in my opinion), using the OptionalInt:

public static OptionalInt tryParse(String value) {
 try {
     return OptionalInt.of(Integer.parseInt(value));
  } catch (NumberFormatException e) {
     return OptionalInt.empty();
  }
}

This makes it explicit that you have to handle the case where no value is available. I would prefer if this kind of function would be added to the java library in the future, but I don't know if that will ever happen.

Marc
  • 3,550
  • 22
  • 28
1

What about forking the parseInt method?

It's easy, just copy-paste the contents to a new utility that returns Integer or Optional<Integer> and replace throws with returns. It seems there are no exceptions in the underlying code, but better check.

By skipping the whole exception handling stuff, you can save some time on invalid inputs. And the method is there since JDK 1.0, so it is not likely you will have to do much to keep it up-to-date.

Vlasec
  • 5,500
  • 3
  • 27
  • 30
1

If you're using Java 8 or up, you can use a library I just released: https://github.com/robtimus/try-parse. It has support for int, long and boolean that doesn't rely on catching exceptions. Unlike Guava's Ints.tryParse it returns OptionalInt / OptionalLong / Optional, much like in https://stackoverflow.com/a/38451745/1180351 but more efficient.

Rob Spoor
  • 6,186
  • 1
  • 19
  • 20
1

Maybe someone is looking for a more generic approach, since Java 8 there is the Package java.util.function that allows to define Supplier Functions. You could have a function that takes a supplier and a default value as follows:

public static <T> T tryGetOrDefault(Supplier<T> supplier, T defaultValue) {
    try {
        return supplier.get();
    } catch (Exception e) {
        return defaultValue;
    }
}

With this function, you can execute any parsing method or even other methods that could throw an Exception while ensuring that no Exception can ever be thrown:

Integer i = tryGetOrDefault(() -> Integer.parseInt(stringValue), 0);
Long l = tryGetOrDefault(() -> Long.parseLong(stringValue), 0l);
Double d = tryGetOrDefault(() -> Double.parseDouble(stringValue), 0d);
A. Markóczy
  • 673
  • 7
  • 15
0

I would suggest you consider a method like

 IntegerUtilities.isValidInteger(String s)

which you then implement as you see fit. If you want the result carried back - perhaps because you use Integer.parseInt() anyway - you can use the array trick.

 IntegerUtilities.isValidInteger(String s, int[] result)

where you set result[0] to the integer value found in the process.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
0

This is somewhat similar to Nikolay's solution:

 private static class Box<T> {
  T me;
  public Box() {}
  public T get() { return me; }
  public void set(T fromParse) { me = fromParse; }
 }

 private interface Parser<T> {
  public void setExclusion(String regex);
  public boolean isExcluded(String s);
  public T parse(String s);
 }

 public static <T> boolean parser(Box<T> ref, Parser<T> p, String toParse) {
  if (!p.isExcluded(toParse)) {
   ref.set(p.parse(toParse));
   return true;
  } else return false;
 }

 public static void main(String args[]) {
  Box<Integer> a = new Box<Integer>();
  Parser<Integer> intParser = new Parser<Integer>() {
   String myExclusion;
   public void setExclusion(String regex) {
    myExclusion = regex;
   }
   public boolean isExcluded(String s) {
    return s.matches(myExclusion);
   }
   public Integer parse(String s) {
    return new Integer(s);
   }
  };
  intParser.setExclusion("\\D+");
  if (parser(a,intParser,"123")) System.out.println(a.get());
  if (!parser(a,intParser,"abc")) System.out.println("didn't parse "+a.get());
 }

The main method demos the code. Another way to implement the Parser interface would obviously be to just set "\D+" from construction, and have the methods do nothing.

Carl
  • 7,538
  • 1
  • 40
  • 64
0

To avoid an exception, you can use Java's Format.parseObject method. The code below is basically a simplified version of Apache Common's IntegerValidator class.

public static boolean tryParse(String s, int[] result)
{
    NumberFormat format = NumberFormat.getIntegerInstance();
    ParsePosition position = new ParsePosition(0);
    Object parsedValue = format.parseObject(s, position);

    if (position.getErrorIndex() > -1)
    {
        return false;
    }

    if (position.getIndex() < s.length())
    {
        return false;
    }

    result[0] = ((Long) parsedValue).intValue();
    return true;
}

You can either use AtomicInteger or the int[] array trick depending upon your preference.

Here is my test that uses it -

int[] i = new int[1];
Assert.assertTrue(IntUtils.tryParse("123", i));
Assert.assertEquals(123, i[0]);
Josh Unger
  • 6,717
  • 6
  • 33
  • 55
0

I was also having the same problem. This is a method I wrote to ask the user for an input and not accept the input unless its an integer. Please note that I am a beginner so if the code is not working as expected, blame my inexperience !

private int numberValue(String value, boolean val) throws IOException {
    //prints the value passed by the code implementer
    System.out.println(value);
    //returns 0 is val is passed as false
    Object num = 0;
    while (val) {
        num = br.readLine();
        try {
            Integer numVal = Integer.parseInt((String) num);
            if (numVal instanceof Integer) {
                val = false;
                num = numVal;
            }
        } catch (Exception e) {
            System.out.println("Error. Please input a valid number :-");
        }
    }
    return ((Integer) num).intValue();
}
Abhinav Mathur
  • 138
  • 1
  • 10
  • 1
    Do not use System.out.println (is a bad practice). The Problem with using it, is that your program will wait until the println has finished. The better approach is to use a logging framework. – Omar Hrynkiewicz May 28 '15 at 13:43
0

This is an answer to question 8391979, "Does java have a int.tryparse that doesn't throw an exception for bad data? [duplicate]" which is closed and linked to this question.

Edit 2016 08 17: Added ltrimZeroes methods and called them in tryParse(). Without leading zeroes in numberString may give false results (see comments in code). There is now also public static String ltrimZeroes(String numberString) method which works for positive and negative "numbers"(END Edit)

Below you find a rudimentary Wrapper (boxing) class for int with an highly speed optimized tryParse() method (similar as in C#) which parses the string itself and is a little bit faster than Integer.parseInt(String s) from Java:

public class IntBoxSimple {
    // IntBoxSimple - Rudimentary class to implement a C#-like tryParse() method for int
    // A full blown IntBox class implementation can be found in my Github project
    // Copyright (c) 2016, Peter Sulzer, Fürth
    // Program is published under the GNU General Public License (GPL) Version 1 or newer

    protected int _n; // this "boxes" the int value

    // BEGIN The following statements are only executed at the
    // first instantiation of an IntBox (i. e. only once) or
    // already compiled into the code at compile time:
    public static final int MAX_INT_LEN =
            String.valueOf(Integer.MAX_VALUE).length();
    public static final int MIN_INT_LEN =
            String.valueOf(Integer.MIN_VALUE).length();
    public static final int MAX_INT_LASTDEC =
            Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(1));
    public static final int MAX_INT_FIRSTDIGIT =
            Integer.parseInt(String.valueOf(Integer.MAX_VALUE).substring(0, 1));
    public static final int MIN_INT_LASTDEC =
            -Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(2));
    public static final int MIN_INT_FIRSTDIGIT =
            Integer.parseInt(String.valueOf(Integer.MIN_VALUE).substring(1,2));
    // END The following statements...

    // ltrimZeroes() methods added 2016 08 16 (are required by tryParse() methods)
    public static String ltrimZeroes(String s) {
        if (s.charAt(0) == '-')
            return ltrimZeroesNegative(s);
        else
            return ltrimZeroesPositive(s);
    }
    protected static String ltrimZeroesNegative(String s) {
        int i=1;
        for ( ; s.charAt(i) == '0'; i++);
        return ("-"+s.substring(i));
    }
    protected static String ltrimZeroesPositive(String s) {
        int i=0;
        for ( ; s.charAt(i) == '0'; i++);
        return (s.substring(i));
    }

    public static boolean tryParse(String s,IntBoxSimple intBox) {
        if (intBox == null)
            // intBoxSimple=new IntBoxSimple(); // This doesn't work, as
            // intBoxSimple itself is passed by value and cannot changed
            // for the caller. I. e. "out"-arguments of C# cannot be simulated in Java.
            return false; // so we simply return false
        s=s.trim(); // leading and trailing whitespace is allowed for String s
        int len=s.length();
        int rslt=0, d, dfirst=0, i, j;
        char c=s.charAt(0);
        if (c == '-') {
            if (len > MIN_INT_LEN) { // corrected (added) 2016 08 17
                s = ltrimZeroesNegative(s);
                len = s.length();
            }
            if (len >= MIN_INT_LEN) {
                c = s.charAt(1);
                if (!Character.isDigit(c))
                    return false;
                dfirst = c-'0';
                if (len > MIN_INT_LEN || dfirst > MIN_INT_FIRSTDIGIT)
                    return false;
            }
            for (i = len - 1, j = 1; i >= 2; --i, j *= 10) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt -= (c-'0')*j;
            }
            if (len < MIN_INT_LEN) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt -= (c-'0')*j;
            } else {
                if (dfirst >= MIN_INT_FIRSTDIGIT && rslt < MIN_INT_LASTDEC)
                    return false;
                rslt -= dfirst * j;
            }
        } else {
            if (len > MAX_INT_LEN) { // corrected (added) 2016 08 16
                s = ltrimZeroesPositive(s);
                len=s.length();
            }
            if (len >= MAX_INT_LEN) {
                c = s.charAt(0);
                if (!Character.isDigit(c))
                    return false;
                dfirst = c-'0';
                if (len > MAX_INT_LEN || dfirst > MAX_INT_FIRSTDIGIT)
                    return false;
            }
            for (i = len - 1, j = 1; i >= 1; --i, j *= 10) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt += (c-'0')*j;
            }
            if (len < MAX_INT_LEN) {
                c = s.charAt(i);
                if (!Character.isDigit(c))
                    return false;
                rslt += (c-'0')*j;
            }
            if (dfirst >= MAX_INT_FIRSTDIGIT && rslt > MAX_INT_LASTDEC)
                return false;
            rslt += dfirst*j;
        }
        intBox._n=rslt;
        return true;
    }

    // Get the value stored in an IntBoxSimple:
    public int get_n() {
        return _n;
    }
    public int v() { // alternative shorter version, v for "value"
        return _n;
    }
    // Make objects of IntBoxSimple (needed as constructors are not public):
    public static IntBoxSimple makeIntBoxSimple() {
        return new IntBoxSimple();
    }
    public static IntBoxSimple makeIntBoxSimple(int integerNumber) {
        return new IntBoxSimple(integerNumber);
    }

    // constructors are not public(!=:
    protected IntBoxSimple() {} {
        _n=0; // default value an IntBoxSimple holds
    }
    protected IntBoxSimple(int integerNumber) {
        _n=integerNumber;
    }
}

Test/example program for class IntBoxSimple:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class IntBoxSimpleTest {
    public static void main (String args[]) {
        IntBoxSimple ibs = IntBoxSimple.makeIntBoxSimple();
        String in = null;
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        do {
            System.out.printf(
                    "Enter an integer number in the range %d to %d:%n",
                        Integer.MIN_VALUE, Integer.MAX_VALUE);
            try { in = br.readLine(); } catch (IOException ex) {}
        } while(! IntBoxSimple.tryParse(in, ibs));
        System.out.printf("The number you have entered was: %d%n", ibs.v());
    }
}
Peter Sulzer
  • 43
  • 1
  • 10
0

Try with regular expression and default parameters argument

public static int parseIntWithDefault(String str, int defaultInt) {
    return str.matches("-?\\d+") ? Integer.parseInt(str) : defaultInt;
}


int testId = parseIntWithDefault("1001", 0);
System.out.print(testId); // 1001

int testId = parseIntWithDefault("test1001", 0);
System.out.print(testId); // 1001

int testId = parseIntWithDefault("-1001", 0);
System.out.print(testId); // -1001

int testId = parseIntWithDefault("test", 0);
System.out.print(testId); // 0

if you're using apache.commons.lang3 then by using NumberUtils:

int testId = NumberUtils.toInt("test", 0);
System.out.print(testId); // 0
Krunal
  • 77,632
  • 48
  • 245
  • 261
0

I would like to throw in another proposal that works if one specifically requests integers: Simply use long and use Long.MIN_VALUE for error cases. This is similar to the approach that is used for chars in Reader where Reader.read() returns an integer in the range of a char or -1 if the reader is empty.

For Float and Double, NaN can be used in a similar way.

public static long parseInteger(String s) {
    try {
        return Integer.parseInt(s);
    } catch (NumberFormatException e) {
        return Long.MIN_VALUE;
    }
}


// ...
long l = parseInteger("ABC");
if (l == Long.MIN_VALUE) {
    // ... error
} else {
    int i = (int) l;
}
Searles
  • 1,447
  • 1
  • 11
  • 26
0

Considering existing answers, I've copy-pasted and enhanced source code of Integer.parseInt to do the job, and my solution

  • does not use potentially slow try-catch (unlike Lang 3 NumberUtils),
  • does not use regexps which can't catch too big numbers,
  • avoids boxing (unlike Guava's Ints.tryParse()),
  • does not require any allocations (unlike int[], Box, OptionalInt),
  • accepts any CharSequence or a part of it instead of a whole String,
  • can use any radix which Integer.parseInt can, i.e. [2,36],
  • does not depend on any libraries.

The only downside is that there's no difference between toIntOfDefault("-1", -1) and toIntOrDefault("oops", -1).

public static int toIntOrDefault(CharSequence s, int def) {
    return toIntOrDefault0(s, 0, s.length(), 10, def);
}
public static int toIntOrDefault(CharSequence s, int def, int radix) {
    radixCheck(radix);
    return toIntOrDefault0(s, 0, s.length(), radix, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int def) {
    boundsCheck(start, endExclusive, s.length());
    return toIntOrDefault0(s, start, endExclusive, 10, def);
}
public static int toIntOrDefault(CharSequence s, int start, int endExclusive, int radix, int def) {
    radixCheck(radix);
    boundsCheck(start, endExclusive, s.length());
    return toIntOrDefault0(s, start, endExclusive, radix, def);
}
private static int toIntOrDefault0(CharSequence s, int start, int endExclusive, int radix, int def) {
    if (start == endExclusive) return def; // empty

    boolean negative = false;
    int limit = -Integer.MAX_VALUE;

    char firstChar = s.charAt(start);
    if (firstChar < '0') { // Possible leading "+" or "-"
        if (firstChar == '-') {
            negative = true;
            limit = Integer.MIN_VALUE;
        } else if (firstChar != '+') {
            return def;
        }

        start++;
        // Cannot have lone "+" or "-"
        if (start == endExclusive) return def;
    }
    int multmin = limit / radix;
    int result = 0;
    while (start < endExclusive) {
        // Accumulating negatively avoids surprises near MAX_VALUE
        int digit = Character.digit(s.charAt(start++), radix);
        if (digit < 0 || result < multmin) return def;
        result *= radix;
        if (result < limit + digit) return def;
        result -= digit;
    }
    return negative ? result : -result;
}
private static void radixCheck(int radix) {
    if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX)
        throw new NumberFormatException(
                "radix=" + radix + " ∉ [" +  Character.MIN_RADIX + "," + Character.MAX_RADIX + "]");
}
private static void boundsCheck(int start, int endExclusive, int len) {
    if (start < 0 || start > len || start > endExclusive)
        throw new IndexOutOfBoundsException("start=" + start + " ∉ [0, min(" + len + ", " + endExclusive + ")]");
    if (endExclusive > len)
        throw new IndexOutOfBoundsException("endExclusive=" + endExclusive + " > s.length=" + len);
}
Miha_x64
  • 5,973
  • 1
  • 41
  • 63
0

I've been using a helper class that contains a static Queue of parsed values, and I find it to look quite clean. This would be the helper class could look like:

public static class Parsing {
    // Could optimise with specific queues for primitive types
    // and also using a circular queue, instead of LinkedList
    private static final Queue<Number> QUEUE = new LinkedList<Number>();

    public static boolean parseInt(String value) {
        // Could implement custom integer parsing here, which does not throw
        try {
            QUEUE.offer(Integer.parseInt(value));
            return true;
        }
        catch (Throwable ignored) {
            return false;
        }
    }
    public static int getInt() {
        return QUEUE.remove().intValue(); // user's fault if this throws :)
    }
}

And then in code, you use it like this:

public Vector3 parseVector(String content) {
    if (Parsing.parseInt(content)) {
        return new Vector3(Parsing.getInt());
    }
    else {
        String[] parts = content.split(",");
        if (Parsing.parseInt(parts[0]) && Parsing.parseInt(parts[1]) && Parsing.parseInt(parts[2])) {
            // the queue ensures these are in the same order they are parsed
            return new Vector3(Parsing.getInt(), Parsing.getInt(), Parsing.getInt());
        }
        else {
            throw new RuntimeException("Invalid Vector3");
        }
    }
}

The only problem with this, is that if you use multiple calls like i did above, but maybe the last one fails, then you'd have to roll back or clear the queue

Edit: You could remove the above problem and include some thread safely, by making the class non-static and, maybe for slightly cleaner code, make the class implement AutoCloseable so that you could do something like this:

public Vector3 parseVector(String content) {
    try (Parsing parser = Parsing.of()) {
        if (parser.parseInt(content)) {
            return new Vector3(parser.getInt());
        }
        else {
            String[] parts = content.split(",");
            if (parser.parseInt(parts[0]) && parser.parseInt(parts[1]) && parser.parseInt(parts[2])) {
                // the queue ensures these are in the same order they are parsed
                return new Vector3(parser.getInt(), parser.getInt(), parser.getInt());
            }
            else {
                throw new RuntimeException("Invalid Vector3");
            }
        }   
    }
}
REghZY
  • 69
  • 1
  • 7
0

They way I handle this problem is recursively. For example when reading data from the console:

Java.util.Scanner keyboard = new Java.util.Scanner(System.in);

public int GetMyInt(){
    int ret;
    System.out.print("Give me an Int: ");
    try{
        ret = Integer.parseInt(keyboard.NextLine());

    }
    catch(Exception e){
        System.out.println("\nThere was an error try again.\n");
        ret = GetMyInt();
    }
    return ret;
}
Boboman
  • 431
  • 5
  • 8
-1

You can use a Null-Object like so:

public class Convert {

    @SuppressWarnings({"UnnecessaryBoxing"})
    public static final Integer NULL = new Integer(0);

    public static Integer convert(String integer) {

        try {
            return Integer.valueOf(integer);
        } catch (NumberFormatException e) {
            return NULL;
        }

    }

    public static void main(String[] args) {

        Integer a = convert("123");
        System.out.println("a.equals(123) = " + a.equals(123));
        System.out.println("a == NULL " + (a == NULL));

        Integer b = convert("onetwothree");
        System.out.println("b.equals(123) = " + b.equals(123));
        System.out.println("b == NULL " + (b == NULL));

        Integer c = convert("0");
        System.out.println("equals(0) = " + c.equals(0));
        System.out.println("c == NULL " + (c == NULL));

    }

}

The result of main in this example is:

a.equals(123) = true
a == NULL false
b.equals(123) = false
b == NULL true
c.equals(0) = true
c == NULL false

This way you can always test for failed conversion but still work with the results as Integer instances. You might also want to tweak the number NULL represents (≠ 0).

yawn
  • 8,014
  • 7
  • 29
  • 34
  • What if 'String integer' is the String literal "0"? You'll never know if there was invalid input. – Bart Kiers Sep 28 '09 at 09:19
  • I guess that depends on whether the == operator for two Integers compares values or references. If it compares values, the problem exists. If it compares references, it would work in a way equivalent to my answer. – Adam Maras Sep 28 '09 at 09:21
  • Why the downvote? My answer is correct and offers the advantage (over null) that you always deal with a valid instance of Integer (instead of null) relieving you of having to deal with NPEs. – yawn Sep 28 '09 at 09:25
  • Distinguishing null from a real integer is *useful* though. You *should* be testing the result for nullity, to know whether the parse succeeded or not. Hiding that behind and otherwise usable object is a recipe for problems, IMO. – Jon Skeet Sep 28 '09 at 09:32
  • More downvotes - interesting! Since /me being new to SO and all could one of the voters explain to me the why? – yawn Sep 28 '09 at 09:33
  • Jon's got a point about the usefulness of your predefined `NULL` value. Here's an example: if he uses your solution and forgets to check for equality to your `NULL` object, his program will work flawlessly, but erroneously interpret the parsed value as 0. With my solution, if he forgets to check for a `null` reference, his program will (correctly) crash at runtime, reminding him that he needs to insert the proper behavior for the results of an invalid parsing. – Adam Maras Sep 28 '09 at 09:37
  • @Adam: true! But the OP *did* ask for a solution returning a valid instance, did he not? – yawn Sep 28 '09 at 09:42
  • No, he asked for "a clean value in order to show that the convertion went wrong," and `null` is a clean value when you're using an `Integer` return type. – Adam Maras Sep 28 '09 at 09:45
  • @Adam: I read/interpreted it differently. Still I don't get -2 - it's not like the answer was a troll post/spam whatever. @Jon: Please delete the entire answer if possible. -2 looks like it's suggesting something blatantly wrong/stupid which it clearly does not. – yawn Sep 28 '09 at 10:32
-1

You shouldn't use Exceptions to validate your values.

For single character there is a simple solution:

Character.isDigit()

For longer values it's better to use some utils. NumberUtils provided by Apache would work perfectly here:

NumberUtils.isNumber()

Please check https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/math/NumberUtils.html

  • «Checks whether the String a valid Java number. Valid numbers include hexadecimal marked with the 0x qualifier, scientific notation and numbers marked with a type qualifier (e.g. 123L).» This is not what can be parsed with `Integer.parseInt`. – Miha_x64 Apr 16 '20 at 23:04
  • Commons provides `NumberUtils.toInt` [https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/math/NumberUtils.html](https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/math/NumberUtils.html#toInt-java.lang.String-) – Ragnar Feb 03 '22 at 11:29
-1

You could roll your own, but it's just as easy to use commons lang's StringUtils.isNumeric() method. It uses Character.isDigit() to iterate over each character in the String.

James Bassett
  • 9,458
  • 4
  • 35
  • 68
  • Then it would not work if the digit contains a too large number. Integer.parseInt throws an exception for numbers larger than Integer.MAX_VALUE (same of course for the negative side). – Searles Feb 15 '18 at 14:36
  • Beware: `String.isNumeric` will give `true` for Arabic / Persian numbers. From JavaDoc: `StringUtils.isNumeric("१२३") = true` – izogfif Jul 29 '21 at 04:11