Java中的True-way解决方案:解析2个字符串中的2个数字,然后返回它们的总和

And*_*lov 84 java parsing exception

相当愚蠢的问题.鉴于代码:

public static int sum(String a, String b) /* throws? WHAT? */ {
  int x = Integer.parseInt(a); // throws NumberFormatException
  int y = Integer.parseInt(b); // throws NumberFormatException
  return x + y;
}
Run Code Online (Sandbox Code Playgroud)

你能告诉它是不是很好的Java?我所说的是,NumberFormatException是一个未经检查的例外.您不必将其指定为sum()签名的一部分.此外,据我所知,未经检查的异常的想法只是表示程序的实现是不正确的,甚至更多,捕获未经检查的异常是一个坏主意,因为它就像在运行时修复坏程序.

请有人澄清是否:

  1. 我应该指定NumberFormatException为方法签名的一部分.
  2. 我应该定义自己检查的exception(BadDataException),NumberFormatException在方法内部处理并重新抛出它BadDataException.
  3. 我应该定义自己检查的异常(BadDataException),像正则表达式一样验证两个字符串,BadDataException如果它不匹配则抛出我的字符串.
  4. 你的想法?

更新:

想象一下,它不是一个开源框架,你应该出于某种原因使用它.你看看方法的签名并思考 - "好吧,它永远不会抛出".然后,有一天,你有一个例外.这是正常的吗?

更新2:

有一些评论说我sum(String, String)的设计不好.我绝对同意,但对于那些认为如果我们有好的设计就不会出现原始问题的人来说,这是一个额外的问题:

问题定义如下:您有一个数据源,其中数字存储为Strings.这个源可能是XML文件,网页,带有2个编辑框的桌面窗口,等等.

你的目标是实现采用这些2 String秒的逻辑,将它们转换为ints并显示消息框,说"总和是xxx".

无论您使用什么方法来设计/实现它,您都将拥有以下2点内部功能:

  1. 转换String为的地方int
  2. 添加2 int秒的地方

我原帖的主要问题是:

Integer.parseInt()期望传递正确的字符串.每当你传递一个错误的字符串,就意味着你的程序不正确(而不是" 你的用户是个白痴").你需要实现这段代码,其中一方面你有Integer.parseInt()和MUST语义,另一方面你需要在输入不正确的情况下做好 - 应该是语义.

简而言之:如果我只有MUST库,我该如何实现SHOULD语义.

Joh*_*erg 49

在我看来,最好尽可能地处理异常逻辑.因此我更喜欢签名

 public static int sum(int a, int b);
Run Code Online (Sandbox Code Playgroud)

使用您的方法签名,我不会改变任何东西.不管你是谁

  • 以编程方式使用不正确的值,您可以在其中验证生成器算法
  • 或者从例如用户输入发送值,在这种情况下该模块应该执行验证

因此,在这种情况下,异常处理成为文档问题.

  • 我喜欢这个.它强制用户遵循合同,并使该方法只做一件事. (4认同)
  • @Swati:我认为这是一个_example_,这是一个简单展示事物的好方法.sum方法也可以是myVeryComplicatedMethodWhichComputesPhoneNumberOfMyIdealMatchGirl(int myID,int myLifeExpectancy)... (4认同)
  • 在这里完全同意.期望两个数字的`sum`函数应该得到两个数字.你获得这些的方式与`sum`函数无关._正确地分离你的逻辑_.所以,我将此与设计问题联系起来. (3认同)

Boh*_*ian 35

这是一个很好的问题.我希望更多的人会考虑这些事情.

如果你已经通过垃圾参数,恕我直言,抛出未经检查的例外是可以接受的.

一般来说,您不应该抛出,BadDataException因为您不应该使用Exceptions来控制程序流.例外是特殊情况.你的方法的调用者可以他们调用之前知道他们的字符串是否为数字,因此传递垃圾是可以避免的,因此可以被认为是编程错误,这意味着可以抛出未经检查的异常.

关于声明throws NumberFormatException- 这没有那么有用,因为很少会注意到由于未选中NumberFormatException.但是,IDE可以使用它并提供try/catch正确的包装.一个很好的选择是使用javadoc,例如:

/**
 * Adds two string numbers
 * @param a
 * @param b
 * @return
 * @throws NumberFormatException if either of a or b is not an integer
 */
public static int sum(String a, String b) throws NumberFormatException {
    int x = Integer.parseInt(a); 
    int y = Integer.parseInt(b); 
    return x + y;
}
Run Code Online (Sandbox Code Playgroud)

编辑:
评论者提出了有效的观点.您需要考虑如何使用它以及应用程序的整体设计.

如果该方法将在所有地方使用,并且所有调用者处理问题都很重要,则将该方法声明为抛出已检查的异常(强制调用者处理问题),但是使用try/catch块使代码混乱.

另一方面,如果我们将这个方法与我们信任的数据一起使用,那么就像上面那样声明它,因为它不会爆炸并且你避免了基本上不必要的try/catch块的代码混乱.

  • 问题在于,未经检查的异常通常会被忽略,并且可能会渗透到您的调用堆栈中,从而严重破坏应用程序中不知道底层内容的部分内容.问题实际上是哪一行代码应该检查输入是否有效. (6认同)
  • 要*"你的方法的来电者可以在他们称之前知道他们的字符串是否是数字,所以传递垃圾是可以避免的"*:这不是真的.验证字符串解析为int的唯一简单方法是尝试它.虽然您可能想要进行一些前期检查,但精确检查是相当PITA的. (3认同)
  • 在javaDoc中具有NumberFormatException的IMHO****更重要**.将它放在`throws`子句中是一个很好的补充,但不是必需的. (2认同)

jmo*_*eno 5

数字4.如上所述,此方法不应将字符串作为应采用整数的参数.在这种情况下(因为java包装而不是溢出),不存在异常的可能性.

 x = sum(Integer.parseInt(a), Integer.parseInt(b))
Run Code Online (Sandbox Code Playgroud)

比什么意思要清楚得多 x = sum(a, b)

您希望异常尽可能接近源(输入).

对于选项1-3,您没有定义异常,因为您希望您的调用者假设您的代码不会失败,您定义一个异常来定义在已知的失败条件下发生的事情,这对您的方法来说是独一无二的.即如果你有一个方法是另一个对象的包装器,它会抛出一个异常,然后传递它.只有当异常对你的方法是唯一的时候才应该抛出一个自定义异常(在你的例子中,如果sum应该只返回正结果,那么检查它并抛出异常将是合适的,如果另一方面java抛出溢出异常而不是包装,然后你会传递它,而不是在你的签名中定义它,重命名它,或者吃掉它).

更新以回应问题的更新:

简而言之:如果我只有MUST库,我该如何实现SHOULD语义.

解决方法是包装MUST库,并返回SHOULD值.在这种情况下,返回一个Integer的函数.编写一个接受字符串并返回Integer对象的函数 - 它可以工作,或者返回null(比如guava的Ints.tryParse).您的验证是否与您的操作分开,您的操作应该采取整合.当您输入无效时,是否使用默认值调用操作,或者您执行其他操作时,将取决于您的规范 - 我可以说最多的是,是否真的不可能做出该决定的地方在操作中方法.

  • @ loki2302:你接受了答案说可以在通过垃圾时抛出一个未经检查的异常,但强类型语言的意思是防止垃圾被传递.有一个方法,希望字符串始终是一个整数值只是要求麻烦.即使是Integer.parseInt也不能很好地解决这个问题(对于应该预期的输入是坏的例外,.Net的integer.TryParse方法要好得多,尽管Java缺少out参数使得它有点不切实际). (2认同)