Integer.parseInt(String, int) にご注意

0xFFFFFFFF は 32 bit int で、型が符号付きなら -1 です。

Java は符号なし int はないので、常に -1 なのですが、ちょっとした罠があります。

以下は文字列 "FFFFFFFF" を int に直そうとするコードです。これを実行するとどうなるでしょう。

public class ParseIntTest {
    public static void main(String[] args) {
        int num = Integer.parseInt("FFFFFFFF", 16);
        System.out.println(num);
    }
}





なんと、NumberFormatException が発生します。10 年以上 Java やってますが、知りませんでした。

Exception in thread "main" java.lang.NumberFormatException: For input string: "FFFFFFFF"
        at java.lang.NumberFormatException.forInputString(Unknown Source)
        at java.lang.Integer.parseInt(Unknown Source)
        at ParseIntTest.main(ParseIntTest.java:3)


Javadoc の Integer.parseInt(String, int) には、

例外:

    NumberFormatException - String が構文解析可能な int 値を含まない場合

Integer (Java 2 Platform SE 5.0)

という説明だけしか書かれておらず、今回の文字列が不正であることが明示的には記載されていません。推測するに、"FFFFFFFF" が符号なし換算で Integer.MAX_VALUE を超えているから、ということだとは思いますが。

なお、以下のコードは全く問題ありません。

public class ParseIntTest {
    public static void main(String[] args) {
        int num = 0xFFFFFFFF;
        System.out.println(num);
    }
}

parseInt なんだから、"FFFFFFFF" は int の -1 にしてもらいたいものです。

Android(Dalvik、Harmony)ではどうかというと、

java.lang.NumberFormatException: Invalid int: "FFFFFFFF"
        at java.lang.Integer.invalidInt(Integer.java:138)
        at java.lang.Integer.parse(Integer.java:378)
        at java.lang.Integer.parseInt(Integer.java:366)

メッセージこそ違いますが、NumberFormatException が出ることには変わりがないようです。


さて、ではどうすればよいか、というと、このケースでは Long.parseLong(String, int) を使用すれば回避できます。

public class ParseIntTest {
    public static void main(String[] args) {
        int num = (int) Long.parseLong("FFFFFFFF", 16);
        System.out.println(num);
    }
}

8 桁の 16 進数文字列を int に変換する場合、場合によっては失敗する、ということを頭の片隅に置いておきましょう。