JAVA는 Null Safety를 지원하지 않는다.
C#이나 코틀린등은 이와 반대로 Null Safety를 지원한다.
Null-Safety란?
아마 코딩을 하다보면 한번쯤은 Null Pointer Exception(NPE)을 겪어보았을 것이다.
NPE는 null인 object에 접근해서 필드를 가져오거나 메소드를 호출할 때 생기는 에러이다
당연히 object가 null이므로 런타임에 우리가 원하는 대로 동작을 할 수 없어 Exception을 뱉는것이다.
NPE는 정말 까다로운 에러로 디버깅하기가 무척 힘들다.
이러한 NPE를 해결하기 위해 C#은 Null-Safety를 지원한다.
Null-Safety를 이해하기 위해서는 Nullable 형식을 이해해야 한다.
Nullable
우선 Nullable은 값 형식에만 유효하다. 참조 형식은 이미 null값을 가질 수 있기 때문이다.
null값을 가질 수 없는 타입인 값 형식에는 int, float, bool등이 있다.
하지만 어떤 필요에 의해서 이들에게도 null값을 가지게 하고 싶을 때가 있다.
예를들어 사용자의 나이를 저장하는 int형 age 변수가 있다고 했을 때,
int age;
void Init()
{
Console.WriteLine(age); // 컴파일 오류 발생, C#은 할당되지 않은 변수 사용을 막는다.
age = -1;
}
보통 나이를 입력받지 않았음을 나타내기 위해 0이나 -1로 초기화 해둔다.
하지만 조금은 찝찝하다. 해당 변수를 아예 비워두고 싶다. 어떻게 해야 할까?
아예 null로 초기화 해버리는 것이다.
기존의 int타입 대신 Nullable-int타입을 선언해서 초기화 하면 된다.
int? age;
void Init()
{
age = null;
}
Nullable 타입은 기존 타입에 ?를 붙이기만 하면 된다.
사실 Nullable도 클래스 이기 때문에 ? 연산자를 쓰면 컴파일러가 알아서 챡챡 바꿔준다.
모든 Nullable 타입은 HasValue와 Value Property를 갖는다.
int? a = null;
int? b = 10;
Console.WriteLine(a.HasValue); // false 출력
Console.WriteLine(b.HasValue); // true 출력
Console.WriteLine(a.Value); // NPE 발생
Console.WriteLine(b.Value); // 10 출력
a는 null로 초기화 되어있는데 a.Value에 접근하게 되면 마찬가지로 NPE를 발생시킨다.
따라서 값에 접근하기 전에 미리 HasValue 프로퍼티로 검사하는것이 낫다.
Nullable 타입을 위한 연산자도 따로 존재하게 되는데 다음과 같다.
1. ?? 연산자
물음표 두개가 놀랍게도 연산자이다.
a ?? b
이런식으로 사용하는데 a 가 null이면 b를 , null이 아니면 a를 리턴하게 된다.
다음 예제를 보자
int? a = null;
object b = new object();
object c = null;
Console.WriteLine($"{a ?? 0}"); // a는 null이므로 0 출력
c = b ?? new object(); // b는 null이 아니므로 c에 b 참조
위 아래 코드는 동일하다.
int? a = null;
object b = new object();
object c = null;
if(a == null)
Console.WriteLine("0");
else
Console.WriteLine(a);
if(b == null)
c = new object();
else
c = b;
?? 연산자를 쓰면 코드의 가독성을 높일 수 있다.
?? 연산자는 Nullable한 타입에만 쓸 수 있으므로
int a = 3;
int? b = null;
b = a ?? 3; // 에러
아마 치자마자 빨간줄을 보게될것이다.
2. ??= 연산자
점점 모양이 흉측해져 간다.
a ??= b
이런식으로 쓸 수 있으며 뜻은
a가 null이면, a에 b를 대입, a가 null이 아니면 무시
a = a ?? b; // 이 코드와 동일하다
3. ?. 연산자
이번에는 ?. 라는 요상하게 생긴 연산자이다. ?[] 연산자도 있으나 배열이냐 아니냐의 차이뿐이어서 설명하지 않겠다.
?. 연산자는 오브젝트 참조 연산자인 . 연산자의 Null-Safety한 버젼이다.
드디어 Null-Safety를 설명 할 수 있게 되었다.
object a = null;
a.ToString(); // NPE를 내면서 프로세스가 죽어버린다.
코드가 두줄 밖에 안돼서 간단하게 null검사를 하는 코드를 넣어 고칠 수 있지만
코드의 양이 많아지면 쉽게 찾을 수 없어 NPE라는 치명타를 맞게 된다.
이때 ?. 연산자를 쓰게 되면 말끔히 해결된다.
object a = null;
a?.ToString(); // a가 이미 null이기 때문에 ToString()까지 가지도 않는다.
null검사를 하는 코드를 더 넣을 필요도 없이 ? 하나로 해결했다.
a?.b?.c?.ToString();
셋중에 하나라도 null이면 실행되지 않는다
'etc > C#' 카테고리의 다른 글
[C#] Lambda Function Capture (1) | 2021.07.30 |
---|---|
[C#] switch 제어문 (0) | 2021.07.16 |
[C#] 문자열 보간(Interpolation) (0) | 2021.07.15 |
[C#] Property(프로퍼티), C#만의 특별한 기능 (0) | 2021.07.13 |
[C#] Lambda Expression(람다 식) 이란? (0) | 2021.07.12 |