【问题标题】:Java String Index Out Of Bounds ExceptionJava 字符串索引越界异常
【发布时间】:2019-08-01 23:34:59
【问题描述】:

是的,我知道如何解决这个问题。我正在查看 String Class 和 String Builder Class 之间的 API。这是我的问题:

StringBuilder sb = new StringBuilder("wibble");
String s = new String("wobble");

sb.charAt(index) //Can throw Index Out Of Bounds Exception
s.charAt(index) //Can throw Index Out of Bounds Exception

sb.substring(start, end) //Can throw STRING index out of bounds exception
s.substring(start, end) //Only throws Index out of Bounds Exception (no String)

因此,当它决定抛出 StringIndexOutOfBoundsException 与 IndexOutOfBoundsException 时,没有任何意义。是的,我知道 StringIndex 是一个子例外。在 String 和 StringBuilder 中,某些实现相同的方法会抛出相同的异常,而在某些实现相同的方法中,StringBuilder 会抛出子异常。那为什么会这样呢?

为了避免人们滚动浏览答案并感谢回答的 2 个人,即使我只能选择一个作为回答,两者都有助于澄清: Java Oracle Doc People 在 String 的子字符串中打错字。它应该是 StringIndexOutOfBoundsException。与 StringBuilder 中的 CharAt() 相同

【问题讨论】:

  • 还有为什么是substring(...)和subString(...)
  • @RNJ 修复它 brosky
  • 可能与 String#codePointBefore(0)String#substring(-1) 有效抛出 StringIndexOutOfBounds 但文档仅声明 IndexOutOfBounds 的原因相同 - 程序员只是人类
  • @CarlosHeuberger 我真的不知道 codePointBefore 方法,但即使它是相同的原因......那是什么原因......所以我可以问同样的问题。这似乎不是武断的......

标签: java string exception indexoutofboundsexception stringbuilder


【解决方案1】:

这取决于您使用的是哪个 JDK 实现。

我做了一些挖掘并找到了实现的方法,public char charAt(int index) 用于 StringBuilder 类。 (注意:我使用的是 Oracle JDK 1.8)。

因此,在这种情况下,StringBuilder 类是AbstractStringBuilder 的子类。这是实现程序员的选择,因为您不会在 docs 中找到它。

我发现charAt 函数是在AbstractStringBuilder 基类上实现的。以下是我系统中相关代码的一些屏幕截图。 (记住,特定的 JDK 是 Oracle & Java 1.8)。

更新

我实际上运行了一些代码来测试抛出了哪些异常并发现了一些有趣的东西。我的环境中的charAt() 函数也会抛出java.lang.StringIndexOutOfBoundsException。这是我运行来测试它的代码:

public class StringVsStringBuilder {
    public static void main(String[] args) {
        StringBuilder builder = new StringBuilder("one");
        String string = "two";

        try {
            builder.charAt(10); // Clearly out of bounds
        } catch (IndexOutOfBoundsException e) {
            System.out.println(String.format(
                    "Exception encountered accessing character out of index bounds on variable 'builder': %s",
                    e.getClass()
            ));
        }

        try {
            string.charAt(10); // Clearly out of bounds
        } catch (IndexOutOfBoundsException e) {
            System.out.println(String.format(
                    "Exception encountered accessing character out of index bounds on variable 'string': %s",
                    e.getClass()
            ));
        }
    }
}

这是运行时的输出(Windows 10、64 位、Oracle JDK 1.8.0_191):

Exception encountered accessing character out of index bounds on variable 'builder': class java.lang.StringIndexOutOfBoundsException
Exception encountered accessing character out of index bounds on variable 'string': class java.lang.StringIndexOutOfBoundsException

Process finished with exit code 0

解决cmets的一些问题:

  • [AbstractStringBuilder] 不在文档中,这意味着我们不能用它编写程序?

    一个通常跟随另一个。 AbstractStringBuilder 类是 java.lang 包的私有类,这意味着它不能从该包的外部访问。这意味着您将无法在代码中导入和使用此类。这是不属于系统公共 API 的部分代码(在本例中为 JDK 本身)的完美示例,在这种情况下,由于以下几个原因,它不会被记录:

    1. 你不能使用它
    2. 实施细节可能会不断变化
    3. 不应影响公共 API(系统的文档部分)的使用
  • 如果StringBuilder 中的charAt() 抛出StringIndexOutOfBoundsException,那么为什么文档只说IndexOutOfBoundsException

    这是因为这是 charAt() 函数基于类的设计意图所描述的行为。由于您可以为异常创建任意数量的子类(就像任何其他不是 final 的 Java 类一样),因此始终由实现程序员来选择从函数中返回(或抛出)的最佳方法,只要功能遵守约定的合同(接口、文档规范、抽象类等)。

    话虽如此,您现在可以实现 JDK 并选择您自己的 IndexOutOfBoundsException 子类来抛出这种情况。如果我在我的代码中使用StringBuilder.charAt(),我会捕获文档中描述的异常,因为这将使我获得最大的灵活性/可移植性,而不会冒着因依赖实现细节而中断的风险。关于这个主题已经写了整本书,所以我将把讨论留在这里:总是尝试捕捉你知道可能抛出的最具体的异常,这意味着,如果其他实现可能不会抛出StringOutOfBoundsException,那么你最好只捕获IndexOutOfBoundsException,因为它保证是那种类型(或它的子类)。

更新 2

在这种特定情况下,您几乎可以忽略我上面提到的所有内容,而只关注以下内容:

charAt()java.lang.CharSequence中描述的接口方法。这意味着对于任何实现类,尝试访问超出序列范围的索引时引发的问题将是IndexOutOfBoundsException。该接口描述了一般行为,并且不必根据StringStringBuilderAlphabetSoup 或任何其他特定实现来定义此行为。如果那些暗示。决定子类化该异常并在每种情况下提供更具体的错误信息,这很好,但它不会改变一般合同。如果您正在编写通用字符处理系统,那么您可能会写入接口而不关心底层 impl。在这种情况下,您只会知道(或关心)IndexOutOfBoundsException,而不会知道其他任何事情。

【讨论】:

  • 快速问个无关紧要的问题,abstractstringbuilder 不在文档中,这意味着我们不能用它编写程序?
  • 你是说jdk吗?不是jvm
  • 对垃圾邮件感到抱歉,如果 StringBuilder 中的 charAt() 抛出 StringIndexOutOfBoundsException,那么为什么文档只说 IndexOutOfBoundsException?
  • 我会尝试在更新我的答案中解决您的问题
  • 是的,我也会将其添加到答案中。
【解决方案2】:

这似乎是文档拼写错误。

在 Java HotSpot(TM) 10.0.1 中,String.substring 会抛出 StringIndexOutOfBoundsException

public String substring(int beginIndex, int endIndex) {
    int length = length();
    checkBoundsBeginEnd(beginIndex, endIndex, length); //here
    int subLen = endIndex - beginIndex;
    if (beginIndex == 0 && endIndex == length) {
        return this;
    }
    return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen)
                      : StringUTF16.newString(value, beginIndex, subLen);
}


static void checkBoundsBeginEnd(int begin, int end, int length) {
    if (begin < 0 || begin > end || end > length) {
        throw new StringIndexOutOfBoundsException(
            "begin " + begin + ", end " + end + ", length " + length);
    }
}

【讨论】:

  • 这不是错字。该规范描述它抛出一个IndexOutOfBoundsException,因为这是意图。如果抛出更具体的异常,那只是因为程序员认为它更有用。这不会改变方法的规范,这意味着您不应该期望所有实现都抛出相同的特定异常。此外,即使意图是抛出一个StringIndexOutOfBoundsException,这也不会是一个错字,因为它一个IndexOutOfBoundsException(多态性)。
猜你喜欢
  • 2013-12-08
  • 1970-01-01
  • 1970-01-01
  • 2014-10-16
  • 2017-03-22
  • 1970-01-01
  • 1970-01-01
  • 2012-10-03
  • 1970-01-01
相关资源
最近更新 更多