string到INT在Java中 – 可能坏数据,需要避免例外

看作Java没有可空types,也没有TryParse(),你如何处理inputvalidation而不抛出exception呢?

通常的方式:

String userdata = /*value from gui*/ int val; try { val = Integer.parseInt(userdata); } catch (NumberFormatException nfe) { // bad data - set to sentinel val = Integer.MIN_VALUE; } 

我可以使用正则expression式来检查它是否可parsing,但是这似乎也是一个很大的开销。

处理这种情况的最佳做法是什么?

编辑:理由:关于exception处理,有很多关于exception的讨论,一般的态度是,exception应该只用于意外情况。 不过,我认为坏的用户input是预期的,并不less见。 是的,这确实是一个学术问题。

进一步修改:

其中一些答案显示了究竟是什么问题。 你忽略被问的问题,回答另一个与它无关的问题。 问题不在于层之间的转换。 如果数字是不可parsing的,问题不是要求返回什么。 对于你所知道的,val = Integer.MIN_VALUE; 对于这个完全没有上下文代码片段的应用来说,这是正确的select。

虽然返回MIN_VALUE是有问题的,除非你确定这是正确的东西来使用你本质上用作错误代码。 不过,至less我会logging错误代码的行为。

可能也是有用的(取决于应用程序)logging错误的input,所以你可以跟踪。

我问是否有开源实用程序库有方法来parsing你的答案是肯定的!

从Apache Commons Lang你可以使用NumberUtils.toInt :

 // returns defaultValue if the string cannot be parsed. int i = org.apache.commons.lang.math.NumberUtils.toInt(s, defaultValue); 

从Google Guava中,您可以使用Ints.tryParse :

 // returns null if the string cannot be parsed // Will throw a NullPointerException if the string is null Integer i = com.google.common.primitives.Ints.tryParse(s); 

没有必要编写自己的方法来parsing数字而不抛出exception。

对于用户提供的数据,Integer.parseInt通常是错误的方法,因为它不支持国际化。 java.text包是你的(详细的)朋友。

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

你的方法有什么问题? 我不认为这样做会损害你的应用程序的性能。 这是做到这一点的正确方法。 不要过早优化

我确定它是不好的forms,但我有一个Utilities类的静态方法,像Utilities.tryParseInt(String value) ,如果该string是不可parsing返回0和Utilities.tryParseInt(String value, int defaultValue)它允许你指定一个值,如果parseInt()抛出一个exception。

我相信有时候,对错误的input返回一个已知的值是完全可以接受的。 一个非常人为的例子:你问用户的格式为YYYYMMDD的date,他们给你不好的input。 像Utilities.tryParseInt(date, 19000101)Utilities.tryParseInt(date, 29991231);可能是完全可以接受的Utilities.tryParseInt(date, 29991231); 取决于scheme的要求。

我要重申一点,就是在这篇文章的底部,

validation用户input(或者来自configuration文件等的input)的一种普遍接受的方法是在实际处理数据之前使用validation。 在大多数情况下,这是一个很好的devise方法,尽pipe它可能导致多次调用parsingalgorithm。

一旦您知道您已经正确validation了用户input, 那么parsing它并忽略,logging或转换为RuntimeException NumberFormatException是安全的。

请注意,这种方法需要你考虑你的模型分为两部分:业务模型(我们实际上关心的是以int还是floatforms存在的值)以及用户界面模型(我们真的希望允许用户放入任何他们想)。

为了将数据从用户界面模型迁移到业务模型,必须通过validation步骤(这可以逐字段地进行,但大多数情况下需要对正在configuration的整个对象进行validation) 。

如果validation失败,则向用户提供反馈,通知他们他们做错了什么,并给予修复的机会。

像JGoodies Binding和JSR 295这样的绑定库使得这种事情比听起来容易得多,而且许多Web框架提供了将用户input与实际业务模型分开的构造,仅在validation完成后才填充业务对象。

在validationconfiguration文件(其他用例在一些注释中提出)方面,指定默认值是一回事(如果没有指定某个特定的值),但是如果数据的格式不正确(某人键入“噢',而不是'零' – 或者他们从MS Word复制和所有的back-ticks有一个时髦的unicode字符),那么需要某种types的系统反馈(即使它只是通过抛出运行时exception而失败) 。

以下是我如何做到这一点:

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

然后空信号无效的数据。 如果你想要一个默认值,你可以改变它:

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

我认为最好的做法是你展示的代码。

我不会因为开销而select正则expression式。

试试org.apache.commons.lang.math.NumberUtils.createInteger(String s) 。 这帮了我很多。 有类似的方法,双打,多头等

你可以使用Integer,如果你的值不好,可以设置为null。 如果您使用的是Java 1.6,它将为您提供自动装箱/拆箱。

Java 8“无价值”的语义

在Java 8+中,我现在考虑使用RegEx进行预过滤(避免出现exception),并将结果封装在一个可选的原语中(以处理“默认”问题):

 public static OptionalInt toInt(final String input) { return input.matches("[+-]?\\d+") ? OptionalInt.of(Integer.parseInt(input)) : OptionalInt.empty(); } 

flatMap()支持

如果你想在flatMap()中使用这个,使用等效的Streamtypes:

 public static IntStream toInt(final String input) { return input.matches("[+-]?\\d+") ? IntStream.of(Integer.parseInt(input)) : IntStream.empty(); } 

然后你可以使用像:

 inputs.flapMapToInt(MyUtility::toInt); 

参考文献

基于parseInt文档的 RegEx

上面的代码是不好的,因为它是相同的如下。

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

这个例外完全被忽略。 此外,魔法令牌不好,因为用户可以通过-2147483648(Integer.MIN_VALUE)。

通用可parsing的问题是不利的。 相反,它应该与上下文有关。 您的应用程序有特定的要求。 你可以定义你的方法

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

在哪里你可以logging的要求,你可以创build定义良好,可testing的规则。

如果你可以像你说的那样预先testing(isParsable())来避免exception,那么它可能会更好 – 但是并不是所有的库都是为了这个而devise的。

我用你的伎俩,它很烂,因为我的embedded式系统上的堆栈跟踪打印,无论你是否抓住他们或不:(

exception机制是有价值的,因为它是将状态指示符与响应值组合在一起的唯一方法。 此外,状态指示器是标准化的。 如果有错误,你会得到一个exception。 这样你就不必自己想一个错误指示器。 争议并不是例外,而是使用Checked Exceptions(例如你必须捕捉或声明的)。

就我个人而言,我觉得你select了一个例外的例子是非常有价值的。 用户input错误的值是一个常见的问题,通常您需要返回给用户以获取正确的值。 如果询问用户,通常不会恢复为默认值; 这给了用户他的input很重要的印象。

如果你不想处理这个exception,就把它包装在一个RuntimeException(或派生类)中,它将允许你忽略你的代码中的exception(并且当它发生的时候杀掉你的应用程序,有时也是这样)。

关于如何处理NumberFormatexception的一些示例:在Web应用程序configuration数据中:

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

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

在networking表单中:将表单返回给用户,并提供一个有用的错误消息,并有机会进行更正。 大多数框架提供了一种标准的validation方式。

Integer.MIN_VALUE作为NumberFormatException是不好的主意。

您可以将投标添加到项目投币将此方法添加到整数

@Nullable public static Integer parseInteger(String src)…对于错误的input,它将返回null

然后在这里把你的build议链接,我们都会投票的!

PS:看看这个http://msdn.microsoft.com/en-us/library/bb397679.aspx这是多么丑陋和臃肿它可能是;

把一些if语句放在它前面。 if(null!= userdata)