티스토리 뷰

SW 개발

Kotlin, 기본 문법 정리

지단로보트 2018. 12. 7. 02:14

val, var을 이용한 변수 할당

  • Java 진영에서 넘어온 개발자가 가장 생소한 부분이 변수 할당이다. KotlinMutable, Immutable 변수를 선언 시점부터 구분한다.
// val 변수는 최초 1번 값을 할당하면 재할당이 불가능하다.
val someText: String
someText = "foo"
someText = "bar" // [Error] Val cannot be reassigned

// var 변수는 값의 재할당이 가능하다.
var someText: String
someText = "foo"
someText = "bar"

// 변수의 값에 따라 조건에 해당하는 문장을 실행한다.
when (someText) {
    "foo" -> println("foo")
    "bar" -> println("bar")
    else -> println("else or null")
}

Null 타입 체크

  • Kotlin이 가진, Java에 없는 대표적인 특징은 Null 타입에 대한 엄격한 체크가 가능하다는 것이다. 덕분에 엔터프라이즈 레벨의 개발에서 많은 실수를 줄일 수 있다.
// 모든 변수는 기본적으로 null이 허용되지 않는 non-null 타입이다.
val someText : String
someText = null // [Error] Null can not be a value of a non-null type String.Companion

// ? 오퍼레이터를 타입 뒤에 붙이면 null이 허용된다.
val someText : String?
someText = null

// ?: 엘비스 오퍼레이터는 좌변이 null일 경우에만 우변을 실행한다.
someText ?: return

// 1개 이상의 여러 문장을 실행할 때는 run{} 블록을 이용한다.
someText ?: run {
    println("foo")
    println("bar")
}

// 변수명 뒤에 ?를 붙이고 함수를 실행하면 null이 아닐 경우에만 함수를 실행한다.
someText?.run {
    println(this)
}

// null이 아닐 경우에만 함수를 실행하여 리턴 값을 변수에 할당한다. null일 경우 그대로 null을 할당한다.
val toUpperCase = someText?.toUpperCase()

// null일 경우 우변의 값을 할당한다.
val toUpperCase = someText?.toUpperCase() ?: "null"

String Template

  • Kotlin에서 String Template은 표현식을 포함한 문자열을 의미한다. Java에서 문자열과 변수를 +로 연결하거나, StringBuilder를 사용해야 했던 것을 생각하면 사용의 편리함과 가독성이 훨신 뛰어나다. [관련 링크]
// abcdef 출력
val foo : "abc"
val bar = "${foo}def"
  • 만약 표현식 내에서 null 상태의 오브젝트를 명시하면 어떤 값을 출력할까? 결과는 오류 없이 null 문자열을 출력한다. KotlinAny?.toString()이 기본적으로 null 확인을 사전에 수행하여 null 문자열을 반환하기 때문이다. null이 아닐 경우에는 본래 오브젝트의 toString()을 호출한다. [관련 링크]
// nulldef 출력
val foo : Foo? = null
val bar = "${foo}def"

String 정규식 치환

  • Kotlin에서의 문자열 정규식 치환 방법은 아래와 같다.
// f*****
"foobar".replace("(?<=.{1}).".toRegex(), "*")

// foo***
"foobar".replace("(?<=.{3}).".toRegex(), "*")

// foo**r@g***l.com
"foobar@gmail.com".replace("(?:(?:^|(?<=@))([^.@])|\\G(?!\\A))[^.@](?:([^.@])(?=[.@]))?".toRegex(), "$1*$2")

String 변환

// 유니코드 -> EUC-KR 변환
String("foobar".toByteArray(Charset.forName("EUC-KR")), Charset.forName("EUC-KR"))

// Base64 변환
Base64.getEncoder().encodeToString("foobar".toByteArray())

Map, List 제어하기

// 읽기 전용 맵을 생성한다.
val someMap = mapOf(1 to "A", 2 to "B", 3 to "C")

// 읽기, 쓰기 가능한 맵을 생성한다.
val someMap = mutableMapOf(1 to "A", 2 to "B", 3 to "C")

// 리스트를 사용하거나 정렬하거나 필터링할 수 있다.
val someList: List<String> = listOf("C", "B", "A")
val someListSorted = someList.sortedBy { it }
val someListFiltered = someList.filter { it > "B" }

println(someList) // [C, B, A]
println(someListSorted) // [A, B, C]
println(someListFiltered) // [C]

메써드 파라메터로 펑션 전달하기

  • Kotlin은 메써드의 파라메터로 다른 메써드를 받을 수 있다. 이는 콜백 처리 등의 상황에서 유용하게 이용할 수 있다. [관련 링크]
class PassFunctionToMethodParameterTest {

    // String 타입을 반환하는 Function 을 파라메터로 받는다.
    private fun someFunction(param1: String, param2: String, param3: () -> String): String {

        return param3()
    }

    // 파라메터로 전달될 Function
    private fun parameterFunction(a: String, b: String): String {

        return "${a}${b}"
    }

    @Test
    fun passFunctionToMethodParameter() {

        // 파라메터를 전달한다.
        // foobar 를 출력한다.
        println(someFunction("korea", "seoul", { parameterFunction("foo", "bar") }))
    }
}

Kotlin 예외 처리

  • Java에서 Checked ExceptionRuntimeException을 제외한, Exception을 상속한 모든 예외 클래스를 범위로 가진다. Checked Exception의 특징은 메써드 내에서 반드시 해당 예외를 처리해야 한다. 처리하지 않고자 할 경우 메써드 레벨에 throws 구문을 명시해야 한다.(ex: throws IOException) 그렇지 않을 경우 컴파일 단계에서 오류가 발생한다.
  • KotlinChecked Exception을 일종의 불필요한 안티 패턴으로 규정하여 언어 레벨에서 제거해버렸다. 문제는, Kotlin으로 작성된 코드에서 Java로 작성된 코드를 호출할 때 발생하는 Checked Exception이다. 이 경우, 컴파일 단계를 건너 뛰고 런타임 단계에서 java.lang.reflect.UndeclaredThrowableException 예외가 발생하므로 유의해야 한다. 해결책은 메써드 레벨에 @Throws 구문을 명시하면 해결된다. 컴파일 단계에서 앞서 설명한 throws 구문으로 변경해주는 지시자 역할을 한다.
// Checked Exception이 상위에서 인지되어 처리
@Throws(IOException::class)
fun foobar() {
   ...
}
  • 만약, 해당 예외 클래스를 통제할 수 있다면 Exception이 아닌 RuntimeException을 상속하도록 수정하는 것이 가장 근본적인 해결책이라고 할 수 있다.

Spring에서의 @Autowired 주입

  • Java에서 Kotlin으로 전환했을 때, 가장 익숙하지 않은 부분이 바로 스프링 빈에서의 @Autowired를 이용한 의존성 주입이다. 가장 최선의 방법은 생성자에 주입할 빈을 아래와 같이 그냥 선언하는 것이다. (@Autowired을 명시하지 않아도 된다. 이러한 단일 생성자에 의한 암시적 의존성 주입은 Spirng 4.3부터 제공된다.) [관련 링크]
@Service
class FooBarServiceImpl: FooBarService(
    val fooRepository: FooRepository,
    val barRepository: BarRepository
) ...

먼저 읽어볼만한 글

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/03   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
글 보관함