はじめに
Integer.parseIntというメソッドをご存知でしょうか?
String型の文字列をint型の数値に変換してくれる便利なやつですね。
とある事情でInteger.parseIntのソースコードを読んでみたので、中身を軽く解説していきたいと思います。
提供されているクラスのソースコードは綺麗なので、読むといろいろ勉強になりますね~。
ソースコード
では早速コードを見てみましょう。
public static int parseInt(String s, int radix)
throws NumberFormatException
{
if (s == null) {
throw new NumberFormatException("null");
}
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
int result = 0;
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
int multmin;
int digit;
if (len > 0) {
char firstChar = s.charAt(0);
if (firstChar < '0') { // Possible leading "+" or "-"
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
if (len == 1) // Cannot have lone "+" or "-"
throw NumberFormatException.forInputString(s);
i++;
}
multmin = limit / radix;
while (i < len) {
// Accumulating negatively avoids surprises near MAX_VALUE
digit = Character.digit(s.charAt(i++),radix);
if (digit < 0) {
throw NumberFormatException.forInputString(s);
}
if (result < multmin) {
throw NumberFormatException.forInputString(s);
}
result *= radix;
if (result < limit + digit) {
throw NumberFormatException.forInputString(s);
}
result -= digit;
}
} else {
throw NumberFormatException.forInputString(s);
}
return negative ? result : -result;
}
長いですね…。
一瞬読むのを躊躇ってしまいます。
ですが、よく見るとシンプルな構造をしているので、ひとつひとつ見ていきましょう!
(まぁそもそも、提供されているクラスのソースコードがぐちゃぐちゃということはないですよね…)
メソッド定義
public static int parseInt(String s, int radix)
throws NumberFormatException
{
まずはメソッド定義の確認をしておきましょう。
戻り値はint型で、引数は2つ、String型の第1引数とint型の第2引数ですね。
第1引数には数値に変換したい文字列を渡し、第2引数には基数を渡してあげます。
基数とは、10進数や2進数といった○進数の○の部分のことです。
Integer.parseInt("10",10) //"10"を10進数で解釈⇒戻り値「10」
Integer.parseInt("10",2) //"10"を2進数で解釈⇒戻り値「2」
Integer.parseInt("10") //第2引数を省略すると10進数で解釈⇒戻り値「10」
引数チェック①
//①文字列がNULLならばエラー出力
if (s == null) {
throw new NumberFormatException("null");
}
//②基数が2未満ならばエラー出力
if (radix < Character.MIN_RADIX) {
throw new NumberFormatException("radix " + radix +
" less than Character.MIN_RADIX");
}
//③基数が36より大きければエラー出力
if (radix > Character.MAX_RADIX) {
throw new NumberFormatException("radix " + radix +
" greater than Character.MAX_RADIX");
}
続いて、if文3連続の部分です。
①のif文では文字列のNULLチェックを行い、②③のif文で基数の範囲チェックを行っています。
条件式中に使われているCharacter.MIN_RADIX,Character.MAX_RADIXは定数です。
Characterクラスを見てみると以下のように定義されています。
public static final int MIN_RADIX = 2; public static final int MAX_RADIX = 36;
引数チェック②
boolean negative = false;
int i = 0, len = s.length();
int limit = -Integer.MAX_VALUE;
//④文字列が""(空)ならばエラー出力
if (len > 0) {
char firstChar = s.charAt(0);
//⑤1文字目が数字でないならばtrue
if (firstChar < '0') {
//⑥1文字目が'-'(マイナス)ならばtrue
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
//⑦1文字目が'+'でも'-'でもない記号ならばエラー出力
} else if (firstChar != '+')
throw NumberFormatException.forInputString(s);
//⑧文字列が'+'または'-'の1文字ならばエラー出力
if (len == 1)
throw NumberFormatException.forInputString(s);
i++;
}
//中略
} else {
throw NumberFormatException.forInputString(s);
}
続いても入力値チェック(と変数の定義)です。
⑤では引数に渡された文字列の1文字目とchar型の’0’を比較しています。
char型の文字には0~65,535の数字が割り当てられているので、比較演算子での大小比較が可能なんでしたよね。
System.out.println('1' < '0');//true 実体は 49 < 48
System.out.println('+' < '0');//true 実体は 43 < 48
System.out.println('-' < '0');//true 実体は 45 < 48
‘+’や’-‘などの記号は’0’よりも小さい数字が割り当てられているため、⑤の結果がtrueとなります。
一方で’1’や’2’などの数字は’0’よりも大きい数字が割り当てられているため、⑤の結果はfalseとなります。
⑦では’+’と’-‘以外の記号を例外処理しています。
多くの記号には’0’よりも小さい数字が割り当てられているため、⑤がtrueとなり、⑦で処理することができますが、
‘?’などのように’0’よりも大きい数字が割り当てられている記号はここで処理することができません。
そのため、この先の箇所で別途処理することになります。
System.out.println('/' < '0');//true 実体は 47 < 48 ⑤でtrue ⇒ ⑦で例外処理できる
System.out.println('?' < '0');//false 実体は 63 < 48 ⑤でfalse ⇒ ⑦で例外処理されない
変数定義
boolean negative = false;
int limit = -Integer.MAX_VALUE;
//中略
//⑥1文字目が'-'(マイナス)ならばtrue
if (firstChar == '-') {
negative = true;
limit = Integer.MIN_VALUE;
変数の定義についても触れておきましょう。
limitはint型に代入できる値の最大値・最小値を保持する変数です。
初期値は-Integer.MAX_VALUE(-2147483647)で、1文字目が’-‘(マイナス)の場合はInteger.MIN_VALUE
(-2147483648)が代入されます。
なぜ、Integer.MAX_VALUEに’-‘をつけるのか?その理由は後ほど説明します。
negativeは文字列が負の値か否かを表すboolean型の変数です。
初期値はfalse、1文字目が’-‘(マイナス)の場合はtrueが代入されます。
思ったよりも長くなってしまったので続きは【後編】で!
(メインの処理まで行ってない…)