什么是StringIndexOutOfBoundsException?我该如何修复它?

14
这是我的代码:
    private void bringData() {
    final TextView mTextView = (TextView) findViewById(R.id.textView);

    // Instantiate the RequestQueue.
    RequestQueue queue = Volley.newRequestQueue(this);
    String url ="http://192.168.4.1:8080/";

    // Request a string response from the provided URL.
    StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    // Display the first 500 characters of the response string.
                    mTextView.setText("Response is: "+ response.substring(0,500));
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            mTextView.setText("That didn't work!");
        }
    });
    // Add the request to the RequestQueue.
    queue.add(stringRequest);
}

这是来自Android文档的默认设置,我只更改了URL。

这是我的错误信息:

java.lang.StringIndexOutOfBoundsException: length=28; regionStart=1; regionLength=499 at java.lang.String.substring(String.java:1931) at com.example.my.app.MainActivity$2.onResponse(MainActivity.java:50) at com.example.my.app.MainActivity$2.onResponse(MainActivity.java:46) at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:60) at com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:30) at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.app.ActivityThread.main(ActivityThread.java:6077) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755)

在调试过程中,我看到在mTextView.setText("Response is: "+ response.substring(0,500));处我的消息已经传递给我,但是textview从未更新并且应用程序崩溃了。

具体而言,它在Looper.Java文件内崩溃:

finally {
if (traceTag != 0) {
   Trace.traceEnd(traceTag);
} 

traceTag为0。

我读到一些字符串边界错误,但我找不出如何修复它。


阅读StringIndexOutOfBoundsException的文档。然后查看您收到的错误。 - njzk2
虽然这个异常与ArrayIndexOutOfBoundsException相关,但它不是一个副本。这个异常是不同的。原因是不同的(尽管类似)。最重要的是,那个问题及其答案没有提到这个异常。 - Stephen C
1个回答

23
Error Message:
    java.lang.StringIndexOutOfBoundsException: length=28; regionStart=1;
    regionLength=499 at java.lang.String.substring(String.java:1931) at     
    com.example.my.app.MainActivity$2.onResponse(MainActivity.java:50) at     
    com.example.my.app.MainActivity$2.onResponse(MainActivity.java:46) at     
    com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:60) at     
    com.android.volley.toolbox.StringRequest.deliverResponse(StringRequest.java:30) at     
    com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:99) at android.os.Handler.handleCallback(Handler.java:751) at     
    android.os.Handler.dispatchMessage(Handler.java:95) at     
    android.os.Looper.loop(Looper.java:154) at     
    android.app.ActivityThread.main(ActivityThread.java:6077) at     
    java.lang.reflect.Method.invoke(Native Method) at     
    com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:865) at     
    com.android.internal.os.ZygoteInit.main(ZygoteInit.java:755) 

Error Description

There is an IndexOutOfBound exception occurred in your MainActivity class 
Inside second inner class's OnResponse function as shown MainActivity$2onResponse
on line 46 which basically occurred during substring operation in String.java line 1931 
which was invoked from StringRequest.deliverResponse at line 60,
which was invoked from StringRequest.deliverResponse at line 30,
which was invoked from ExecutorDelivery.java at line 99,
which intially started from ZygoteInit$MethodAndArgsCaller's run function 
and reached up-to main thread of ActivityThread.main=>looper=>handler

实际原因

您的代码尝试创建一个子字符串,但是

starting index = 0
ending index = 500

虽然您实际的响应字符串长度为28,因此字符串长度不足以创建500个字符的子字符串。
解决方案:
  1. Validate length using ternary operator ?:

    mTextView.setText("Response is: "+ 
       ((response.length()>499) ? response.substring(0,500) : "length is too short"));
    

    Note : Ternary operator (?:) is a short expression of if else but it is not a statement mean it cannot occur as an atomic statement as this is INVALID because there is no assignment

    ((someString.length()>499) ? someString.substring(0,500):"Invalid length");
    
  2. if-else enhances the visibility

    String msg="Invalid Response";
    if(response.length()>499){
        msg=response.substring(0,500);
    }
    mTextView.setText("Response is: "+msg);
    
    //or     mTextView.setText("Response is: "+response);
    

什么是IndexOutOfBoundsException?

IndexOutOfBoundsExceptionRuntimeException的一个子类,意味着它是一个未经检查的异常,用于指示某种索引(例如数组、字符串或向量)超出范围,例如使用List。

文档所示。

List<String> ls=new ArrayList<>();
      ls.add("a");
      ls.add("b");
      ls.get(3); // will throw IndexOutOfBoundsException , list length is 2

预防措施 :

String str = "";
int index =3; 
if(index < ls.size())    // check, list size must be greater than index
    str = ls.get(index);
else
    // print invalid index or other stuff

使用索引或字符串消息的类构造函数用法

public IndexOutOfBoundsException() {
    super();
}

public IndexOutOfBoundsException(String s) {
    super(s);
}

IndexOutOfBoundsException有哪些其他变体/子类?

  • ArrayIndexOutOfBoundsException : This indicate that an array has been accessed with an illegal index. The index is either negative or greater than or equal to the size of the array for e.g

    int arr = {1,2,3}
    int error = arr[-1]; // no negative index allowed
    int error2 = arr[4]; // arr length is 3 as index range is 0-2
    

预防措施 :

int num = "";
int index=4;
if(index < arr.length)     // check, array length must be greater than index
    num = arr[index];
else
    // print invalid index or other stuff
  • StringIndexOutOfBoundsException : This is thrown by String methods to indicate that an index is either negative or greater than the size of the string. For some methods such as the charAt method, this exception also is thrown when the index is equal to the size of the string.

    String str = "foobar";       // length = 6
    char error = str.charAt(7);  // index input should be less than or equal to length-1
    char error = str.charAt(-1); // cannot use negative indexes
    

预防措施

String name = "FooBar";
int index = 7;
char holder = '';
if(index < name.length())     // check, String length must be greater than index
    holder = name.charAt(index) ;
else
    // print invalid index or other stuff

注意:length()String类的函数,而lengtharray的一个关联字段。

为什么会发生这些异常?

  • 在使用arrayscharAtsubstring函数时使用了负索引
  • BeginIndex小于0或endIndex大于输入字符串长度以创建substring,或者beginIndex大于endIndex
  • endIndex - beginIndex的结果小于0
  • 输入的字符串/数组为空

信息: JVM的工作是创建适当的异常对象并使用throw关键字将其传递到它发生的地方,也可以使用throw关键字手动执行该操作。

if (s == null) {
    throw new IndexOutOfBoundsException("null");
}

我该如何修复这个问题?
1.分析StackTrace 2.针对空值、长度或有效索引验证输入字符串 3.使用调试或日志记录 4.使用通用异常捕获块
1.) 分析StackTrace 如本文开头所示,StackTrace提供了有关发生位置和原因的必要信息,因此您可以简单地跟踪该代码并应用所需的解决方案。
例如,查看StringIndexOutOfBoundsException的原因,然后查找指示类文件的包名称,然后转到该行并牢记原因,简单地应用解决方案。
如果您在文档中学习异常及其原因,那么这是一个良好的起点。
2.) 针对空值、长度或有效索引验证输入字符串
在你不确定实际输入(比如来自服务器的响应,或者可能是错误或什么都没有)或用户时,最好涵盖所有意外情况,尽管相信我,一些用户总是喜欢推动测试的极限,因此使用input!=null && input.length()>0或对于索引,您可以使用三元运算符或if-else边界检查条件。
3.) 使用调试或日志
您可以通过在项目中添加断点以调试模式测试项目的运行环境,系统会在那里停止等待您的下一个操作,同时您可以查看变量和其他细节的值。
日志就像检查点一样,当您的控制穿过这个点时,它们生成详细信息,基本上它们是由系统或用户使用Logs或Println消息放置日志消息的信息性消息。
4.) 使用通用异常捕获块 try-catch块总是有用的,用于处理RuntimeExceptions,因此您可以使用多个catch块来处理可能的问题并提供适当的详细信息。
try {
     mTextView.setText("Response is: "+ response.substring(0,500));
} catch (IndexOutOfBoundsException e) {
    e.printStackTrace();
    System.out,println("Invalid indexes or empty string");
}
  catch (NullPointerException e) { // mTextView or response can be null 
    e.printStackTrace();
    System.out,println("Something went wrong ,missed initialization");
}
catch (Exception e) {  
    e.printStackTrace();
    System.out,println("Something unexpected happened , move on or can see stacktrace ");
}

进一步参考资料

什么是NullPointerException,如何修复它?


谢谢,但现在它只显示“您想要显示的任何内容”。因此,response.length()不超过499。 - traveller
@traveller 因为我在我的答案中说过,您的响应长度为28,因此您无法创建一个500个字符的字符串。关于“您想要显示的任何内容”,它只是一个字符串,因此您在这里提供的任何内容都将被显示。 - Pavneet_Singh
1
我现在明白了。我的字符串只有28个字符,而我正在尝试创建一个长度为500的子字符串,显然我做不到,但如果我的字符串超过500个字符,我就能够做到。 - traveller
为了最大化未来价值,我建议删除或概括您答案中的第一部分(特定于问题的部分),并更新问题以更像一个规范问题(包括 [mcve],像这样),或发布一个单独的规范问答。 - Bernhard Barker
@Dukeling,我非常欣赏慷慨的人,非常感谢你,我完全同意你宝贵的建议,特别是创建一个单独的新规范问题,虽然我不完全确定,但我会花些时间重新组织内容,使其更相关。很高兴和你交流。 - Pavneet_Singh
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接