brunch

You can make anything
by writing

C.S.Lewis

by 최창규 Jan 28. 2022

Effective Java to Kotlin

코틀린도 이펙티브하게 개발하자.

Kotlin으로 프로젝트를 하면서 자연스럽게 Effective Java에서 소개하고 있는 지침들을 Kotlin으로 구현하면 어떻게 개발해야 하는지 관심이 갔습니다.

그래서 각 항목별로 간단하게 Kotlin으로 구현하는 방법을 정리해 봤습니다. 또 Language 레벨에 녹아 있는 지침들도 찾아보겠습니다.


규칙 1. 생성자 대신 정적 팩토리 메서드를 사용할 수 없는지 생각해 보라

Kotlin은 companion object를 사용해서 정적 팩토리 메서드를 대체할 수 있습니다. 추가로 private constructor와 함께 사용한다면 완벽하게 생성자 호출을 차단할 수 있습니다.      

class Person private constructor (val name: String) {
      companion object {
         fun of(name: String): Person {
           return Person (name)    
        } 
    }


val peter = Person.of("Peter") 
새로운 규칙 1. 생성자 대신 companion object를 고려해 보라


규칙 2. 생성자 인자가 많을 때는 Builder 패턴을 고려하라

Kotlin은 Builder 패턴을 대체할 수 있는 문법을 제공합니다. 바로 1. 생성자에 named arguments를 사용하는 것과 2. apply()를 사용하는 것입니다.

named arguments는 필수 프로퍼티에 값을 할당할 때 사용할 수 있습니다.      

val peter = Person(name="Peter", age=25)  


여기에 추가로 선택 프로퍼티에 값을 할당할 때는 apply()를 사용합니다.      

val peter = Person(name="Peter", age=25).apply {
       height = 180        
      married = true 
새로운 규칙 2. 생성자 인자가 많을 때는 named arguments와 apply()를 사용하라


규칙 3. private 생성자나 enum 자료형은 싱글턴 패턴을 따르도록 설계하라

kotlin은 언어 레벨에서 싱글턴 패턴을 지원합니다. 바로 object class로 정의하는 것입니다.      

// 선언 
object Singleton {
      fun myFunction() { ... } 


// 사용
 Singleton.myFunction() 
새로운 규칙 3. 싱글턴 패턴은 object class를 사용하라


규칙 8. equals를 재정의할 때는 일반 규약을 따르라

Kotlin은 == 비교 시에 내부적으로 equals를 호출합니다. ==과 equals의 역할이 다른 Java와는 차이가 있습니다. 만약 equals를 재정의할 필요가 있다면 Java에서 따르는 일반 규약을 적용하면 되는데 Kotlin은 비교적 간단한 대안을 제공하고 있습니다. 바로 data class를 사용해서 클래스를 정의하는 것입니다. data class는 equals, hashCode, toString을 자동으로 구현해 주기 때문에 매우 편리합니다.

새로운 규칙 8. equals가 재정의할 때는 data class로 정의하라

규칙 11. clone을 재정의할 때는 신중하라

Kotiln은 data class로 정의하면 사용할 수 있는 copy()를 Java의 clone()을 대신 사용할 수 있습니다.      

val x = Person("Peter") val y = x.copy() assertThat(x == y, is(true)) 
새로운 규칙 11. clone 대신 copy function을 사용하라


규칙 12. Comparable 구현을 고려하라

Kotlin은 Java와 다르게 Comparable 인터페이스를 받드시 상속 받지 않아도 됩니다. 대신에 compareBy와 lamda를 이용해 쉽게 객체를 비교할 수 있습니다.      

val sortedListOfMovies: 
List <Movies> = list.sortedWith(compareBy({ it.rating }, { it.year })) 
새로운 규칙 12. Comparator와 lamda로 쉽게 비교하라


규칙 14. public 클래스 안에는 public 필드를 두지 말고 접근자 메서드를 사용하라

일반적인 원칙은 Java와 동일하나 Kotlin은 getter와 setter를 좀 더 쉽게 만들 수 있습니다.      

var name: String = ""
     get() = field
     set(name) {
         field = name
     } 


규칙 15. 변경 가능성을 최소화하라

Kotlin은 immutable 변수의 경우 val 키워드로 지정하고, mutable 변수는 var로 지정합니다.

새로운 규칙 15. val 키워드를 사용해서 변경 가능성을 최소화하라


규칙 36. Override 어노테이션은 일관되게 사용하라

Kotlin은 Override 어노테이션을 사용하지 않습니다. 대신 override 키워드를 function 이나 property 앞에 넣어야 합니다. 그리고 override를 허용하는 부모의 function에는 open 키워드를 넣어야 합니다.      

override fun process(){... } 
새로운 규칙 36. open/override 키워드를 사용하라


규칙 49. 객체화된 자료형 대신 기본 자료형을 이용하라

Kotlin은 기본 자료형이 없고, 객체화된 자료형(Int, Boolean, Long 등)을 써야 하므로 해당 규칙은 Kotlin에 해당하지 않습니다. Kotlin은 객체화된 자료형만 사용하세요.


정리

Kotlin으로 프로젝트를 진행해보니 언어를 설계할 때 Effective Java의 다양한 지침을 Language 레벨에 많이 녹여서 구현했다는 느낌을 받았습니다. class가 default는 final이고, 상속을 허용하려면 open 키워드를 추가해야 하는데 ‘규칙 16. 계승하는 대신 구성하라’를 적용한 것입니다. 또 싱글턴 패턴을 object 키워드로 간결하게 구현할 수 있고, 특히 data class와 null이 될 수 있는 타입은 Kotlin의 백미라고 할 수 있습니다.


이렇게 정리해 놓고 보니 Kotlin이 Java에 비해 조금 더 Effective 하다는 생각이 듭니다. 빨리 Kotlin으로 갈아타세요.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari