Điều gì gây ra java.lang.ArrayIndexOutOfBoundException và làm cách nào để ngăn chặn nó?


298

Điều đó ArrayIndexOutOfBoundsExceptioncó nghĩa là gì và làm thế nào để tôi thoát khỏi nó?

Đây là một mẫu mã kích hoạt ngoại lệ:

String[] names = { "tom", "bob", "harry" };
for (int i = 0; i <= names.length; i++) {
    System.out.println(names[i]);
}

1
Để tham khảo câu hỏi cuối cùng, mã sẽ hữu ích. Bạn đang truy cập vào mảng với một chỉ mục đã biết hay bạn phải bắt đầu gỡ lỗi để tìm ra cách tính chỉ mục khi xảy ra lỗi?
justkt

43
Thay thế i <= name.lengthbằng i < name.length- hoặc tốt hơn, viết một vòng lặp nâng cao. ( for (String aName : name) { ... })
Jean Hominal

1
điều đó có nghĩa là bạn muốn lấy phần tử của mảng không tồn tại, 'i <= name.length' có nghĩa là bạn muốn lấy phần tử có độ dài + 1 - nó không tồn tại.
gbk


Câu trả lời:


296

Cổng gọi đầu tiên của bạn phải là tài liệu giải thích hợp lý rõ ràng:

Ném để chỉ ra rằng một mảng đã được truy cập với một chỉ mục bất hợp pháp. Chỉ số là âm hoặc lớn hơn hoặc bằng kích thước của mảng.

Ví dụ:

int[] array = new int[5];
int boom = array[10]; // Throws the exception

Về cách tránh nó ... ừm, đừng làm thế. Hãy cẩn thận với các chỉ số mảng của bạn.

Một vấn đề đôi khi mọi người gặp phải là nghĩ rằng các mảng được lập chỉ mục 1, ví dụ:

int[] array = new int[5];
// ... populate the array here ...
for (int index = 1; index <= array.length; index++)
{
    System.out.println(array[index]);
}

Điều đó sẽ bỏ lỡ phần tử đầu tiên (chỉ số 0) và đưa ra một ngoại lệ khi chỉ mục là 5. Các chỉ mục hợp lệ ở đây là 0-4. Phát biểu chính xác, thành ngữ forở đây sẽ là:

for (int index = 0; index < array.length; index++)

(Tất nhiên, giả sử bạn cần chỉ mục, tất nhiên. Nếu bạn có thể sử dụng vòng lặp nâng cao thay thế, hãy làm như vậy.)


1
Tôi muốn thêm rằng đối với các mảng nhiều chiều có thể có hình dạng tùy ý trong Java, các vòng lặp lồng nhau sẽ kiểm tra độ dài phân đoạn có liên quan : for (int nestedIndex = 0; nestedIndex < array[outerIndex].length; nestedIndex++) { ... array[outerIndex][nestedIndex] ... }.
Andrey

52
if (index < 0 || index >= array.length) {
    // Don't use this index. This is out of bounds (borders, limits, whatever).
} else {
    // Yes, you can safely use this index. The index is present in the array.
    Object element = array[index];
}

Xem thêm:


Cập nhật : theo đoạn mã của bạn,

for (int i = 0; i<=name.length; i++) {

Các chỉ số được bao gồm chiều dài của mảng. Đây là ngoài giới hạn. Bạn cần thay thế <=bằng <.

for (int i = 0; i < name.length; i++) {

22

Từ bài viết xuất sắc này: ArrayIndexOutOfBoundException trong vòng lặp for

Nói ngắn gọn:

Trong lần lặp lại cuối cùng của

for (int i = 0; i <= name.length; i++) {

isẽ bằng name.lengthđó là một chỉ mục bất hợp pháp, vì các chỉ số mảng là không dựa trên.

Mã của bạn nên đọc

for (int i = 0; i < name.length; i++) 
                  ^

17

Điều đó có nghĩa là bạn đang cố gắng truy cập vào một chỉ mục của một mảng không hợp lệ vì nó không nằm trong giới hạn.

Ví dụ, điều này sẽ khởi tạo một mảng số nguyên thủy với giới hạn trên 4.

int intArray[] = new int[5];

Lập trình viên đếm từ số không. Vì vậy, ví dụ này sẽ ném một ArrayIndexOutOfBoundsExceptiongiới hạn trên là 4 chứ không phải 5.

intArray[5];

4
Giới hạn là giới hạn trong phạm vi. I E; 0-5
John Giotta

11

Để tránh ngoại lệ chỉ mục mảng ngoài giới hạn, người ta nên sử dụng câu lệnh nâng caofor ở đâu và khi nào có thể.

Động lực chính (và trường hợp sử dụng) là khi bạn lặp và bạn không yêu cầu bất kỳ bước lặp phức tạp nào. Bạn sẽ không thể sử dụng một tăng cường - forđể di chuyển ngược trong một mảng hoặc chỉ lặp đi lặp lại trên mọi phần tử khác.

Bạn được đảm bảo không hết các yếu tố để lặp đi lặp lại khi thực hiện điều này và ví dụ [đã sửa] của bạn dễ dàng được chuyển đổi qua.

Mã dưới đây:

String[] name = {"tom", "dick", "harry"};
for(int i = 0; i< name.length; i++) {
    System.out.print(name[i] + "\n");
}

... tương đương với điều này:

String[] name = {"tom", "dick", "harry"};
for(String firstName : name) {
    System.out.println(firstName + "\n");
}

11

Nguyên nhân ArrayIndexOutOfBoundsExceptiongì?

Nếu bạn nghĩ về một biến là một "hộp" nơi bạn có thể đặt một giá trị, thì một mảng là một chuỗi các hộp được đặt cạnh nhau, trong đó số lượng hộp là một số nguyên hữu hạn và rõ ràng.

Tạo một mảng như thế này:

final int[] myArray = new int[5]

tạo một hàng gồm 5 hộp, mỗi hộp giữ một int. Mỗi hộp có một chỉ mục, một vị trí trong chuỗi các hộp. Chỉ số này bắt đầu từ 0 và kết thúc tại N-1, trong đó N là kích thước của mảng (số lượng hộp).

Để lấy một trong các giá trị từ loạt hộp này, bạn có thể tham khảo nó thông qua chỉ mục của nó, như sau:

myArray[3]

Nó sẽ cung cấp cho bạn giá trị của hộp thứ 4 trong chuỗi (vì hộp đầu tiên có chỉ số 0).

Một nguyên nhân ArrayIndexOutOfBoundsExceptionlà do cố gắng lấy lại một "hộp" không tồn tại, bằng cách vượt qua một chỉ số cao hơn chỉ số của "hộp" cuối cùng hoặc âm.

Với ví dụ đang chạy của tôi, các đoạn mã này sẽ tạo ra một ngoại lệ như vậy:

myArray[5] //tries to retrieve the 6th "box" when there is only 5
myArray[-1] //just makes no sense
myArray[1337] //waay to high

Làm sao để tránh ArrayIndexOutOfBoundsException

Để ngăn chặn ArrayIndexOutOfBoundsException, có một số điểm chính cần xem xét:

Vòng lặp

Khi lặp qua một mảng, luôn đảm bảo rằng chỉ mục bạn đang truy xuất nhỏ hơn hoàn toàn so với chiều dài của mảng (số lượng hộp). Ví dụ:

for (int i = 0; i < myArray.length; i++) {

Lưu ý rằng <, không bao giờ trộn một =trong đó ..

Bạn có thể muốn được cám dỗ để làm một cái gì đó như thế này:

for (int i = 1; i <= myArray.length; i++) {
    final int someint = myArray[i - 1]

Chỉ không. Bám sát cái ở trên (nếu bạn cần sử dụng chỉ số) và nó sẽ giúp bạn tiết kiệm rất nhiều nỗi đau.

Nếu có thể, hãy sử dụng foreach:

for (int value : myArray) {

Bằng cách này, bạn sẽ không phải suy nghĩ về các chỉ số.

Khi lặp, bất cứ điều gì bạn làm, KHÔNG BAO GIỜ thay đổi giá trị của trình vòng lặp (ở đây i:). Nơi duy nhất này nên thay đổi giá trị là giữ cho vòng lặp tiếp tục. Thay đổi nó chỉ là rủi ro ngoại lệ, và trong hầu hết các trường hợp không phải là cần thiết.

Truy xuất / cập nhật

Khi lấy một phần tử tùy ý của mảng, luôn kiểm tra xem đó có phải là một chỉ mục hợp lệ so với độ dài của mảng không:

public Integer getArrayElement(final int index) {
    if (index < 0 || index >= myArray.length) {
        return null; //although I would much prefer an actual exception being thrown when this happens.
    }
    return myArray[index];
}

6

Trong mã của bạn, bạn đã truy cập các phần tử từ chỉ số 0 đến độ dài của mảng chuỗi. name.lengthđưa ra số lượng các đối tượng chuỗi trong mảng các đối tượng chuỗi của bạn tức là 3, nhưng bạn chỉ có thể truy cập tối đa chỉ mục 2 name[2], vì mảng có thể được truy cập từ chỉ mục 0 đến name.length - 1nơi bạn nhận được name.lengthsố lượng đối tượng.

Ngay cả khi sử dụng forvòng lặp, bạn đã bắt đầu với chỉ số 0 và bạn nên kết thúc bằng name.length - 1. Trong một mảng, [n] bạn có thể truy cập từ [0] đến [n-1].

Ví dụ:

String[] a={"str1", "str2", "str3" ..., "strn"};

for(int i=0;i<a.length()i++)
    System.out.println(a[i]);

Trong trường hợp của bạn:

String[] name = {"tom", "dick", "harry"};

for(int i = 0; i<=name.length; i++) {
    System.out.print(name[i] +'\n');
}

5

Đối với mảng đã cho của bạn, độ dài của mảng là 3 (tức là name.length = 3). Nhưng vì nó lưu trữ phần tử bắt đầu từ chỉ số 0, nên nó có chỉ số tối đa 2.

Vì vậy, thay vì 'i ** <= name.length', bạn nên viết 'i <** name.length' để tránh 'ArrayIndexOutOfBoundException'.


3

Quá nhiều cho câu hỏi đơn giản này, nhưng tôi chỉ muốn làm nổi bật một tính năng mới trong Java, điều này sẽ tránh mọi sự nhầm lẫn xung quanh việc lập chỉ mục trong mảng ngay cả đối với người mới bắt đầu. Java-8 đã trừu tượng hóa nhiệm vụ lặp lại cho bạn.

int[] array = new int[5];

//If you need just the items
Arrays.stream(array).forEach(item -> { println(item); });

//If you need the index as well
IntStream.range(0, array.length).forEach(index -> { println(array[index]); })

Lợi ích là gì? Vâng, một điều là khả năng đọc như tiếng Anh. Thứ hai, bạn không cần phải lo lắng vềArrayIndexOutOfBoundsException


3

Bạn đang nhận được ArrayIndexOutOfBoundsExceptiondo i<=name.lengthmột phần. name.lengthtrả về độ dài của chuỗi name, là 3. Do đó khi bạn cố gắng truy cập name[3], đó là bất hợp pháp và ném ngoại lệ.

Mã đã giải quyết:

String[] name = {"tom", "dick", "harry"};
for(int i = 0; i < name.length; i++) { //use < insteadof <=
  System.out.print(name[i] +'\n');
}

Nó được định nghĩa trong đặc tả ngôn ngữ Java :

Các public finallĩnh vực length, trong đó có số lượng các thành phần của mảng. lengthcó thể dương hoặc bằng không.


3

Chỉ số mảng ngoài giới hạn

Đó là cách loại ngoại lệ này trông như thế nào khi được ném vào Eclipse. Số màu đỏ biểu thị chỉ mục bạn đã cố truy cập. Vì vậy, mã sẽ trông như thế này:

myArray[5]

Lỗi được đưa ra khi bạn cố truy cập vào một chỉ mục không tồn tại trong mảng đó. Nếu một mảng có độ dài bằng 3,

int[] intArray = new int[3];

thì các chỉ mục hợp lệ duy nhất là:

intArray[0]
intArray[1]
intArray[2]

Nếu một mảng có độ dài bằng 1,

int[] intArray = new int[1];

thì chỉ số hợp lệ duy nhất là:

intArray[0]

Bất kỳ số nguyên nào bằng độ dài của mảng hoặc lớn hơn nó: nằm ngoài giới hạn.

Bất kỳ số nguyên nào nhỏ hơn 0: nằm ngoài giới hạn;

PS: Nếu bạn muốn hiểu rõ hơn về mảng và thực hiện một số bài tập thực tế, có một video ở đây: hướng dẫn về mảng trong Java


3

Đối với các mảng nhiều chiều, có thể khó để đảm bảo bạn truy cập vào thuộc lengthtính của kích thước phù hợp. Lấy mã sau đây làm ví dụ:

int [][][] a  = new int [2][3][4];

for(int i = 0; i < a.length; i++){
    for(int j = 0; j < a[i].length; j++){
        for(int k = 0; k < a[j].length; k++){
            System.out.print(a[i][j][k]);
        }
        System.out.println();
    }
    System.out.println();
}

Mỗi kích thước có một chiều dài khác nhau, do đó, lỗi tinh tế là các vòng ở giữa và bên trong sử dụng thuộc lengthtính của cùng một chiều (vì a[i].lengthgiống như a[j].length).

Thay vào đó, vòng lặp bên trong nên sử dụng a[i][j].length(hoặc a[0][0].length, để đơn giản).


Đã thêm một ví dụ mã từ Tại sao vòng lặp for của tôi không hoạt động khi tôi thay đổi điều kiện (mảng nhiều chiều)? vì câu hỏi này được sử dụng làm mục tiêu lừa đảo cho bất kỳ câu hỏi nào liên quan đến ArrayIndexOutOfBoundException.
Bill Lizard

2

Trường hợp phổ biến nhất tôi từng thấy đối với Array IndexOutOfBoundExceptions dường như bí ẩn, nghĩa là dường như không phải do mã xử lý mảng của riêng bạn, là việc sử dụng đồng thời SimpleDateFormat. Đặc biệt trong một servlet hoặc bộ điều khiển:

public class MyController {
  SimpleDateFormat dateFormat = new SimpleDateFormat("MM/dd/yyyy");

  public void handleRequest(ServletRequest req, ServletResponse res) {
    Date date = dateFormat.parse(req.getParameter("date"));
  }
}

Nếu hai luồng kết hợp phương thức SimplateDateFormat.parse () với nhau, bạn có thể sẽ thấy một ArrayIndexOutOfBoundException. Lưu ý phần đồng bộ hóa của lớp javadoc cho SimpleDateFormat .

Hãy chắc chắn rằng không có chỗ nào trong mã của bạn đang truy cập các lớp không an toàn của luồng như SimpleDateFormat theo cách đồng thời như trong một servlet hoặc trình điều khiển. Kiểm tra tất cả các biến đối tượng của servlets và bộ điều khiển của bạn để tìm các nghi phạm có khả năng.


2

ArrayIndexOutOfBoundException bất cứ khi nào có ngoại lệ này xảy ra, điều đó có nghĩa là bạn đang cố gắng sử dụng một chỉ mục của mảng nằm ngoài giới hạn của nó hoặc theo thuật ngữ giáo dân mà bạn yêu cầu nhiều hơn bạn đã khởi tạo.

Để ngăn chặn điều này luôn đảm bảo rằng bạn không yêu cầu một chỉ mục không có trong mảng tức là nếu độ dài mảng là 10 thì chỉ mục của bạn phải nằm trong khoảng từ 0 đến 9


2

ArrayIndexOutOfBound có nghĩa là bạn đang cố gắng lập chỉ mục một vị trí trong một mảng không được phân bổ.

Trong trường hợp này:

String[] name = { "tom", "dick", "harry" };
for (int i = 0; i <= name.length; i++) {
    System.out.println(name[i]);
}
  • name.length là 3 vì mảng đã được xác định với 3 đối tượng String.
  • Khi truy cập nội dung của một mảng, vị trí bắt đầu từ 0. Vì có 3 mục, có nghĩa là tên [0] = "tom", tên [1] = "tinh ranh" và tên [2] = "harry
  • Khi bạn lặp, vì tôi có thể nhỏ hơn hoặc bằng name.length, bạn đang cố truy cập tên [3] không khả dụng.

Để giải quyết vấn đề này ...

  • Trong vòng lặp for của bạn, bạn có thể thực hiện i <name.length. Điều này sẽ ngăn việc lặp sang tên [3] và thay vào đó sẽ dừng ở tên [2]

    for(int i = 0; i<name.length; i++)

  • Sử dụng một cho mỗi vòng lặp

    String[] name = { "tom", "dick", "harry" }; for(String n : name) { System.out.println(n); }

  • Sử dụng list.forEach (Hành động của người tiêu dùng) (yêu cầu Java8)

    String[] name = { "tom", "dick", "harry" }; Arrays.asList(name).forEach(System.out::println);

  • Chuyển đổi mảng thành luồng - đây là một tùy chọn tốt nếu bạn muốn thực hiện các 'thao tác' bổ sung cho mảng của mình, ví dụ: bộ lọc, chuyển đổi văn bản, chuyển đổi thành bản đồ, v.v. (yêu cầu Java8)

    String[] name = { "tom", "dick", "harry" }; --- Arrays.asList(name).stream().forEach(System.out::println); --- Stream.of(name).forEach(System.out::println);


1

ArrayIndexOutOfBoundsExceptioncó nghĩa là bạn đang cố gắng truy cập vào một chỉ mục của mảng không tồn tại hoặc nằm ngoài giới hạn của mảng này. Các chỉ mục mảng bắt đầu từ 0 và kết thúc ở độ dài - 1 .

Trong trường hợp của bạn

for(int i = 0; i<=name.length; i++) {
    System.out.print(name[i] +'\n'); // i goes from 0 to length, Not correct
}

ArrayIndexOutOfBoundsExceptionxảy ra khi bạn đang cố truy cập phần tử được lập chỉ mục name.length không tồn tại (chỉ mục mảng kết thúc ở độ dài -1). chỉ cần thay thế <= bằng <sẽ giải quyết vấn đề này.

for(int i = 0; i < name.length; i++) {
    System.out.print(name[i] +'\n');  // i goes from 0 to length - 1, Correct
}

1

Đối với bất kỳ mảng nào có độ dài n, các phần tử của mảng sẽ có chỉ số từ 0 đến n-1.

Nếu chương trình của bạn đang cố truy cập vào bất kỳ phần tử (hoặc bộ nhớ) nào có chỉ số mảng lớn hơn n-1, thì Java sẽ ném ArrayIndexOutOfBoundException

Vì vậy, đây là hai giải pháp mà chúng ta có thể sử dụng trong một chương trình

  1. Duy trì số lượng:

    for(int count = 0; count < array.length; count++) {
        System.out.println(array[count]);
    }

    Hoặc một số câu lệnh lặp khác như

    int count = 0;
    while(count < array.length) {
        System.out.println(array[count]);
        count++;
    }
  2. Một cách tốt hơn đi với một vòng lặp cho mỗi vòng lặp, trong phương pháp này, một lập trình viên không cần phải bận tâm về số lượng phần tử trong mảng.

    for(String str : array) {
        System.out.println(str);
    }

1

Theo mã của bạn:

String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<=name.length; i++) {
  System.out.print(name[i] +'\n');
}

Nếu bạn kiểm tra System.out.print (name.length);

bạn sẽ nhận được 3;

điều đó có nghĩa là chiều dài tên của bạn là 3

vòng lặp của bạn đang chạy từ 0 đến 3, nên chạy "0 đến 2" hoặc "1 đến 3"

Câu trả lời

String[] name = {"tom", "dick", "harry"};
for(int i = 0; i<name.length; i++) {
  System.out.print(name[i] +'\n');
}

1

Mỗi mục trong một mảng được gọi là một phần tử và mỗi phần tử được truy cập bằng chỉ mục số của nó. Như thể hiện trong hình minh họa trước, đánh số bắt đầu bằng 0 . Do đó, phần tử thứ 9 sẽ được truy cập tại chỉ mục 8.

IndexOutOfBoundException được đưa ra để chỉ ra rằng một chỉ mục nào đó (chẳng hạn như một mảng, cho một chuỗi hoặc cho một vectơ) nằm ngoài phạm vi.

Bất kỳ mảng X, có thể được truy cập từ [0 đến (X.length - 1)]


1

Tôi thấy tất cả các câu trả lời ở đây giải thích cách làm việc với mảng và cách tránh chỉ số ra khỏi giới hạn ngoại lệ. Cá nhân tôi tránh mảng bằng mọi giá. Tôi sử dụng các lớp Bộ sưu tập, để tránh tất cả sự điên cuồng khi phải xử lý hoàn toàn các chỉ số mảng. Các cấu trúc lặp hoạt động rất đẹp với các bộ sưu tập hỗ trợ mã vừa dễ viết, hiểu và duy trì.


1

Nếu bạn sử dụng độ dài của một mảng để điều khiển vòng lặp for , hãy luôn nhớ rằng chỉ mục của mục đầu tiên trong một mảng là 0 . Vì vậy, chỉ mục của phần tử cuối cùng trong một mảng nhỏ hơn một chiều dài của mảng.


0

ArrayIndexOutOfBoundsException Tên chính nó giải thích rằng Nếu bạn cố gắng truy cập giá trị tại chỉ mục nằm ngoài phạm vi kích thước Mảng thì loại ngoại lệ đó sẽ xảy ra.

Trong trường hợp của bạn, Bạn chỉ có thể xóa dấu bằng khỏi vòng lặp for của mình.

for(int i = 0; i<name.length; i++)

Tùy chọn tốt hơn là lặp lại một mảng:

for(String i : name )
      System.out.println(i);

0

Lỗi này xảy ra tại thời gian chạy vòng lặp quá mức. Hãy xem xét ví dụ đơn giản như thế này,

class demo{
  public static void main(String a[]){

    int[] numberArray={4,8,2,3,89,5};

    int i;

    for(i=0;i<numberArray.length;i++){
        System.out.print(numberArray[i+1]+"  ");
    }
}

Lúc đầu, tôi đã khởi tạo một mảng là 'numberArray'. sau đó, một số phần tử mảng được in bằng vòng lặp for. Khi vòng lặp đang chạy 'i' time, hãy in phần tử (numberArray [i + 1] .. (khi giá trị i là 1, phần tử numberArray [i + 1] được in.) Giả sử rằng, khi i = (numberArray. length-2), phần tử cuối cùng của mảng được in..Khi giá trị 'i' chuyển sang (numberArray.length-1), không có giá trị để in..Trong thời điểm đó, 'ArrayIndexOutOfBoundException' xảy ra. Tôi hy vọng bạn có thể nhận được ý tưởng. Cảm ơn bạn!


0

Bạn có thể sử dụng Tùy chọn theo kiểu chức năng để tránh NullPointerExceptionArrayIndexOutOfBoundsException:

String[] array = new String[]{"aaa", null, "ccc"};
for (int i = 0; i < 4; i++) {
    String result = Optional.ofNullable(array.length > i ? array[i] : null)
            .map(x -> x.toUpperCase()) //some operation here
            .orElse("NO_DATA");
    System.out.println(result);
}

Đầu ra:

AAA
NO_DATA
CCC
NO_DATA

-4

Bạn không thể lặp hoặc lưu trữ nhiều dữ liệu hơn độ dài của mảng. Trong trường hợp này bạn có thể làm như thế này:

for (int i = 0; i <= name.length - 1; i++) {
    // ....
}

Hoặc này:

for (int i = 0; i < name.length; i++) {
    // ...
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.