개발을 하던 중 평소와 다름없이 조건에 map에 들어있는 값과 String 값을 비교하기 위해 equals를 썼는데
java.lang.NullPointerException에러가 발생하는 것이다!
오잉? 나는 객체나 문자열을 비교할때는 equals를 쓰고 문자나 숫자를 비교할때는 ==를 사용해서 비교하는것으로만 기억하고있는데
왜 오류가 나는거지? 해서 내가 실수한 부분을 찾아보고 정리하는 것이다.
자 그럼 알아보자!
여담이지만 이번에 봤던 정보처리기사 2023년 2회 실기 시험문제에서도 equals와 ==의 결과값을 쓰는 문제가 나왔다.
문제로 낼 수 있을만큼 헷갈리기 쉬운것이다. 잘 알아보자!
A.equals("B")와 A == B 은 기본적으로 양쪽에 있는 A,B를 비교하기 위해서 사용한다.
기본형 데이터 타입은 기본값이 있기 때문에 NULL이 존재하지 않는다.
실제 값을 저장함으로 stack 메모리에 저장이 된다.
ex) boolean, int, double, char... 등
참조형 데이터 타입은 빈 객체를 의미하는 NULL이 존재한다.
값이 저장되어 있는 곳의 주소값을 저장하는 공간으로 Heap 메모리에 저장이 된다.
객체나 배열을 Null 값으로 받으면 NullPointerException이 발생하므로 변수값을 넣어야 한다.
ex) Array, Class, Interface.. 등
Object에 정의되어있는 코드를 한번 보자
public boolean equals(Object obj) {
return (this == obj);
}
위 코드를 보면 equals도 내부적으로 "=="연산자를 사용해서 비교하고 있는것을 볼 수 있다.
하지만 위에서 말했듯이 equals는 Object 클래스에 포함되어 있어 재정의 해서 사용할 수 있다고 했다.
우리가 String에서 사용하던 재정의된 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;
}
위 코드를 보면
if (this == anObject) 이부분에서 anObject 변수로 들어온 객체와 자신의 주소값이 같다면 true를 리턴
주소값이 다르다면 String 객체의 문자열을 Char 타입으로 하나씩 잘라서 비교하고
모든게 같다면 true, 다르다면 false를 리턴한다.
이렇듯 String 클래스의 equals는 문자열의 비교가 가능하게 재정의 되어있는 것이다.
String a = "abc";
String b = "abc";
String c = new String("abc");
System.out.println(a.equals(b));
System.out.println(a.equals(c));
System.out.println(b.equals(c));
System.out.println(a == b);
System.out.println(a == c);
위 코드의 출력값이 어떻게 나올까?
.
.
.
.
.
.
.
.
.
.
.
정답을 먼저 보자면 아래와 같이 나온다.
true
true
true
true
false
왜 이렇게 나올까?
먼저 a가 생성되면서 메모리에 abc라는 값이 저장된 방이 만들어지고 a는 이 주소값을 바라보게 된다.
그리고 같은 값을 가진 b도 abc라는 값이 저장된 방의 주소를 바라보게 된다.
즉, a와 b는 같은 주소값을 가지고 있다.
하지만 c는 새로 방을 생성했기 때문에 a,b와 같은 값을 가지고 있지만 독자적인 다른 방의 주소 값을 가지고 있는것이다.
- a와 b가 가지고 있는 내용을 비교 : true
- a와 c가 가지고 있는 내용을 비교 : true
- b와 c가 가지고 있는 내용을 비교 : true
- a와 b가 가지고 있는 주소값을 비교 : true
- a와 c가 가지고 있는 주소값을 비교 : false
내가 소스에서 실수했던 부분은
map에 단일 쿼리 결과를 받고 ('Y'또는'N'으로 받았다.)
이 것을 조건에 넣어서 if(map.get("result") == ("Y"))로 비교했는데
객체와 문자를 비교하고 있으니 에러가 나는것이다!
그래서 if(map.get("result").equals("Y"))로 바꿔서 아 됐다 하고 있는데.....
부장님한테 혼났다!
이렇게 하면 result가 null일때 에러가 날 수있다는 것이다.
그래서 이렇게 바꿔서 썼다.
if("Y".equals(map.get("result")))
이렇게 하면 에러가 안날것이다..!!!
이런 유용한 정보를 나눠주셔서 감사합니다.