
적절하게 null을 처리하라
String.toIntOrNull(): String을 Int로 적절하게 변환할 수 없는 경우Iterable<T>.firstOrNull(() -> Boolean): 주어진 조건에 맞는 요소가 없을 경우 null위와 같이 null은 최대한 명확한 의미를 갖도록 하는 것이 좋다.
null 의 경우, 아래와 같이 세가지 방법으로 처리할 수 있다.
?., 스마트 캐스팅, Elvis 연산자 등을 활용해서 안전하게 처리printer?.print() //safe call
if (printer != null) printer.print() //smart casting
//Elvis 연산자
val printName1 = printer?.name ?: "Unnamed"
val printName2 = printer?.name ?: return
val printName3 = printer?.name ?: throw Error("에러")
위의 방식들은 개발자에게 오류를 알리지 않고, 코드가 진행되는 방법이다. 만약 null일때 문제가 발생한다면 개발자에게 오류를 강제로 발생시켜주는 것이 좋다.
이때 throw, !!, requireNotNull, checkNotNull 을 사용해 강제로 오류를 발생시킬 수 있다.
!!은 null이 나오지 않는다는 것이 거의 확실한 상황에서 많이 사용된다. 하지만 미래에 null이 가능성은 언제나 존재한다. 따라서 결국 NPE 예외로 이어질 수 있다.
또한 계속해서 언팩(unpack)해야해서 귀찮아질 수 있고, 의미있는 null 값을 가질 가능성을 차단해버리게 된다.
!!은 웬만하면 지양하는 것이 좋고, lateinit, Delegates.notNull을 사용하는 것이 좋다.
의미가 없다면 null을 사용하지 않는 것이 좋다. 이유 없이 사용한다면 !!을 사용하게 되고, 이는 의미 없이 코드를 더럽히게 된다.
nullability 를 피하는 방법은 다음과 같다.
클래스가 클래스 생성 중 초기화할 수 없는 프로퍼티를 가질 수 있는데, 이는 사용 전 반드시 초기화해서 사용해야 한다. (ex. @BeforeEach)
lateinit은 처음 사용하기 전 반드시 초기화된다는 것을 의미한다. nullable과 비교해 다음과 같은 차이가 있다.
notNull 델리게이트는 JVM에서 Int, Long, Double, Boolean과 같은 기본 타입과 연결된 타입으로 프로퍼티를 초기화해야 할 때 사용한다. (lateinit 보다 느리다)
private var doctorId: Int by Delegates.notNull()
lateinit, Delegates.notNull: https://codechacha.com/ko/diff-between-deligate-and-lateinit-in-kotlin/
좋은 글 감사합니다!