Java equals 총 정리, 값 비교하기, Objects.equals()

equals 함수에 대해 살펴보도록 하겠습니다.

equals()는 두 객체를 비교하는 함수로써 모든 클래스의 조상인 Object 클래스의 함수입니다.

 

 

Object.equals

Object 클래스의 equals() 함수는 객체의 주소를 비교합니다.

즉 같은 값을 가진 객체라 할지라도 따로 생성되었다면 False입니다.

public class Main {
    public static void main(String args[]) {
        Name nameA = new Name("Aiden");
        Nmae nameB = new Name("Aiden");
        Name nameC = nameA;
        System.out.println(nameA.equals(nameB)); // --> False
        System.out.println(nameA.equals(nameC)); // --> True
    }
    
    public static class Name {
        private String name;
        public Name(String name) {
            this.name = name;
        }
    }
}

nameA와 nameB는 "Aiden"이라는 같은 이름의 값을 가진 객체이지만

해당 객체가 생성된 주소가 다르기 때문에 False를 리턴합니다.

반면 nameC는 nameA를 할당했기 때문에 같은 주소 임으로 True를 리턴합니다.

 

String.equals

String 객체에 equals를 쓸 때는 주소가 분명 다름에도 불구하고 문자열 값이 같으면 True를 리턴하는 경우를 많이 보셨을 것입니다. 흔히 Java에서 문자열을 비교할 때는 equals 함수를 사용합니다.

 

String 객체에서 equals 가 주소가 다름에도 문자열만 같으면 True를 리턴하는 것은

String 객체에서는 Overriding 된 equals 함수를 사용하기 때문입니다.

String Class에서 equals 함수를 살펴보겠습니다.

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String) anObject;
        int n = value.length;
        if (n == anotherString.value.length) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = 0;
            while (n-- != 0) {
                if (v1[i] != v2[i])
                    return false;
                i++;
            }
            return true;
        }
    }
    return false;
}

String의 equlas는 같은 객체면 True인 것은 당연하고

비교대상이 String Instance 라면 문자열을 비교해서 참이면 True를 리턴합니다.

 

Integer.equals

public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}

 

Integer Class의 equals 함수도 String Class와 별반 다르지 않습니다.

비교대상이 Integer의 Integer Instance 라면 intValue를 비교해서 리턴합니다.

 

String과 Integer Class의 예로 충분하리라 생각됩니다.

다른 자료형에서 사용되는 equals 함수도 별반 다르지 않습니다.

같은 Instance라면 값을 비교하여 일치 여부를 리턴합니다. (다른 Instance라면 False)

 

(추천!!) Objects.equals, Objects.toString

Equals 함수를 사용하다 보면 NullPointerException 이 발생하는 경우가 종종 있습니다.

@Controller
public class Controller{
    @RequestMapping(value = "/test")
    public void test(@RequestParam Map param) {
        // 만약 param에 TEST를 넘기지 않았다면 NullPointerException 발생
        System.out.println(param.get("TEST").equals("TEST")); 
    }
}

파라미터로 TEST 값이 넘어올거라 생각했지만 넘어오지 않았을 때 NPE가 발생하게 됩니다

물론 이런 NullPointerException을 방지하기 위해 아래처럼 코딩하기도 합니다.

System.out.println("TEST".equals(param.get("TEST")));

 

 

 

"TEST"라는 문자열에 equals 함수를 사용해 NullPointerException이 일어나는 걸 방지하는 것입니다.

 

아래와 같은 경우를 생각해 봅시다.

System.out.println("2".equals(String.valueOf(param.get("TEST"))));

파라미터로 넘어온 TEST의 값이 String이 아닌 경우 우리는 캐스팅해주어야 합니다.

그래서 위와 같은 코드를 작성했습니다, 하지만 이때 TEST 파라미터가 NULL이라면?

또다시 String.valueOf 함수에서 NPE가 발생합니다.

( String.valueOf 대신에 ""+param.get("TEST")를 사용할 수도 있습니다. NULL인 경우 "null" 문자열이 됨)

 

모던 자바 8에 등장한 Objects 클래스에도 equals 함수가 있습니다.

그리고 해당 함수는 NPE에 대한 염려를 어느 정도 해소시켜주었습니다.

//Objects.equals()
public static boolean equals(Object a, Object b) {
    return (a == b) || (a != null && a.equals(b));
}

 

 

코드는 간단합니다, 파라미터로 넘긴 A Object의 equals 함수로 비교하는 내용입니다.

중요한 것은 해당 Object A에 Null 체크를 했다는 것입니다.

 

System.out.println(Objects.equals(String.valueOf(param.get("TEST")), "2"));

 

이런 식으로 사용할 수 있지만 여전히 파라미터에 TEST가 NULL 일 경우 String.valueOf 에서 NPE가 발생합니다.

그래서 Objects 클래스에 있는 toString() 함수를 함께 사용해주겠습니다.

// Objects.toString()
public static String toString(Object o, String nullDefault) {
    return (o != null) ? o.toString() : nullDefault;
}

역시 간단한 코드입니다, NULL 체크를 하는 toString 함수입니다.

응용해서 equals를 만들어 보겠습니다.

System.out.println(Objects.equals(Objects.toString(param.get("TEST")), "2"));

이제 파라미터로 NULL이 넘어왔더라도 NPE는 발생하지 않습니다.

Objects Class가 생기면서 NPE에 대한 많은 불편이 해소된 것 같습니다.

 

주저리주저리 글이 조금 길어진 것 같은데요

결론은 Objects Class를 사용해서 NullPointerException 걱정 없이 개발하면 좋겠다는 것입니다.

일일이 챙기기 귀찮은 코드였는데 유용하게 사용할 수 있을 것 같습니다.