1. Java에서의 null 체크
// case 1
public boolean checkStarts(String str) {
return str.startsWith("A");
}
// case 2
public boolean checkStarts(String str) {
if (str == null) {
throw new IllegalArgumentException("null이 들어와선 안됩니다.");
}
return str.startsWith("A");
}
// case 3
public boolean checkStarts(String str) {
if (str == null) {
return false;
}
return str.startsWith("A");
}
// case 4
public Boolean checkStarts(String str) {
if (str == null) {
return null;
}
return str.startsWith("A");
}
- case 1
- str에 null이 들어오면 NullPointException이 발생한다. 불안전한 코드이다.
- case 2, 3
- 이렇게 str에 null이 들어올 수 있다는 가정하에 Exception을 처리하거나 false를 반환해서 처리해줘야 안전한 코드이다.
- case 4
- 만약 null이 반환되어야 하는 상황이라면 원시타입이 아닌 참조타입이 반환타입으로 명시되어야 한다.
2. Kotlin에서의 null 체크 - Safe Call
- Safe Call(?)은 컴파일 단계의 안전성을 보장해준다.
- 수신타입 혹은 반환타입에 null이 들어오거나 나갈 수 있다면 반드시 Safe Call을 명시해야 컴파일 에러가 발생하지 않는다.
- 메소드 앞의 Safe Call은 null이 아니면 실행하고, null이면 실행하지 않는다.
// case 1
fun checkStarts(str: String): Boolean {
return str.startsWith("A")
}
// case 2
fun checkStarts(str: String?): Boolean {
if (str == null){
throw IllegalArgumentException("null이 들어와선 안됩니다.")
}
return str.startsWith("A")
}
// case 3
fun checkStarts(str: String?): Boolean {
if (str == null){
return false
}
return str.startsWith("A")
}
// case 4
fun checkStarts(str: String?): Boolean? {
// if (str == null){
// return null
// }
// return str.startsWith("A")
return str?.startsWith("A")
}
- case 1
- 만약 이렇게 Safe Call을 적용하지 않고, checkStarts 함수에 null을 넘기면 컴파일 에러가 발생한다.
- case 2, 3
- 위에서 null을 체크했다면 더 이상 그 아래에선 신경쓰지 않아도 된다. 한번만 검사를 하면 non-null임을 컴파일러가 알 수 있기 때문이다.
- 반환타입도 마찬가지로 Safe Call이 필요 없게 된다.
- case 4
- 설령 null을 반환하더라도 반환타입에 Safe Call을 명시해주면 된다.
- 이 케이스의 경우, 더 간결한 처리가 가능하다. 말했듯 메소드 앞에 Safe Call을 명시하면 null이 아닐 때만 실행되기 때문이다.
3. Kotlin에서의 null 체크 - Safe Call + Elvis
- Elvis 연산자(?:)를 사용하면 조금 더 간결한 코드 작성이 가능하다.
- Elvis 연산자는 앞의 연산 결과가 null이면 뒤의 값을 사용하고, null이 아니면 그대로 앞의 연산 결과를 넘겨준다.
// case 2
fun checkStarts(str: String?): Boolean {
return str?.startsWith("A")
?: throw IllegalArgumentException("null이 들어와선 안됩니다.")
}
// case 3
fun checkStarts(str: String?): Boolean {
return str?.startsWith("A") ?: false
}
- 이런 식으로 Elvis 연산자를 활용해 더 간결한 코드를 작성할 수 있다.