好的方法来封装Integer.parseInt()

我有一个项目,我们经常使用Integer.parseInt()将一个string转换为一个int。 当出现错误(例如, String不是数字,而是字母a ,或其他)时,此方法将引发exception。 但是,如果我必须在任何地方处理我的代码中的exception,这很快就会变得非常难看。 我想把这个方法,但是,我不知道如何返回一个干净的值,以显示转换出错。

在C ++中,我可以创build一个接受int指针的方法,并让方法本身返回true或false。 不过,据我所知,这在Java中是不可能的。 我也可以创build一个包含true / falsevariables和转换后的值的对象,但这看起来并不理想。 同样的事情为全球价值,这可能会给我multithreading的麻烦。

那么有没有一个干净的方法来做到这一点?

你可以返回一个Integer而不是int ,在parsing失败时返回null

这是一个耻辱Java没有提供这样做的方式,但没有在内部抛出exception – 你可以隐藏exception(通过捕获和返回null),但它仍然可能是一个性能问题,如果你parsing数百数千位用户提供的数据。

编辑:这种方法的代码:

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

请注意,我不确定如果text为空,这将做什么。 你应该考虑 – 如果它代表一个错误(即你的代码可能传递一个无效的值,但不应该传递null),那么抛出一个exception是合适的; 如果它不代表一个bug,那么你可能应该像其他任何无效值一样返回null。

最初这个答案使用new Integer(String)构造函数; 它现在使用Integer.parseInt和一个装箱操作; 通过这种方式,小值最终会被caching到caching的Integer对象中,从而在这些情况下更有效率。

当它不是一个数字时,你期望什么样的行为?

例如,如果您在input不是数字时经常使用默认值,那么像这样的方法可能是有用的:

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

当input不能被parsing时,可以针对不同的默认行为编写类似的方法。

在某些情况下,您应该将parsing错误作为快速失败的情况处理,但在其他情况下(例如应用程序configuration),我更愿意使用Apache Commons Lang 3 NumberUtils处理缺less的input。

 int port = NumberUtils.toInt(properties.getProperty("port"), 8080); 

为避免处理exception,请使用正则expression式来确保您首先有全部数字:

 if(value.matches("\\d+") { Integer.parseInt(value); } 

在Guava中有Ints.tryParse() 。 它不会在非数字string上引发exception,但它会在空string上引发exception。

读过这个问题的答案后,我认为封装或包装parseInt方法是没有必要的,甚至不是一个好主意。

你可以像Jon所说的那样返回'null',但是这或多或less地用一个空检查replacetry / catch结构。 如果您“忘记”error handling,则行为只有轻微的差别:如果您没有发现exception,则不会分配任何东西,而左侧variables则会保留旧值。 如果你不testingnull,你可能会被JVM(NPE)击中。

哈欠的build议看起来更优雅,因为我不喜欢返回null来表示一些错误或exception状态。 现在你必须检查一个预定义的对象的引用相等性,这表明了一个问题。 但是,正如其他人所认为的,如果再次忘记检查并且string是不可parsing的,那么程序将在“ERROR”或“NULL”对象中连续包装int。

Nikolay的解决scheme更加面向对象,并且可以与其他包装类的parseXXX方法一起工作。 但最后,他只是用一个OperationNotSupportedexception来replaceNumberFormatException – 同样你需要一个try / catch来处理unparsableinput。

所以,我的结论是不封装简单的parseInt方法。 我只能封装,如果我可以添加一些(应用程序依赖)error handling以及。

可能你可以使用这样的东西:

 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; } } 

你也可以简单地复制你想要的C ++行为

 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; } } 

你会用这样的方法:

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

之后,variablesresult是真的,如果一切顺利,并通过byRef[0]包含parsing的值。

就我个人而言,我会坚持抓住例外。

我的Java有点生疏,但让我看看我能否指出你正确的方向:

 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; } } 

如果您的返回值为null ,那么您的值很差。 否则,你有一个有效的Integer

怎么样派生parseInt方法?

这很容易,只需将内容复制粘贴到一个新的实用程序,该实用程序返回IntegerOptional<Integer>并用返回值replace。 在底层代码中似乎没有例外, 但更好的检查

通过跳过整个exception处理的东西,你可以节省一些无效input的时间。 从JDK 1.0开始,这个方法就在那里,所以你不可能为了保持最新而做很多事情。

你可以像这样使用一个空对象:

 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)); } } 

在这个例子中主要的结果是:

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

这样你总是可以testing失败的转换,但仍然可以用Integer实例来处理结果。 你可能也想调整NULL代表的数字(≠0)。

我build议你考虑一个像

  IntegerUtilities.isValidInteger(String s) 

然后按照你的意思执行。 如果你想让结果反过来 – 也许是因为你使用了Integer.parseInt() – 你可以使用数组技巧。

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

在那里你把result [0]设置为在进程中find的整数值。

这有点类似于尼古拉的解决scheme:

  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()); } 

主要方法演示代码。 实现parsing器接口的另一种方式显然是从构造中设置“\ D +”,并使这些方法无效。

可以推出你自己的,但是使用commons lang的StringUtils.isNumeric() 方法也同样简单。 它使用Character.isDigit()遍历string中的每个字符。

他们处理这个问题的方式是recursion的。 例如,从控制台读取数据时:

 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; } 

为了避免出现exception,可以使用Java的Format.parseObject方法。 下面的代码基本上是Apache Common的IntegerValidator类的简化版本。

 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; } 

您可以使用AtomicIntegerint[]数组技巧,具体取决于您的偏好。

这是我的testing使用它 –

 int[] i = new int[1]; Assert.assertTrue(IntUtils.tryParse("123", i)); Assert.assertEquals(123, i[0]); 

我也有同样的问题。 这是我写的一个方法,要求用户input,不接受input,除非它是一个整数。 请注意,我是初学者,所以如果代码不能按预期工作,责怪我的经验不足!

 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(); } 

Jon Skeet给出的答案很好,但我不喜欢给出一个null Integer对象。 我觉得这个使用混乱。 由于Java 8有一个更好的select(在我看来),使用OptionalInt

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

这就明确表示你必须处理没有价值的情况。 我宁愿如果这种function将被添加到Java库,但我不知道这是否会发生。

这是对问题8391979的回答,“是否java有一个int.tryparse不会抛出坏数据exception?[重复]”,它被closures并链接到这个问题。

编辑2016 08 17:添加ltrimZeroes方法,并在tryParse()中调用它们。 numberString中没有前导零可能会导致错误的结果(请参阅代码中的注释)。 现在还有公共的静态stringltrimZeroes(String numberString)方法,它适用于正数和负数“数字”(结束编辑)

在下面,你会发现int的一个基本的Wrapper(boxing)类,它有一个高速优化的tryParse()方法(类似于C#),它parsingstring本身并比Java中的Integer.parseInt(String s)

 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 (ie 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; } } 

类IntBoxSimple的testing/示例程序:

 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()); } } 

尝试使用正则expression式和默认参数参数

 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 

如果您使用apache.commons.lang3,然后通过使用NumberUtils :

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