java.lang.ArrayIndexOutOfBoundsExceptionの原因とそれを防ぐにはどうすればよいですか?
どういうArrayIndexOutOfBoundsException
意味ですか、どうすればそれを取り除くことができますか?
例外をトリガーするコードサンプルを次に示します。
String[] names = { "tom", "bob", "harry" };
for (int i = 0; i <= names.length; i++) {
System.out.println(names[i]);
}
回答
最初の寄港地は、それを合理的に明確に説明する文書でなければなりません。
配列が不正なインデックスでアクセスされたことを示すためにスローされます。インデックスは負であるか、配列のサイズ以上です。
したがって、たとえば:
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ループを使用できる場合は、そうしてください。)
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];
}
参照:
- Javaチュートリアル-言語の基本-配列
更新:コードスニペットに従って、
for (int i = 0; i<=name.length; i++) {
インデックスには、配列の長さが含まれます。これは範囲外です。あなたは交換する必要がある<=
ことで<
。
for (int i = 0; i < name.length; i++) {
この優れた記事から:forループのArrayIndexOutOfBoundsException
簡単に言えば:
の最後の反復で
for (int i = 0; i <= name.length; i++) {
i
等しくなるname.length
配列のインデックスは、ゼロベースであるため、不正指標です。
あなたのコードは読むべきです
for (int i = 0; i < name.length; i++)
^
これは、境界の間にないために無効な配列のインデックスにアクセスしようとしていることを意味します。
たとえば、これは上限4でプリミティブ整数配列を初期化します。
int intArray[] = new int[5];
プログラマーはゼロから数えます。したがって、これは、たとえばArrayIndexOutOfBoundsException
、上限が5ではなく4であるため、をスローします。
intArray[5];
配列インデックスの範囲外の例外を回避するには、可能な場合はいつでも、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");
}
何が原因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];
}
コードでは、インデックス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');
}
指定された配列の場合、配列の長さは3です(つまり、name.length = 3)。ただし、インデックス0から始まる要素を格納するため、最大インデックスは2になります。
したがって、「ArrayIndexOutOfBoundsException」を回避するには、「i ** <= name.length」の代わりに「i <** name.length」と記述する必要があります。
この簡単な質問についてはこれだけですが、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
あなたは一部の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
正またはゼロの場合があります。
これが、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の配列に関するチュートリアル
多次元配列の場合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
、簡単にするために)を使用する必要があります。
一見不思議な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のようなスレッドセーフでないクラスに同時にアクセスする場所がコード内にないことを確認してください。サーブレットとコントローラのすべてのインスタンス変数をチェックして、疑わしい可能性がないか確認します。
ArrayIndexOutOfBoundsExceptionこの例外が発生するたびに、範囲外の配列のインデックスを使用しようとしていること、または一般の用語で、初期化した以上に要求していることを意味します。
これを防ぐには、配列に存在しないインデックスを要求していないことを常に確認してください。つまり、配列の長さが10の場合、インデックスの範囲は0〜9である必要があります。
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++)
foreachループを使用する
String[] name = { "tom", "dick", "harry" }; for(String n : name) { System.out.println(n); }
list.forEach(消費者アクション)を使用します(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);
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
}
長さnの配列の場合、配列の要素のインデックスは0からn-1になります。
プログラムが配列インデックスがn-1より大きい要素(またはメモリ)にアクセスしようとすると、JavaはArrayIndexOutOfBoundsExceptionをスローします。
プログラムで使用できる2つのソリューションがあります
カウントの維持:
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++; }
for eachループを使用する方が良い方法です。この方法では、プログラマーは配列内の要素の数を気にする必要がありません。
for(String str : array) { System.out.println(str); }
あなたのコードによると:
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');
}
配列内の各項目は要素と呼ばれ、各要素はその数値インデックスによってアクセスされます。前の図に示されているように、番号付けは0から始まります。したがって、たとえば9番目の要素はインデックス8でアクセスされます。
IndexOutOfBoundsExceptionは、ある種のインデックス(配列、文字列、ベクトルなど)が範囲外であることを示すためにスローされます。
任意の配列Xは、[0から(X.length-1)]までアクセスできます。
配列を操作する方法と、インデックスの範囲外の例外を回避する方法を説明するすべての回答がここに表示されます。私は個人的にアレイを絶対に避けています。私はCollectionsクラスを使用します。これにより、配列インデックスを完全に処理する必要があるという愚かなことをすべて回避できます。ループ構造は、記述、理解、および保守の両方が容易なコードをサポートするコレクションで美しく機能します。
配列の長さを使用してforループの反復を制御する場合は、配列の最初の項目のインデックスが0であることを常に覚えておいてください。したがって、配列の最後の要素のインデックスは、配列の長さより1つ短くなります。
ArrayIndexOutOfBoundsException
名前自体は、配列サイズの範囲外のインデックスの値にアクセスしようとすると、そのような種類の例外が発生することを説明しています。
あなたの場合、forループから等号を削除するだけです。
for(int i = 0; i<name.length; i++)
より良いオプションは、配列を反復することです。
for(String i : name )
System.out.println(i);
このエラーは、実行ループの超過時間で発生します。次のような簡単な例を考えてみましょう。
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]要素が出力されます。)。i =(numberArray。 length-2)、配列の最後の要素が出力されます。「i」の値が(numberArray.length-1)になると、出力の値がなくなります。その時点で、「ArrayIndexOutOfBoundsException」が発生します。 idea.thank you!
あなたは回避するために、機能的なスタイルでオプションを使用することができます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