Javaにおける値を比較する方法

まえがき

Javaにおける、プリミティブ型と参照型の比較方法をまとめる。

変更履歴

2021/07/02(FRI): 新規作成

この記事の環境

Java 1.8

Javaの値の種類=型の種類

  1. プリミティブ型
    1. 参照型(ラッパークラス)

プリミティブ型と参照型の対応

プリミティブ型参照型
charCharacter
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
booleanBoolean

オートボクシング、アンボクシングについて

先にこの2つについて触れておくべきか。忘れがちなのがオートボクシングとアンボクシング。そもそもボクシングにならないように設計するべきだと思う。

オートボクシング

プリミティブ型から参照型へ自動変換することを指す。

int num1 = 12;
Integer num2 = num1;

アンボクシング

参照型からプリミティブ型への自動変換することを指す。

Integer anNum1 = 33;
int anNum2 = anNum1;

プリミティブ型と参照型の違い

値の所在がスタック領域か、ヒープ領域かによって比較方法が決まる。

プリミティブ型

  • 値のサイズが決まっている。
  • 値はメモリのスタック領域に入れられる。

参照型

  • 値のサイズが決まっていない。
  • 値はメモリのヒープ領域に入れられる。
  • 参照値がスタック領域に入れられる。

比較の基本

比較は「==」か「オブジェクト.equals()」によって行う。

お察しの通り、プリミティブ型の比較は「==」を使う。参照型の比較は「equals()」を使う。もう少し踏み込んでみると、スタック領域にある値は「==」で、ヒープ領域にあるものは「equlas()」で行う、という事になる。

int num1 = 3;
int num2 = 6;

if (num1 == num2) return true;

Integer heapNum1 = 2;
Integer heapNum2 = 4;

if (heapNum1.equlas(heapNum2)) return true;

また、後述するが比較演算子の「>, <, >=, <=」は数値形の参照型では使うことができる。

参照型で==を使った比較で起きること

つまり参照型では、先に述べた「参照値」が比較の対象になる。 参照値が同一がどうかを比較したい場合には意図通りということだが、これが分かっていないとあなたのソフトウェアは明後日の方向を向いている事にになる。

Float x = 1.0; // 参照値:a8658b2f
Float y = 1.0; // 参照値:b8111102

if (x == y) return "参照値は同一ではありません";

参照型の値を比較したい場合は各参照型に用意された「eqauls()」を使う事になる。 Integer#equlas(Object obj)などだ。

ボクシングされた値と比較演算子について

例えばint型がInteger型にオートボクシングされ、それを引数と受け取るメソッドがあるとする。この時の値の比較は「>, <, >=, <=」が使える。「==, !=」は使えない。

// オートボクシング
int num1 = 12;
Integer boxNum1 = num1;

int num2 = 22;
Integer boxNum2 = num2;

// NGパターン
if (boxNum1 == boxNum2) return "NG"; // 参照値が違うからリターンされない

// OKパターン
if (boxNum1 &lt; boxNum2) return "OK"; // boxNum2の方が大きいのでレターンされる。

また、オートボクシングされたものでもByte型とBoolean型では「==, !=」を値の比較に使うことができる。

ややこしいが、とにかくそういうことだ。

boolean bool1 = true;
Boolean boxBool1 = bool1;

boolean bool1 = false;
Boolean boxBool2 = bool2;

if (boxBool1 == boxBool2) return true;

if (boxBool1 != boxBool2) return false;

文字列型の比較

ちょいと面倒なのがこの文字列型。わかっていればなんのことはないが知らない間は夜も眠れない存在だ。

文字列がの特徴:

  • 参照型である。
  • 変更不可能体(イミュータブル)である。
  • 同じ文字列があると、新たな変数でも参照値は同じとなる。
  • 同じ値でも、newすれば新しい参照値がもらえる。
  • 文字列の比較のString#equlas()はぬっl。
String str1 = "アメノウズメの尊";
String str2 = "クシナダヒメの命";

// 値の比較
if (str1.equals(str2)) return true; // 違う値なのでリターンされない

// 同じ参照値
String str3 = "アメノウズメの尊";
if (str1 == str3) return true; // 参照値が同じなのでリターンされる

// 新しい参照値を貰う
String str4 = new String("アメノウズメの尊");
if (str1 == str4) return false; // 参照値が違うのでリターンされない

BigDecimal型の比較

BigDecimalの特徴:

  • 参照型である。
  • 変更不可能体(イミュータブル)である。
  • 算術、スケール操作、丸めとか便利。
  • BigDecimal同士だと、BigDecimal#equalsで比較できる。
  • 15と15.0のなどの比較は、「BigDecimal#compareTo(Bigdecimal) == 0」といった感じでできる。
BigDecimal bigNum1 = new BigDecimal(15);
BIgDecimal bigNum2 = new BigDecimal(14);
BigDecimal bigNum3 = new BigDecimal(15.0);

if (bigNum1.eqauls(bigNum2)) return true; // 違う値なのでリターンされない

if (bigNum1.equlas(bigNum3)) retunr false; // これはリターンされない。

// compareTo()で値が同じなら0を返す。
if (bigNum1.compareTo(bigNum3) == 0) return false; // リターンされる。

// bigNum1が大きい場合は正の数を返す。
if (bigNum1.compareTo(bigNum2) &gt; 0) return false; // リターンされる。

// bigNum1が小さい場合は負の数を返す。
if (bigNum1.compareTo(bigNum2) &gt; 0) return false; // リターンされない。

nullチェックの方法

nullチェックをしたい時は。

if (num == null) 
	throw new BusinessException();

nullは「==」でもOK.

しかし君よ。

if (Objects.isNull(num))
	throw new BusinessException();

if (Objects.nonNull(num))
	return true;

こっちがおすすめです。

というか。

Optional.ofNullable(numList)
	.ifPresent(list -&gt; {
		list.forEach(num -&gt; {
			System.out::print;
		})
	});

nullチェックに関してはOptionalを使うのが大人のマナーです。

参照型のnullへの処方箋

Integer#equals() String#equals()などではnullが返される可能性がある。参照型なので参照がないというnullが帰ってくるのは当たり前だが、比較のタイミングで NPEでは困るので別の方法を使う。

Objects.equals(Object obj1, Object obj2)、といった感じである。この形であればnullが帰っきても結果がfalseになるだけなので設計しやすい。

むすび

Javaの外部ライブラリにも便利なモジュールがあるので、それらの中でもっと使えるものを利用していくこともお忘れなく。Booleanの比較はBooleanUtilsなどが便利だ。

次はtoStringとvalueOfの動きもまとめていきたい。

コメントする