【问题标题】:Java : Proper way a method() should handle a bad callJava:method() 处理错误调用的正确方式
【发布时间】:2016-11-08 11:05:10
【问题描述】:

我经常遇到这个问题。让我们看一个简单的例子,我得到了这个简单的方法:它在String[] 中检索String 的位置。

public int getStringPosition(String s, String[] text) {
    for (int i = 0; i < text.length; i++) {
        if (text[i].equals(s)) {
            return i;
        }
    }
    return text.length;
}

但是如果字符串不在数组中怎么办?在这里,它返回数组的大小(一个int,它不能来自正常使用该方法)。它也可以返回-1。我希望它会返回 null 但这似乎是不可能的。

不管怎样,这个方法会在同一个类中被其他一些方法使用。我的问题很笼统,如何处理无法返回预期内容的情况?

【问题讨论】:

  • 抛出异常...
  • 异常应该怎么办?如何警告用户该方法并仍然让他继续他的程序流程?
  • 尽管@Hackerdarshi 说过,另一方面,例如String 方法如何工作,也可能返回-1,例如String#indexOf,如果您返回原始类型.
  • @Fitz,通过捕获异常以防它被抛出,就像所有异常一样:)
  • @Fitz 是的。您的代码抛出异常,调用该方法的部分捕获它。

标签: java return


【解决方案1】:

如果无法找到字符串构成错误异常情况,那么你应该向调用者抛出一些异常。例如,

throw new RuntimeException("String not found");

如果无法找到字符串是调用者希望在正常代码流中处理的正常情况,那么您应该使用特殊的返回值。对于这种类型的搜索方法,正常的返回值不可能是负数,约定是返回-1,就像String.indexOfList.indexOf一样。如果你遵循这个约定,你实际上可以用一行来实现你的方法体:

return java.util.Arrays.asList(text).indexOf(s);

注意:该更改对null 的处理略有不同。您的方法中可能为 null 的三件事:搜索字符串、数组和数组元素。如果传递了一个空数组,或者当它遇到一个空元素时,您当前的代码会抛出一个NullPointerException,但会默默地忽略空搜索字符串。通过推迟到List.indexOf,所有数组元素也被允许为空,允许在数组中搜索空值。这可能是一个无害的区别,但设计良好的方法会考虑这些问题。例如,您可能更愿意将空搜索字符串视为无效输入并在这种情况下立即抛出异常。

一个完整记录的公共方法也会考虑数组中多个匹配元素的情况:它应该返回最低匹配索引,还是任何匹配索引?如果任何索引是可接受的,它是否必须始终为具有相同参数的重复调用返回相同的索引? (假设的多线程搜索实现很容易推翻返回最低索引的“明显”假设,因为您无法预测哪个 CPU 内核会首先找到匹配项。)

还要考虑该方法可以声明为static

【讨论】:

    【解决方案2】:

    如果s 不在text 中的情况不是调用该方法的有效方式,您应该抛出异常,例如非法参数异常。

    但是如果以这种方式调用该方法是可以的,则不应抛出异常,因为它是有效的预期用法。在这种情况下,您可以例如返回-1

    但在这种情况下,-1 是一个“幻数”,这是一种不好的做法,因此您应该为此声明一个常量。

    private static final int STRING_NOT_IN_TEXT=-1;
    
    /**
     * @return first position of 's' in 'text' 
     *         and if 's' is not in 'text' returns NOT_IN_TEXT
     */
    public static int getStringPosition(final String s, final String[] text) {
        for (int i = 0; i < text.length; i++) {
            if (text[i].equals(s)) {
                return i;
            }
        }
        return STRING_NOT_IN_TEXT;
    }
    

    附注您可能还想检查text 是否为null 并处理这种情况,而不是简单地让系统抛出NullPointerReference

    【讨论】:

    • 我也喜欢。我确实想过返回-1,这似乎更好。
    【解决方案3】:

    这是任意的。一些开发人员会抛出异常,其他人会返回一些特殊值,例如 -1。最重要的是准确定义您的方法在任何情况下的作用,以便使用您的代码的人知道他们正在使用什么。

    【讨论】:

    • 好的,所以没有一般​​性。我目前使用的许多来自 Apache POI 的方法在我请求某些可以提供的东西时经常返回 null。所以我可以通过之前测试 null 的情况来继续编码。感谢您的回答。
    • 请注意,测试 null 仅适用于非原始类型,如 String、ArrayList 等(原始类型为 int、double、float 等)
    【解决方案4】:

    遵循常见和已知的编码约定:您的方法看起来像 String.indexOf(String),因此当找不到输入时只需返回 -1。异常应该是“异常的”,而不是在数组中找不到字符串。

    如果你想要更多面向对象的东西,你可以实现类似

    Result search(T something,Set<T> someSet);
    

    FoundNotFound 类实现的接口 Result 以不同方式处理;总的来说,虽然这个解决方案看起来有点矫枉过正。

    【讨论】:

    • 我理解一些“更笼统”的东西。但是OO 究竟是什么意思呢? :)
    • 面向对象 ;)
    【解决方案5】:

    我想到了两件事:

    a) 对于返回指向任何类型序列的“索引”的方法返回 -1 表示“未找到匹配”是非常有效的

    b) 它可能也可以只抛出一些运行时异常,例如 IllegalArgumentException

    在考虑选项“b)”时,有时使用两种方法会有所帮助,例如 findIndex() 与 getIndex();按照惯例,“查找”方法总是会抛出异常;而另一个将返回 null/-1 或其他值。但当然,这是您为您的项目/您的团队/您的任何东西本地定义的东西。换句话说:所有处理你的代码的人都必须明白调用 findXyz() 可能会抛出异常;并且还有其他方法不会抛出。

    另外,您应该始终尝试与“标准解决方案”保持一致。我的意思是;假设您的代码将使用集合:

    int getIndex(String stringToSearch, List<String> stringsToSearch) {
      return stringsToSearch.indexOf(stringToSearch);
    

    猜猜这会返回什么...现在问问自己是否希望基于数组的解决方案与 java 标准集合做同样的事情...

    (最后的旁注:是的,我的变量名非常长,但我仍然认为一个冗长的名称比“s”更好......因为后者并没有告诉你任何关于这些变量的预期用途的信息参数)。

    【讨论】:

      【解决方案6】:

      你不能返回 null 因为你返回的是一个基本类型。改为返回 Integer 并允许 null。

      尽管如此,我同意上面的评论员,例外是处理这个问题的正确方法

      【讨论】:

      • 我喜欢 return Integer 的想法。目标是让用户继续他的程序。我目前使用的许多来自 Apache POI 的方法通常会在我要求提供的情况下返回 null。所以我可以通过之前测试 null 的情况继续编码。
      • 但这可能会导致 NullPointerException,最终,您需要处理异常...
      • 用户可以捕获异常,记录它或分配一个默认值(或任何他需要的值)并继续程序。
      • @Hackerdarshi 是的,但在 Apache POI 中,它似乎留给了用户。这是一个很好的解决方案吗?我个人很喜欢。 Cell cell = row.getCell(i, Row.RETURN_BLANK_AS_NULL); 经常返回 null(例如)。
      【解决方案7】:

      如果什么也没找到,返回 null 是一个很好的模式。您可以使用Integer 代替intInteger 类将原始类型 int 的值包装在一个对象中。 Integer 类型的对象包含一个类型为 int 的字段。这就是为什么你可以返回 null 如果你让它像

      public Integer getStringPosition(String s, String[] text)
      

      【讨论】:

        【解决方案8】:

        不过,您可以使用此处的建议:

        • '-1' 是一个“神奇的值”,通常被认为是一种反模式
        • 为非异常情况抛出异常也被视为反模式(有些人会说抛出任何非系统异常都是反模式)
        • 使用Integer 作为返回类型并返回一个null 值。然而null 也被视为一种反模式(谷歌“消除了十亿美元的错误”)

        如果您不介意上述内容,请继续使用其中一个选项(很多程序员都经常使用这些选项)

        你也可以使用 Optional/Maybe/Option 类型

        public Optional<Integer> getStringPosition(String s, String[] text) {
            for (int i = 0; i < text.length; i++) {
                if (text[i].equals(s)) {
                    Optional.of(i);
                }
            }
            return Optional.empty();
        }
        

        Optional 在 Java 8 中可用。如果您使用的是旧版本,则可以使用众多可用实现之一(例如,https://google.github.io/guava/releases/19.0/api/docs/com/google/common/base/Optional.html

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-10-06
          • 2019-05-17
          • 1970-01-01
          • 2019-03-04
          • 1970-01-01
          相关资源
          最近更新 更多