何がjava.lang.ArrayIndexOutOfBoundsExceptionを引き起こし、どうやってそれを防ぐのですか?


298

どういうArrayIndexOutOfBoundsException意味ですか、どうすれば取り除くことができますか?

例外をトリガーするコードサンプルを次に示します。

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

1
最後の質問を参照して、コードが役立つでしょう。既知のインデックスを持つ配列にアクセスしていますか、またはエラーが発生したときにインデックスがどのように計算されるかを理解するためにデバッグを開始する必要がありますか?
justkt

43
-またはそれ以上に置き換えi <= name.lengthi < name.length、拡張forループを記述します。(for (String aName : name) { ... }
Jean Hominal

1
これは、存在しない配列の要素を取得することを意味します。「i <= name.length」は、要素の長さ+1を取得することを意味します-存在しません。
gbk 2013


回答:


296

最初の呼び出しポートはドキュメントでなければなりませんそれを合理的に明確に説明で。

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

だから例えば:

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

これにより、最初の要素(インデックス0)が失われ、インデックスが5の場合に例外がスローされます。ここでの有効なインデックスは0〜4です。ここでの正しい、慣用的なforステートメントは次のようになります。

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

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


1
Javaで任意の形状を持つ可能性のある多次元配列の場合、ネストされたループは関連するサブ配列の長さをチェックする必要があることを追加します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];
}

以下も参照してください。


更新:コードスニペットに従って、

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

インデックスには配列の長さが含まれます。これは範囲外です。あなたは交換する必要がある<=ことで<

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

22

この優れた記事から:forループでのArrayIndexOutOfBoundsException

簡単に言うと:

の最後の反復で

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

i等しくなるname.length配列のインデックスは、ゼロベースであるため、不正指標です。

あなたのコードは

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

17

これは、境界の間にないため無効な配列のインデックスにアクセスしようとしていることを意味します。

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

int intArray[] = new int[5];

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

intArray[5];

4
境界は範囲内の制限です。すなわち; 0-5
ジョンジョッタ

11

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

主な動機(および使用例)は、反復処理を行っているときに複雑な反復ステップを必要としない場合です。あなたはなりません enhanced-を使用することができます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");
}

11

何が原因ArrayIndexOutOfBoundsExceptionですか?

変数を値を配置できる「ボックス」と考える場合、配列は互いに隣り合って配置された一連のボックスであり、ボックスの数は有限で明示的な整数です。

次のような配列を作成します。

final int[] myArray = new int[5]

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

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

myArray[3]

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

ArrayIndexOutOfBoundsException最後に、「ボックス」、または負の屈折率より高いインデックスを渡すことによって、存在しない「ボックス」をretriveしようとによって引き起こされます。

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

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

6

コードでは、インデックス0から文字列配列の長さまでの要素にアクセスしました。name.length文字列オブジェクトの配列内の文字列オブジェクトの数、つまり3を示しますがname[2]、配列はインデックス0からオブジェクトの数name.length - 1を取得する場所までアクセスできるため、インデックス2までしかアクセスできません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」を回避する必要があります。


3

この単純な質問はこれで終わりですが、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

あなたは一部のArrayIndexOutOfBoundsExceptionために得ていi<=name.lengthます。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

配列インデックスの範囲外例外

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

myArray[5]

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

int[] intArray = new int[3];

有効なインデックスは次のとおりです。

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

配列の長さが1の場合

int[] intArray = new int[1];

有効なインデックスは次のとおりです。

intArray[0]

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

0未満の整数:範囲外です。

PS:配列の理解を深め、実際的な演習を行う場合は、こちらのビデオ(Javaでの配列に関するチュートリアル)をご覧ください。


3

多次元配列の場合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].length同じであるためa[j].length)。

代わりに、内部ループを使用する必要がありますa[i][j].length(またはa[0][0].length、簡単にするために)。


以下からのコード例を追加しました私は、条件(多次元配列)を変更するときに私がループのために動作しないのはなぜか?この質問は、ArrayIndexOutOfBoundsExceptionを処理する質問の重複ターゲットとして使用されるためです。
トカゲに請求する

2

見たところ謎のように見える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

ArrayIndexOutOfBoundsExceptionは、この例外が発生するたびに、境界を超えた配列のインデックスを使用しようとしていることを意味します。

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


2

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++)

  • for eachループを使用する

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

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

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


1

ArrayIndexOutOfBoundsException存在しない、またはこの配列の範囲外の配列のインデックスにアクセスしようとしていることを意味します。配列インデックスは0から始まり、長さ-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

長さ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 eachループを使用するより良い方法は、この方法では、プログラマーが配列の要素数を気にする必要がないことです。

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

1

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

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

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

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

[0から(X.length-1)]までの任意の配列Xにアクセスできます


1

配列の操作方法とインデックスが範囲外の例外を回避する方法を説明するすべての答えがここにあります。個人的には、アレイを絶対に避けます。私はコレクションクラスを使用します。これにより、配列のインデックスを完全に処理する必要があるすべての愚かなことを回避できます。ループ構造は、記述、理解、維持の両方が簡単なコードをサポートするコレクションで見事に機能します。


1

配列の長さを使用してforループの反復を制御する場合、配列の最初の項目のインデックスは0であることを常に覚えておいてください。したがって、配列の最後の要素のインデックスは、配列の長さよりも1つ少なくなります。


0

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)に移動すると、出力する値はありません。その時点で「ArrayIndexOutOfBoundsException」が発生します。 idea。ありがとうございます!


0

あなたは回避するために機能的なスタイルでオプションを使用することができます NullPointerExceptionし、ArrayIndexOutOfBoundsException

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

出力:

AAA
NO_DATA
CCC
NO_DATA

-4

配列の長さを超えるデータを反復または格納することはできません。この場合、次のようにすることができます。

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

またはこれ:

for (int i = 0; i < name.length; i++) {
    // ...
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.