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)