Java String Index Out of Bounds Exception

问题描述 投票:4回答:2

是的我知道如何解决这个问题。我正在查看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()相同

java string exception indexoutofboundsexception stringbuilder
2个回答
1
投票

这取决于您正在使用的JDK实现。

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

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

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

enter image description here

enter image description here

更新

我实际上运行了一些代码来测试抛出的异常并发现一些有趣的东西。我的环境中的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,64bit,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

要从评论中提出一些问题:

  • [AbstractStringBuilder]不在文档中,这意味着我们不能用它编写程序? 一个通常跟随另一个。 AbstractStringBuilder类是java.lang包的私有类,这意味着它无法从该包外部访问。这意味着您将无法在代码中导入和使用此类。这是代码的某些部分的完美示例,它不属于系统的公共API(在本例中为JDK本身),在这种情况下,由于以下几个原因,它不会被记录: 你不能使用它 实施细节可能会不断变化 它不应该影响公共API的使用(系统的文档部分)
  • 如果在charAt()StringBuilder投掷StringIndexOutOfBoundsException,那么为什么文档只说IndexOutOfBoundsException? 这是因为这是基于类的设计意图的charAt()函数的描述行为。因为你可以为异常创建任意数量的子类(就像任何其他不是final的Java类一样),所以总是由实现程序员选择最好从函数返回(或抛出)的子类,只要因为该函数遵守约定的合同(接口,doc规范,抽象类等)。 话虽如此,你现在可以实现JDK并选择你自己的IndexOutOfBoundsException子类来引入这种情况。如果我在我的代码中使用StringBuilder.charAt(),我会捕获文档中描述的异常,因为这将使我具有最大的灵活性/可移植性,而不会因为依赖于实现细节而中断。关于这个主题已经写了整本书,所以我将在这里留下讨论:总是尝试捕捉你知道可能抛出的最具体的异常,这意味着,如果有可能其他实现可能不会抛出StringOutOfBoundsException,那么你最好是只捕捉IndexOutOfBoundsException,因为它保证属于那种类型(或它的子类)。

更新2

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

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


1
投票

这似乎是一个文件拼写错误。

在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);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.