文字列切り取り関数である「substring」使用時のエラーの原因と回避方法のまとめです。

目次


java.lang.NullPointerException

NullPointerExceptionいわゆるヌルポが発生する場合、substringを仕掛けるオブジェクトが「null」(設定されていない)になっています。

例1:関数の戻り値が「null」

String s = getValue();
s = s.substring(1, 2);
 
「getValue」関数の戻り値が「null」の場合「NullPointerException」が発生します。

対策1-1:substringの直前にチェックを入れる

String s = getValue();
if (s != null) {
  s = s.substring(1, 2);
}
 
「getValue」の戻り値がnullでない場合だけsubstringを行うようチェックを追加しました。
実際には「戻り値がnullだった場合にはどうすべきか」というのも考えなければいけません。

対策1-2:「getValue」関数の戻り値がnullにならないようにする

String getValue() {
  String ret = null;
// ・・・関数の処理・・・
  if (ret == null) {
    return "retがnullの場合の値";
  } else {
    return ret;
  }
}
 
「getValue」が戻り値を返すところにチェックを挿入し、戻り値がnullの場合規定の値を返却するよう修正しました。
「直前の関数がnullを返さない」と分かっていればsubstringの直前にnullチェックする必要はありません。

対策1-3:エラー処理を行う

try {
  String s = getValue();
  s = s.substring(1, 2);
} catch(Exception e) {
  // ・・・エラー処理・・・
}
 
「getValue」の戻り値がnullだったらエラーになってOK、エラー処理をしてしまえ!という対策です。
この場合「nullチェックしてnullだったらエラーを投げる」の方がよいのかもしれません。

例2:if文の通り具合で「null」になる場合

String s = null;
if (getHanteiKekka()) {
  // ・・・判定結果がtrueの場合の処理・・・
  s = "hogehoge";
} else {
  // ・・・判定結果がfalseの場合の処理・・・
}
s = s.substring(1, 2);
 
「getHanteiKekka」の戻り値がfalseの場合、「s」に値が設定されず「NullPointerException」が発生します。

対策2-1:すべてのif文のルートでもれなく値を設定する

String s = null;
if (getHanteiKekka()) {
  // ・・・判定結果がtrueの場合の処理・・・
  s = "hogehoge";
} else {
  // ・・・判定結果がfalseの場合の処理・・・
  s = "mogemoge";
}
s = s.substring(1, 2);
 
「判定結果がfalseの場合の処理」にも値を設定するように修正したので「NullPointerException」が発生しません。
今回の例ではif文のルートが2通りでしたが、if文が大量にあってルートを網羅しきれない場合はsubstringの直前でチェックするしかないでしょう。

対策2-2:substringの直前にチェックを入れる

対策1-1と同じなのでコードは省略します。

対策2-3:エラー処理を行う

対策1-3と同じなのでコードは省略します。

java.lang.StringIndexOutOfBoundsException: String index out of range: xxx

オブジェクトの文字数が足りない場合のエラーです。
対策は「NullPointerException」の対策に+αの形になります。

例1:関数の戻り値が短い

String s = getValue();
s = s.substring(1, 2);
 
この例では「getValue」関数の戻り値が0~1文字の場合「StringIndexOutOfBoundsException」が発生します。
2文字以上であれば例外は発生しません。

対策1-1:文字数チェックをする

String s = getValue();
if (s != null && s.length() >= 2) {
  s = s.substring(1, 2);
}
 
「sがnull以外かつ2文字以上の場合」にsubstringを行うように修正しました。
nullチェックを入れているのは、sがnullだと「length」の方でエラーになる可能性があるためです。

対策1-2:「getValue」関数の戻り値が2文字以下にならないようにする

String getValue() {
  String ret = null;
// ・・・関数の処理・・・
  if (ret == null || ret.length() <= 1) {
    return "retがnullまたは1文字以下の場合の値";
  } else {
    return ret;
  }
}
 
こちらも「NullPointerException」の例に+αした内容ですが「戻り値がnullまたは1文字以下の場合」に規定の値を返すように修正してあります。

対策1-3:エラー処理を行う

try {
  String s = getValue();
  s = s.substring(1, 2);
} catch(Exception e) {
  // ・・・エラー処理・・・
}
 
「getValue」の戻り値が1文字だったらエラーになってOK、エラー処理をしてしまえ!という対策です。
「NullPointerException」の例と同じです。

例2:if文の通り具合で文字数が不足する場合

String s = null;
if (getHanteiKekka()) {
  // ・・・判定結果がtrueの場合の処理・・・
  s = "hogehoge";
} else {
  // ・・・判定結果がfalseの場合の処理・・・
  s = "m";
}
s = s.substring(1, 2);
 
「getHanteiKekka」の戻り値がfalseの場合、「s」が1文字のため例外が発生します。

対策2-1:すべてのif文のルートで文字数が不足するしないように設定する

String s = null;
if (getHanteiKekka()) {
  // ・・・判定結果がtrueの場合の処理・・・
  s = "hogehoge";
} else {
  // ・・・判定結果がfalseの場合の処理・・・
  s = "mogemoge";
}
s = s.substring(1, 2);
 
「判定結果がfalseの場合の処理」にも値を設定するように修正したので例外が発生しません。
今回の例ではif文のルートが2通りでしたが、if文が大量にあってルートを網羅しきれない場合はsubstringの直前でチェックするしかないでしょう。

対策2-2:substringの直前にチェックを入れる

対策1-1と同じなのでコードは省略します。

対策2-3:エラー処理を行う

対策1-3と同じなのでコードは省略します。

例3:第2パラメータより第1パラメータの方が小さい

String s = getValue();
s = s.substring(2, 1);
 
これは「3文字目から1文字切り取り」という意図で記述しやすいコードです。

対策2-1:パラメータを適正な値に変更する

String s = getValue();
s = s.substring(2, 3);
 
「3文字目から1文字切り取り」の場合、パラメータは「2」と「3」が正解です。
これは気合で覚えるしかないです。

例4:第一パラメータが0未満の場合

String s = getValue();
int x = getKaishi();
int n = getMojisuu();
s = s.substring(x, x + n);
 
「xからn文字切り取り」という意図の使い方ですが「x」が0未満の場合にも例外が発生します。
パラメータを何らかの処理で決定している場合に発生しやすい例外です。

対策4-1:substringの直前にチェックを行う

String s = getValue();
int x = getKaishi();
int n = getMojisuu();
if (x >= 0) {
  s = s.substring(x, x + n);
}
 
「x」が0以上の場合にだけsubstringを行うように修正しました。
第2パラメータが「x + n」ではなく「y」などの場合は第2パラメータも含めてチェックを行う必要があります。

対策4-2:0未満の値が設定されないようにする

int getKaishi() {
  int ret = 0;
  // ・・・getKaishiの処理・・・
  if (ret < 0) {
    return 0;
  } else {
    return ret;
  }
}
 
「getKaishi」関数を修正し、戻り値に0未満の値が設定されないようにする対策です。

対策4-3:エラー処理を行う

対策1-3と同じなのでコードは省略します。