読者です 読者をやめる 読者になる 読者になる

Java7 のObjectsクラス

Java7 になってtry-catch-resourceとかDiamond Operatorとか色々入ってきていますが、java.util.Objectsクラスが入って来ました。
比較するオブジェクトがnullのときに、ぬるぽガッってならないので便利ですね。

JavaDocを見てると、equalsとdeepEqualsという違いがあるので、動きの違いを見てみました。

結論はJavaDocに書いてあるとおり、引数が配列のときに動きが違います。
Objects.equals

Returns true if the arguments are equal to each other and false otherwise. Consequently, if both arguments are null, true is returned and if exactly one argument is null, false is returned. Otherwise, equality is determined by using the equals method of the first argument.

Objects. deepEquals

Returns true if the arguments are deeply equal to each other and false otherwise. Two null values are deeply equal. If both arguments are arrays, the algorithm in Arrays.deepEquals is used to determine equality. Otherwise, equality is determined by using the equals method of the first argument.

public class EqualsSample {
	@Test
	public void test_arrays_equals(){
		ImplementsEqualsMethodBean array1 [] = new ImplementsEqualsMethodBean[4];
		ImplementsEqualsMethodBean bean1 = new ImplementsEqualsMethodBean(1, new ArrayList<String>());
		array1[0] = bean1;
		ImplementsEqualsMethodBean array2 [] = new ImplementsEqualsMethodBean[4];
		ImplementsEqualsMethodBean bean2 = new ImplementsEqualsMethodBean(1, new ArrayList<String>());
		array2[0] = bean2;
		
                // ここがちがう!!
		assertFalse(Objects.equals(array1, array2));
		assertTrue(Objects.deepEquals(array1, array2));
	}

  	@Test
	public void test_equals_list() {
		List<String> list1 = new ArrayList<>();
		list1.add("hoge");
		list1.add("fuga");

		List<String> list2 = new ArrayList<>();
		list2.add("hoge");
		list2.add("fuga");

		assertTrue(Objects.equals(list1, list2));
		assertTrue(Objects.deepEquals(list1, list2));
	}

	@Test
	public void test_equals_sampleBean() {
		List<String> list1 = new ArrayList<>();
		list1.add("hoge");
		list1.add("fuga");
		NoImplementsEqualsMethodBean sample1 = new NoImplementsEqualsMethodBean(1, list1);
		NoImplementsEqualsMethodBean sample2 = new NoImplementsEqualsMethodBean(1, list1);

		assertFalse(Objects.equals(sample1, sample2));
		assertFalse(Objects.deepEquals(sample1, sample2));
	}

	@Test
	public void test_equals_sampleBean2() {
		List<String> list1 = new ArrayList<>();
		list1.add("hoge");
		list1.add("fuga");
		ImplementsEqualsMethodBean sample1 = new ImplementsEqualsMethodBean(1, list1);

		List<String> list2 = new ArrayList<>();
		list2.add("hoge");
		list2.add("fuga");
		ImplementsEqualsMethodBean sample2 = new ImplementsEqualsMethodBean(1, list2);

		assertTrue(Objects.equals(sample1, sample2));
		assertTrue(Objects.deepEquals(sample1, sample2));
	}

	@Test
	public void test_equals_null() {
		ImplementsEqualsMethodBean sample1 = null;
		ImplementsEqualsMethodBean sample2 = null;

		assertTrue(Objects.equals(sample1, sample2));
		assertTrue(Objects.deepEquals(sample1, sample2));
	}
	
	public class NoImplementsEqualsMethodBean {
		private Integer id;
		private List<String> list;

		public NoImplementsEqualsMethodBean(Integer id, List<String> list) {
			this.id = id;
			this.list = list;
		}
	}

	public class ImplementsEqualsMethodBean {
		private Integer id;
		private List<String> list;

		public ImplementsEqualsMethodBean(Integer id, List<String> list) {
			this.id = id;
			this.list = list;
		}

		@Override
		public int hashCode() {
			return Objects.hash(id, list);
		}

		@Override
		public boolean equals(Object obj) {
			if (obj == null) {
				return false;
			}
			if (!(obj instanceof ImplementsEqualsMethodBean)) {
				return false;
			}
			return this.id == ((ImplementsEqualsMethodBean) obj).id;
		}
	}
}