为什么我的程序抛出StringIndexOutOfBounds异常?

时间:2015-02-28 20:27:28

标签: java stringbuilder biginteger

我正在编写一个计算程序:

1 ^ 1 + 2 ^ 2 + 3 ^ 3 + ... + 1000 ^ 1000 =?

一旦计算出来,我想删除除最后十位数之外的答案中的所有数字,然后在屏幕上打印最后十位数字。但是,要删除我使用StringBuilder.deleteCharAt()方法的所有其他数字,这会导致一些问题。我在下面提供了我的代码:

import java.math.BigInteger;
public class problemFourtyEight {
  public static void main(String [] args) {
    BigInteger answer = new BigInteger(""+0);
    for(int i = 0; i <= 1000; i++) {
      BigInteger temp = new BigInteger(""+i);
      temp = temp.pow(i);
      answer = answer.add(temp);
    }
    System.out.println(answer.toString().length());
    StringBuilder sb = new StringBuilder((answer.toString()));
    for(int k = 0; k <= (answer.toString().length() - 10); k++) {
      sb.deleteCharAt(k);  //Line 13 is here.
    }
    String finalAnswer = sb.toString();
    System.out.println(finalAnswer);
  }
}

抛出的异常是:

Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 1501
    at java.lang.AbstractStringBuilder.deleteCharAt(AbstractStringBuilder.java:797)
    at java.lang.StringBuilder.deleteCharAt(StringBuilder.java:253)
    at problemFourtyEight.main(problemFourtyEight.java:13)

从打印出答案的长度(删除任何字符之前),它告诉我数字的长度是3001,所以我不明白为什么String index 1,501被认为是{ {1}}。

4 个答案:

答案 0 :(得分:6)

您的错误是此代码:

StringBuilder sb = new StringBuilder((answer.toString()));
for(int k = 0; k <= (answer.toString().length() - 10); k++) {
  sb.deleteCharAt(k);  //Line 13 is here.
}

由于字符串构建器的可变性,使字符串变得更短。 你想要:

System.out.println(answer.substring(answer.length()-10))

如果对你很重要,这也有速度的优势。

答案 1 :(得分:1)

当您删除第i个字符时,第i + 1个字符将成为新的第i个字符。因此,您的外观应始终删除第一个字符:

for(int k = 0; k <= (answer.toString().length() - 10); k++) {
  sb.deleteCharAt(0);
}

例如:

        StringBuilder sb = new StringBuilder("abcdef");
        sb.deleteCharAt(0);
        sb.deleteCharAt(1);
        sb.deleteCharAt(2);
        sb.deleteCharAt(3); // throws java.lang.StringIndexOutOfBoundsException: String index out of range: 3
        System.out.println(sb.toString());

        sb = new StringBuilder("abcdef");
        sb.deleteCharAt(0);
        sb.deleteCharAt(0);
        sb.deleteCharAt(0);
        sb.deleteCharAt(0);
        System.out.println(sb.toString()); // prints "ef"

答案 2 :(得分:1)

如果您检查了StringBuilder对象的长度,则此代码可能会(某种程度上),但是您检查原始字符串的长度,但删除StringBuilder中的字符。每次删除时StringBuilder都会变短,因此k索引最终会超出sb的范围。

StringBuilder sb = new StringBuilder((answer.toString()));
for(int k = 0; k <= (sb.length() - 10); k++) { // <-- make sure to test the length of the thing you are mutating
  sb.deleteCharAt(0);  // Delete first character of remaining sb
}

但是,substring()在这里应该首选。

答案 3 :(得分:0)

我认为这是因为每次从字符串中删除字符时,字符串缓冲区会调整大小并且字符串变短,所以从3001中删除1500个字符后,字符串缓冲区将存储从0到1500的字符,并且索引1501已经输出范围。

您可以使用子字符串打印最后10位数字。