Java API设计:解析半数字字符串的方法的NumberFormatException?

时间:2011-04-15 11:49:13

标签: java api api-design

我正在创建一个包含一些解析字符串日期和时间的方法的库。当字符串参数不可解析时,我很难确定这些方法应该抛出的异常。我正在考虑几种选择:

1。 java.lang.IllegalArgumentException - 无效的字符串显然是非法的参数,但是,对我来说,IllegalArgumentException通常意味着编程错误,并且很少想要为一个显式try catch 。我认为字符串解析通常用于外部输入,更像是一种值得特殊处理的特殊情况。例如,如果您有一大块代码解析用户输入并对其执行其他操作,您可能希望将该代码包装在try catch块中,以便您可以处理包含无效字符串的用户输入的情况。但是捕获IllegalArgumentException对于查明无效的用户输入并不是很好,因为很可能代码中有多个地方可以抛出它(而不仅仅是用户输入的解析)。

2。 java.lang.NumberFormatException - 它由Integer.parseInt(String)java.lang中的其他类似解析方法引发。因此,大多数Java开发人员都熟悉,当您尝试解析可能有效或无效的字符串(例如用户输入)时,它会被捕获。但它的名字中有“数字”,所以我不确定它是否真的适合日期和时间这些在某种意义上是数字的东西,但在我看来在概念上是不同的。如果它只被称为“FormatException”......

第3。 java.text.ParseException - 不是真正的选项,因为它已经过检查。我希望不加以控制。

4。自定义异常 - 这可以绕过IllegalArgumentExceptionNumberFormatException的缺点,也可以扩展IllegalArgumentException。但我不认为向库中添加例外是个好主意,除非真的需要它们。引用约什布洛赫,"If in doubt, leave it out"。 (另外,在我的例子中,对于解析日期和时间的包,很难命名这样的异常:“DateFormatException”,“TimeFormatException”,“CalendricalFormatException”(如JSR 310) - 当应用于方法时,似乎没有一个对我来说是理想的解析日期,时间,日期时间等。我认为如果它们都只用于识别不可解析的字符串,那么在单个包中创建多个例外将是愚蠢的。)

您认为哪个选项最有意义?

NB我有充分的理由不想使用java.util.Date或Joda Time或JSR 310,所以不需要提出建议。另外我认为如果这个问题保持相当普遍会很好,因为这一定是其他设计API的人一直在努力解决的问题。日期和时间也可以是IP地址,URL或具有需要解析的字符串格式的任何其他类型的信息。

其他图书馆设定的先例

我发现的几个例子:

java.sql.Timestamp.valueOf(String) throws IllegalArgumentException

java.util.Date.parse(String) throws IllegalArgumentException(已弃用的方法,未声明异常,但您可以在源代码中看到它)

java.util.UUID.fromString(String) throws IllegalArgumentException

org.apache.axis.types.Time(String) throws NumberFormatException(也是Apache Axis中的Day类)

org.apache.tools.ant.util.DeweyDecimal(String) throws NumberFormatException

com.google.gdata.data.DateTime.parseDateTime(String) throws NumberFormatException

java.lang.Package.isCompatibleWith(String versionString) throws NumberFormatException(在Java 7中,这需要带点的字符串版本号 - 有点像某个意义上的日期或时间)

我确信有很多软件包使用自定义异常,所以我怀疑提供这些例子有很多意义。

4 个答案:

答案 0 :(得分:3)

我会建议IllegalFormatException作为基类(继承自IllegalArgumentException,但不幸的是唯一的构造函数是受包保护的,所以我可能会使用

  • IllegalArgumentException 小API(一些方法)
  • 您自己的类层次结构,否则继承自IllegalArgumentException

无论如何,我会使用IllegalArgumentException作为基类。

在我之前的一个项目中,指南是仅抛出继承自

的RuntimeExceptions
  • IllegalStateException
  • IllegalArgumentException
  • UnsupportedOperationException

虽然这不是官方的教条,但我称之为好习惯。所有这三个都是简单和自我描述。

答案 1 :(得分:1)

我会选择ParseException,因为这就是DateFormat.parse抛出的内容。因此,它具有你在2中提到的优势,程序员熟悉它。但既然你想要未经检查,我想这不是一个选择。如果被迫不加控制,我会选择4.

答案 2 :(得分:0)

对于这个问题,这是一个品味问题。在我看来,我不会抛出异常而是处理它。原因是如果输入错误,用户无法在异常处理程序中执行任何操作。因此,通过检查返回码可以轻松处理这些类型的错误。例外很重,不会带来额外的价值。

答案 3 :(得分:0)

我目前倾向于使用NumberFormatException。我在考虑简单的IllegalArgumentException,但我清楚地知道,当我编写一些代码时,这并不理想:

try {
    final Day day = Day.fromString(userInputString);
    someMethodThatCouldAlsoThrowIllegalArgumentException(day);
} catch (IllegalArgumentException e) {
    ui.showWarningMessage("Invalid date: " + userInputString);
}

假设你解析了一个有效的Day,你会想要用它做一些事情。如果它们收到无效参数(即编程错误而不是用户错误),那么您传递给它的方法很可能会抛出IllegalArgumentException。在上面的例子中,您需要注意不要混淆无效用户输入的编程错误,因此,为了安全起见,您需要像try / catch块之前定义的空变量一样混乱的东西,并在它之后检查null。

IllegalArgumentException交换NumberFormatException或自定义异常,问题就会消失。

看到JDK 1.7的java.lang.Package.isCompatibleWith(String versionNo)使用NumberFormatException作为解析版本号的方法(像"1.6.1.32"这样的半数字字符串),我想这可能是对于解析日期和时间等问题的方法也是明智的选择。

NumberFormatException对于解析只是半数字的字符串并不完全理想,但如果您不希望使用非真正需要的自定义异常来混淆API,它可能是最佳选择。如果他们在java.lang中进行,那么也许这就是按照定义使其成为Java的做事方式......

我希望能抓住它:)