From Java to Kotlin: life without static
Kotlin엔 static 키워드가 없습니다. 그럼 코틀린에서는 static을 대체하기 위해 무엇을 써야할까요?
이를 대체하기 위해 선택할 수 있는 옵션은 다음과 같습니다.
이런 선택지들이 있는데, 언제 어떤 옵션을 선택해야할까요?
자바에서는 main 함수를 작성할 때 많은 보일러 플레이트 코드가 있습니다! 클래스 안에 public static void main(String[] args)와 같이 작성해야 해요. 코틀린에서는 Top-level function으로 구현해주면 끝 입니다!
많은 Util, Helper 클래스를 작성한 경험이 있죠? Util 클래스 안에 static 키워드로 범용적인 메소드를 구현하곤 했습니다. Kotlin에서는 그냥 Top-level function으로 작성해주면 됩니다! 그러고 해당 패키지 내부에서 사용하거나, 다른 패키지에서 해당 Top-level function을 import하면 사용 가능합니다~ ㅎㅎ
Java
public class StringUtils {
private StringUtils() { /* Forbid instantiation of utility class */ }
public static int lowerCaseCount(String value) {
return value.chars().reduce(0,
(count, current) -> count + (Character.isLowerCase(current) ? 1 : 0));
}
}
Kotlin
package toplevel
fun lowerCaseCount(value: String): Int = value.count { it.isLowerCase() }
프로퍼티 또한 Top-level에 작성할 수 있습니다. 물론 immutable하게 선언을 해야겠죠?
위 Get rid of utility classes의 lowerCaseCount 메소드가 한 클래스에서만 필요하다면 Java에서는 다음과 같이 구현할 수 있겠죠?
public class MyClass {
private String myString;
public void doSomething() {
int count = lowerCaseCount(myString);
...
}
private static int lowerCaseCount(String value) { ... } // private static pure function
}
코틀린에서는 해당 static 메소드를 클래스 밖으로 빼서 해당 파일내에 priate top-level function으로 구현해 해당 파일 내에서만 접근가능하게 할 수 있습니다!
코틀린에서는 싱글톤 패턴을 Object 키워드로 제공합니다! 따라서, 자바에서 싱글톤 패턴 구현을 위해 static 키워드를 썼다면 Object 키워드로 대체할 수 있죠~
해당 클래스의 함수임을 명시적으로 표현하고 싶은 경우에는 어떻게 해야할까요?(ex. Math.abs()) 이럴 땐 Companion object를 사용하면 됩니다! (static에 대한 대체로 무조건적으로 Companion object을 사용하는 사람들이 있는데 이런건 잘못된 사용입니다,,)
Companion objects는 클래스 내부에 정의된 Singletone value에요. Companion object 내 멤버들은 클래스 이름으로 호출할 수 있습니다. 게다가 Companion obeject는 클래스 인스턴스의 private 멤버들에 접근할 수 있기 때문에 팩토리 메소드에 !특히! 유용합니다 ㅎㅎ
class Rocket private constructor() {
private fun attachPropellers() { ... }
companion object {
fun build(): Rocket {
val rocket = Rocket() // can call private constructor
rocket.attachPropellers() // can call private function
return rocket
}
}
}
fun main() {
val rocket = Rocket.build() // Companion function called using the accompanied class name
}