web-dev-qa-db-ja.com

Java.lang.ArrayIndexOutOfBoundsExceptionの原因は何ですか。どのようにしてそれを回避できますか?

ArrayIndexOutOfBoundsExceptionはどういう意味ですか?どうやってそれを取り除くのですか?

これは、例外を引き起こすコードサンプルです。

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

あなたの最初の寄港地は documentation であるべきです。

配列が不正なインデックスでアクセスされたことを示すためにスローされます。インデックスは、負であるか、配列のサイズ以上です。

だから、例えば:

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

それを避ける方法については…えーと、そうしないでください。配列インデックスに注意してください。

人々が遭遇することがある1つの問題は、配列が1添字であると考えることです。

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

これは最初の要素(index 0)を見逃し、indexが5のときに例外を投げます。ここでの有効なインデックスは0から4です。ここでの正しい、慣用句のforステートメントは次のようになります。

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

(もちろん、インデックスをneedと仮定しています。代わりにenhanced forループを使用できる場合は、そうしてください。)

262
Jon Skeet
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];
}

また見なさい:


更新 :あなたのコードスニペットに従って

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

インデックスは配列の長さを含みます。これは範囲外です。 <=<に置き換える必要があります。

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

簡単に言うと:

の最後の繰り返しで

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

配列インデックスは0から始まるため、iname.lengthと等しくなります。これは不正なインデックスです。

あなたのコードは読むべきです

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

境界の間にないので無効な配列のインデックスにアクセスしようとしています。

たとえば、これは上限4でプリミティブ整数配列を初期化します。

int intArray[] = new int[5];

プログラマはゼロから数えます。したがって、これは、上限が5ではなく4であるため、たとえばArrayIndexOutOfBoundsExceptionをスローします。

intArray[5];
16

何がArrayIndexOutOfBoundsExceptionを引き起こしますか?

変数を値を配置できる「ボックス」と考えると、配列は隣同士に配置された一連のボックスで、ボックスの数は有限かつ明示的な整数です。

このような配列を作る:

final int[] myArray = new int[5]

それぞれがintを保持する5つのボックスからなる行を作成します。各箱にはインデックス、つまり一連の箱の中の位置があります。このインデックスは0から始まり、N-1で終わります。Nは配列のサイズ(ボックスの数)です。

この一連のボックスから値の1つを取得するには、次のようにインデックスを通してそれを参照できます。

myArray[3]

これにより、シリーズの4番目のボックスの値がわかります(最初のボックスのインデックスは0です)。

ArrayIndexOutOfBoundsExceptionは、最後の "box"のインデックスよりも高いインデックス、または負の値を渡すことによって、存在しない "box"を再試行しようとしたことが原因です。

私の実行中の例では、これらのコードスニペットはそのような例外を生成します:

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

ArrayIndexOutOfBoundsExceptionを回避する方法

ArrayIndexOutOfBoundsExceptionを防ぐために、考慮すべきいくつかの重要なポイントがあります。

ループ

配列をループ処理するときは、取得しているインデックスが配列の長さ(ボックスの数)より厳密に小さいことを必ず確認してください。例えば:

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

<に注意してください。そこに=を混ぜないでください。

このようなことをしたくなるかもしれません。

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

しないでください。上のものに固執すると(インデックスを使う必要がある場合)、それはあなたに多くの苦痛を救うでしょう。

可能であれば、foreachを使ってください。

for (int value : myArray) {

こうすれば、インデックスについて考える必要がまったくなくなります。

ループするときは、ループイテレータの値を変更しないでください(ここではi)。これが値を変えるべき唯一の場所はループを続けていくことです。そうでなければそれを変更することは単に例外の危険を冒すことであり、そしてほとんどの場合必要ではない。

検索/更新

配列の任意の要素を取得するときは、それが配列の長さに対して有効なインデックスであることを常に確認してください。

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];
}
10
Tobb

配列インデックスの範囲外の例外を回避するには、 enhanced -for ステートメントを使用できる場所とタイミングで使用する必要があります。

主な動機(およびユースケース)は、反復しているときで、複雑な反復ステップを必要としないときです。あなたはnotが配列の中で後方に移動するために拡張された-forを使うことができるか、または他のすべての要素に対してだけ繰り返すことができるでしょう。

これを行うときに繰り返すために要素を使い果たしないことが保証されています、そしてあなたの[修正された]例は簡単に変換されます。

以下のコード

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

...はこれと同じです。

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

コードでは、インデックス0から文字列配列の長さまでの要素にアクセスしています。 name.lengthは、文字列オブジェクトの配列内の文字列オブジェクトの数、つまり3を示しますが、配列はインデックス0からname[2]にアクセスできるため、インデックス2 name.length - 1までしかアクセスできません。 name.length個のオブジェクトを取得します。

forループを使用していても、インデックス0で開始しているため、name.length - 1で終了する必要があります。配列a [n]では、フォームa [0]からa [n-1]にアクセスできます。

例えば:

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

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

あなたの場合:

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

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

与えられた配列では、配列の長さは3です(つまり、name.length = 3)。しかし、インデックス0から始まる要素を格納するので、最大インデックス2を持ちます。

そのため、 'i ** <= name.length'の代わりに 'i <** name.length'と記述して 'ArrayIndexOutOfBoundsException'を回避する必要があります。

4
nIKHIL

この単純な質問では、これだけですが、初心者でも配列内のインデックス付けに関する混乱を避けるためのJavaの新機能を強調したいと思いました。 Java-8はあなたのために繰り返すというタスクを抽象化しました。

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]); })

利点は何ですか?えーと、一つは英語のような読みやすさです。次に、ArrayIndexOutOfBoundsExceptionについて心配する必要はありません。

3
Satyendra Kumar

Array index out of bounds exception

そういうわけで、Eclipseでこのタイプの例外がスローされます。赤の数字はアクセスしようとしたインデックスを表します。そのため、コードは次のようになります。

myArray[5]

その配列に存在しないインデックスにアクセスしようとすると、エラーがスローされます。配列の長さが3の場合、

int[] intArray = new int[3];

その場合、唯一有効なインデックスは次のとおりです。

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

配列の長さが1の場合、

int[] intArray = new int[1];

その場合、唯一の有効なインデックスは次のとおりです。

intArray[0]

配列の長さに等しい、またはそれよりも大きい整数は、範囲外です。

0より小さい整数は範囲外です。

P.S .:もしあなたが配列についてもっとよく理解していて、そしていくつかの実用的な演習をするように見えるならば、ここにビデオがあります: Javaにおける配列に関するチュートリアル

3
Ion

i<=name.lengthの部分が原因でArrayIndexOutOfBoundsExceptionを取得しています。 name.lengthは、文字列nameの長さ(3)を返します。したがって、name[3]にアクセスしようとすると、不正であり、例外がスローされます。

解決されたコード

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

Java言語仕様で定義されています

public finalフィールドlength。これには、配列の構成要素の数が入ります。 lengthは正またはゼロです。

3
roottraveller

ArrayIndexOutOfBoundsExceptionこの例外が発生するたびに、範囲外の配列のインデックスを使用しようとしているか、または初期化した以上のものを要求しています。

これを防ぐには、配列に存在しないインデックスを要求していないことを常に確認してください。つまり、配列の長さが10の場合、インデックスは0から9の範囲でなければなりません。

2
sgrpwr

ArrayIndexOutOfBoundsは、割り当てられていない配列内の位置にインデックスを付けようとしていることを意味します。

この場合:

String[] name = { "tom", "dick", "harry" };
for (int i = 0; i <= name.length; i++) {
    System.out.println(name[i]);
}
  • 配列は3つのStringオブジェクトで定義されているため、name.lengthは3です。
  • 配列の内容にアクセスする場合、位置は0から始まります。項目が3つあるため、name [0] = "tom"、name [1] = "dick"、name [2] = "harryとなります
  • ループすると、 i はname.length以下になる可能性があるため、利用できないname [3]にアクセスしようとしています。

これを回避するには.

  • Forループでは、i <name.lengthを実行できます。これはname [3]へのループを防ぎ、代わりにname [2]で止まります。

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

  • 各ループにaを使用

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

  • List.forEach(Consumer action)を使用してください(Java8が必要です)

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

  • 配列をストリームに変換 - これはあなたの配列に追加の '操作'を実行したい場合に適したオプションです。フィルタ、テキストの変換、マップへの変換など(Java 8が必要)

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

2
martinywwan

一見不思議なArrayIndexOutOfBoundsExceptionsのために私が見た最も一般的なケース、すなわち明らかにあなた自身の配列処理コードによって引き起こされない、はSimpleDateFormatの同時使用です。特にサーブレットやコントローラでは:

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

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

2つのスレッドがSimplateDateFormat.parse()メソッドを一緒に入力すると、おそらくArrayIndexOutOfBoundsExceptionが発生します。 SimpleDateFormatの クラスjavadocの同期セクションに注目してください

コード内に、SimpleDateFormatのようなスレッドセーフでないクラスにサーブレットやコントローラのように並行してアクセスする場所がないことを確認してください。サーブレットとコントローラのすべてのインスタンス変数に疑いがあるかどうかを確認してください。

2
Kyri Sarantakos

多次元配列の場合、正しい次元のlengthプロパティにアクセスするようにするのは難しいかもしれません。例えば次のようなコードを見てください。

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();
}

各次元は長さが異なります。したがって、微妙なバグは、中間ループと内部ループが同じ次元のlengthプロパティを使用することです(a[i].lengtha[j].lengthと同じであるため)。

代わりに、内側のループはa[i][j].length(または単純にするためにa[0][0].length)を使用するべきです。

2
Bill the Lizard

ArrayIndexOutOfBoundsExceptionは、存在しないか、この配列の範囲外にある配列のインデックスにアクセスしようとしていることを意味します。配列インデックスは 0 から始まり length - 1 で終わります。

あなたの場合

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

ArrayIndexOutOfBoundsExceptionは、存在しないname.lengthインデックス付き要素にアクセスしようとしたときに発生します(配列インデックスは長さ-1で終わります)。 <=を<に置き換えるだけでこの問題を解決できます。

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

配列内の各項目は要素と呼ばれ、各要素はその数値インデックスによってアクセスされます。前の図に示されているように、 番号付けは0 で始まります。たとえば、9番目の要素は、インデックス8でアクセスされます。

IndexOutOfBoundsExceptionは、ある種のインデックス(配列、文字列、ベクトルなど)が範囲外であることを示すためにスローされます。

任意の配列X、[0から(X.length - 1)]までアクセス可能

1
ZiadM

for ループの繰り返しを制御するために配列の長さを使用する場合は、常に配列の最初の項目のインデックスが 0 であることを忘れないでください。そのため、配列の最後の要素のインデックスは、配列の長さより1つ小さくなります。

1

長さnの任意の配列に対して、配列の要素は0からn-1までのインデックスを持ちます。

プログラムがn-1より大きい配列インデックスを持つ要素(またはメモリ)にアクセスしようとすると、Javaは ArrayIndexOutOfBoundsException をスローします。

だからここで私たちがプログラムで使用できる2つの解決策があります

  1. 維持数:

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

    または他のループ文

    int count = 0;
    while(count < array.length) {
        System.out.println(array[count]);
        count++;
    }
    
  2. この方法では、プログラマは配列内の要素数を気にする必要はありません。

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

あなたのコードによると:

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

System.out.print(name.length)をチェックした場合

あなたは3を得るでしょう。

つまり、あなたの名前の長さは3です。

あなたのループは0から3まで走っていて、それは "0から2"か "1から3"のどちらかを走らせるべきです

答え

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

ここですべての答えを見て、配列を操作する方法と、インデックスが範囲外の例外を回避する方法を説明します。私は個人的にはどうしても配列を避けます。私はCollectionsクラスを使用します。これは配列インデックスを完全に処理しなければならないという面倒なことをすべて回避します。ループ構造は、記述、理解、および保守がより簡単なコードをサポートするコレクションとうまく連携します。

1

ArrayIndexOutOfBoundsExceptionの名前自体は、配列サイズの範囲外のインデックスの値にアクセスしようとすると、そのような例外が発生することを説明しています。

あなたのケースでは、あなたはちょうどあなたのforループから等号を削除することができます。

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

より良い方法は配列を繰り返すことです。

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

このエラーは、実行ループが制限時間を超えたときに発生します。このような単純な例を考えてみましょう。

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]+"  ");
    }
}

最初、配列を 'numberArray'として初期化しました。それから、いくつかの配列要素はforループを使って表示されます。ループが 'i'回実行されているとき、(numberArray [i + 1]要素..(i値が1のとき、numberArray [i + 1]要素が印刷される)を出力します。 length-2)、配列の最後の要素が印刷されます。 'i'値が(numberArray.length-1)になると、印刷するための値はありません。よろしくお願いします。

0
GT_hash