Javaには「Integer」や「Long」という型と、「int」や「long」という型が存在しています。
どちらを使用するのが良いかは、Javaに精通していないと判断しづらいところがあります。
本記事では「Integer」と「int」どちらを使うべきなのか?その理由は?という点を解説します。
Integerとintの違い
「Integer」と「int」の違いに着目して解説します。
※「Long」と「long」などの違いについても同様です。
intは基本データ型
intは基本データ型と言います。
基本的にはint型を使用してください。
基本データ型は参照を持っていないので高速に動作するといった特徴があります。
Integerは参照型
Integerは参照型です。
基本データ型のintは参照型ではないため、参照型の使い方をしたいときに使うことができないという問題があったので、基本データ型をラップした型として作成されました。
参照型の基本的な用途は以下の場面です。
- Listなどのコレクションのキーや値は参照型の値を使用する必要がある
- メソッドの型パラメータなどは参照型の値を使用する必要がある
これ以外の用途では以降で説明する問題が起きるため、基本データ型を選択するべきです。
ボクシング
また、基本データ型と参照型の間で「ボクシング」と呼ばれる仕様が存在します。
Integer i1 = 12; // オートボクシング int i2 = new Integer(12); // オートアンボクシング
上記はいずれも12になりますが、i1ではオートボクシング、i2ではオートアンボクシングが行われています。
基本データ型を参照型に変換するのがオートボクシングで、
参照型を基本データ型に変換するのがオートアンボクシングです。
これがあるおかげで、基本データ型と参照型をあまり意識せずに使用することができています。
ただし、ボクシングでは変換作業で多少の時間を使っているという点があることを留意しておく必要があります。
Integerを使用する場合の問題点について
Integerは参照型であること、ボクシングという仕様があることの2点から、使用すると問題が発生するケースが3つ存在します。
そのため、通常は基本データ型を採用してください。
比較で注意が必要
以下のコード例をご覧ください。
public static void main(String[] args) { // 問題1 比較で注意が必要 Integer i1 = new Integer(10); Integer i2 = new Integer(10); if (i1 < i2) { System.out.println("i2が大きい"); } else if (i1 == i2) { System.out.println("i1とi2は同じ"); } else { System.out.println("i1が大きい"); } // i1が大きいになる!? }
Integerを比較する単純な処理です。
i1とi2を10で初期化しているので、「i1とi2は同じ」が表示されると思うところですが、結果は「i1が大きい」となります。
なぜそうなるか解説します。
はじめにi1 < i2 の比較ではオートアンボクシングが行われ、10と10の比較となるため、適合せず次の条件式に行きます。
次がポイントですが、i1 == i2 の比較では参照の比較が行われます。そのため、10と10が一致していることを検査するのではなく、インスタンスの同一性をチェックします。i1とi2は各々newしている別のインスタンスであるため、結果がfalseとなってしまい期待した結果にならないということが発生します。
これは基本データ型を使用している場合は発生しない問題です。
もし、Integerを使用したい場合は、比較前に「基本データ型にオートアンボクシングする」必要があります。
NullPointerExceptionに注意が必要
IntegerはNullPointerExceptionが発生する可能性を秘めています。
以下のコード例をご覧ください。
public static void main(String[] args) { // 問題2NullPointerExceptionに注意が必要 Integer i3 = null; if (i3 == 20) { System.out.println("iは20"); } }
この比較を実行すると、NullPointerExceptionが発生します。
参照型はnullが設定できます。
このコード例は直接nullを入れているおかしな処理ですが、別の場所から呼び出されて検査されていないIntegerの値が渡ってくる可能性があります。
Integerを比較するのであれば、nullでないかのチェックを先に行う必要がありますが、しなくてもコンパイルが通ってしまうので、比較を忘れてしまうとNullPointerExceptionが発生する可能性のある処理が生まれてしまいます。
基本データ型のintは初期値が0になるため、少なくともNullPointerExceptionが発生することはありません。
オートボクシング、オートアンボクシングが繰り返される可能性
基本データ型と参照型を意識せず使っていると、オートボクシングとオートアンボクシングが発生して無駄な変換が行われる可能性があります。
以下のコードをご覧ください。
0からintの最大値までを合計する処理です。
合計値を保持する変数sumが参照型であるため、毎回合計するときにオートアンボクシングが行われます。
public static void main(String[] args) { // 問題3オートボクシング、オートアンボクシングが繰り返される可能性 double start = System.nanoTime(); Long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum); double end = System.nanoTime(); System.out.println("処理時間:" + ((end - start) / Math.pow(10, 9)) + "s"); }
結果は以下の通りです。
2305843005992468481 処理時間:6.7224169s
処理時間が6.7秒もかかっています。
参照型ではなく基本データ型を使用した場合は、以下の通りです。
public static void main(String[] args) { // 問題3オートボクシング、オートアンボクシングが繰り返されない場合 double start = System.nanoTime(); long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum); double end = System.nanoTime(); System.out.println("処理時間:" + ((end - start) / Math.pow(10, 9)) + "s"); }
結果は以下の通りです。
2305843005992468481 処理時間:0.7357414s
計算結果は同じですが、処理時間に10倍近い差が出ています。
オートアンボクシングが行われないようにしただけで、ここまでの違いが出てしまいます。
まとめ
一見違いが分かりにくい「Integer」、「int」、「Long」、「long」の違いについて解説しました。
参照型である「Integer」を使用すると発生する問題があるので、基本的には基本データ型である「int」の使用を選択してください。
参照型を使用する場面は以下くらいです。
- Listなどのコレクションのキーや値は参照型の値を使用する必要がある
- メソッドの型パラメータなどは参照型の値を使用する必要がある
この記事がお役に立てば幸いです。
ちなみに、このIntegerやintの違いといった、少々深い内容を学ぶには「Effective Java」という本で勉強することをお勧めします。
Effective Java はJavaを使用して業務をするのであれば、知っておくべき内容が網羅されています。
業務でJavaを使用するのであれば、必携となる書籍です。
購入する場合、サイズが大きい本なのでKindle版ではなく書籍を強くおススメします。
【お知らせ 無料!】未経験エンジニアがJavaでWebサイトを作成できるようになるための学習ロードマップを、無料で公開しています!
実体験に基づいて作成されているので、プログラミングスクールなどで指導されるロードマップにも劣らない品質です。
こちらの「【Java】エンジニア未経験者がJavaを効率的に勉強する手順を紹介します」リンクから無料で閲覧できるので、是非ご覧ください!