코틀린이란

코틀린은 간결하고, 실용적이며, 자바 코드와의 상호운용성을 중시한다.

→ 현재 자바가 사용중인 곳이라면 거의 대부분 코틀린을 활용할 수 있다

1.1 코틀린 맛보기

data class Person(
    val name: String,
    val age: Int? = null
)

fun main() {
    val persons = listOf(Person("영희"), Person("철수", age = 29))
    val oldest = persons.maxByOrNull { it.age ?: 0 } // maxBy가 deprecated 됨
    println("나이가 가장 많은사람: $oldest")
}

| 추가적으로 leetcode 에서는 maxBy() 는 deprecated 되어 있지 않아 maxBy() 를 사용해야 한다.

it이라는 이름을 사용하면 별도로 파라미터 이름을 정의하지 않아도 람다식의 유일한 인자를 사용할 수 있다.

엘비스 연산자(Elvis operator)라고 부르는 ?: 는 age가 null인 경우 0을 반환하고, 그렇지 않은 경우 age의 값을 반환한다.

1.2 코틀린의 주요 특성

1.2.1 대상 플랫폼: 서버 안드로이드 등 자바가 실행되는 모든 곳

  • 서버상의 코드(백엔드)

  • 안드로이드 디바이스에서 실행되는 모바일 애플리케이션

자바뿐 아니라 자바스크립트도 코틀린을 컴파일 할 수 있다.

→ 코틀린 코드를 브라우저나 노드에서 실행할 수 있다.

1.2.2 정적 타입 지정 언어

자바와 마찬가지로 코틀린도 정적(statically typed) 지정 언어다.

정적 타입 지정은 모든 프로그램 구성 요소의 타입을 컴파일 시점에 알 수 있고 프로그램 안에서 객체의 필드나 메소드를 사용할 떄마다 컴파일러가 타입을 검증해준다는 뜻이다.

동적 타입(dynamically typed) 지정 언어와는 다르다.(예시: Groovy, JRuby)

동적 타입 지정 언어에서는 타입과 관계없이 모든 값을 변수에 넣을 수 있고, 메소드나 필드 접근에 대한 검증이 실행 시점에 일어나며, 그에 따라 코드가 더 짧아지고 데이터 구조를 더 유연하게 생성하고 사용할 수 있다.

다만 반대로 이름을 잘못 입력하는 등의 실수로 컴파일 시 걸러내지 못하고 실행 시점에 오류가 발생한다.


코틀린에서는 모든 변수의 타입을 직접 명시할 필요가 없다. 컴파일러가 문맥을 고려해 변수 타입을 결정하는 이런 기능을 타입 추론(type inference)라고 한다.

정적 타입 지정의 장점은 다음과 같다.

  • 성능: 실행 시점에 어떤 메소드를 호출할지 알아내는 과정이 필요 없으므로 메소드 호출이 더 빠르다.

  • 신뢰성: 컴파일러가 프로그램의 정확성(correctness)을 검증하기 때문에 실행 시 프로그램이 오류로 중단될 가능성이 더 적어진다.

  • 유지 보수성: 코드에서 다루는 객체가 어떤 타입에 속하는지 알 수 있기 때문에 처음 보는 코드를 다룰 때도 더 쉽다.

  • 도구 지원: 더 안전하게 리팩토링이 가능하며 도구는 더 정확한 코드 완성 기능을 제공할 수 있다.

가장 중요한 특성은 코틀린이 널이 될 수 있는 타입(nullable type)을 지원한다는 점이다.

널이 될 수 있는 타입을 지원함에 따라 컴파일 시점에 널 포인터 예외(NPE)가 발생할 수 있는지 여부를 검사할 수 있어서 좀 더 프로그램의 신뢰성을 높일 수 있다.

코틀린의 타입 시스템에 있는 다른 새로운 내용으로는 함수 타입(function type) 에 대한 지원을 들 수 있다.

1.2.3 함수형 프로그래밍과 객체지향 프로그래밍

함수형 프로그래밍의 핵심 개념

  • 일급 시민인 함수(first-class): 함수를 일반 값처럼 다룰 수 있다. 함수를 변수에 저장할 수 있고, 함수를 인자로 다른 함수에 전달할 수 있으며, 함수에서 새로운 함수를 만들어서 반환할 수 있다.

  • 불변성(immutability): 함수형 프로그래밍에서는 일단 만들어지고 나면 내부 상태가 절대로 바뀌지 않는 불변 객체를 사용해 프로그램을 작성한다.

  • 부수 효과(side effect) 없음: 입력이 같으면 항상 같은 출력을 내놓고 다른 객체의 상태를 변경하지 않으며, 함수 외부나 다른 바깥 환경과 상호작용하지 않는 순수 함수(pure function)을 사용한다.

함수형 스타일로 프로그램을 작성하면 좋은점

  1. 간결성: 함수형 코드는명령형 코드에 비해 더 간결하고 우아하다. 함수를 값처럼 활용할 수 있으면 더 강력한 추상화를 할 수 있고 강력한 추상화를 사용해 코드 중복을 막을 수 있다.

    • 람다 식이라 불리는 익명함수 구문을 사용하면 간결하게 그런 함수를 표현할 수 있다.

    fun findAlice() = findPerson {it.name == "Alice"}
    // 중괄호 사이에 있는 코드 블록은 찾으려는 사람을 식별함
  2. 다중 스레드를 사용해도 안전하다(safe multithreading): 다중 스레드 프로그램에서는 적절한 동기화 없이 같은 데이터를 여러 스레드가 변경하는 경우 가장 많은 문제가 생긴다. → 불변 데이터 구조를 사용하고 순수 함수를 사용하면 여러 스레드가 변경할 수 없다. → 복잡한 동기화를 적용하지 않아도 된다.

  3. 테스트 하기 쉽다: 순수 함수는 그런 코드 없이 독립적으로 테스트 할 수 있다.

코틀린의 함수형 프로그래밍 지원

  • 함수 타입을 지원함에 따라 어떤 함수가 다른 함수를 파라미터로 받거나 함수가 새로운 함수를 반환할 수 있다.

  • 람다 식을 지원함에 따라 번거로운 준비 코드를 작성하지 않아도 코드 블록을 쉽게 정의하고 여기저기 전달할 수 있다.

  • 데이터 클래스는 불변적인 값 객체(value object)를 간편하게 만들 수 있는 구문을 제공한다.

  • 코틀린 표준 라이브러리는 객체와 컬렉션을 함수형 스타일로 다룰 수 있는 API를 제공한다.

1.2.4 무료 오픈소스

1.3 코틀린 응용

1.3.1 코틀린 서버 프로그래밍

코틀린의 HTML 생성 라이브러리

fun renderPersonList(persons: Collection<Person>) {
    createHTML().table {
        for (person in persons) {
            tr {
                td { +person.name}
                td { +person.age}
            }
        }
    }
}

1.3.2 코틀린 안드로이드 프로그래밍

1.4 코틀린의 철학

1.4.1 실용성

1.4.2 간결성

게터(getter), 세터(setter), 생성자 파라미터를 필드에 대입하기 위한 로직 등 자바에 존재하는 여러 가지 번거로운 준비 코드를 코틀린은 묵시적으로 제공한다.

코틀린은 연산자 오버로딩(operator overloading)을 지원하지만, 언어가 제공하지 않는 연산자를 프로그래머가 정의할 수 있게 허용하지는 않는다.

1.4.3 안전성

JVM을 사용하면 메모리 안전성을 보장하고, 버퍼 오버플로를 방지하며, 동적으로 할당한 메모리를 잘못 사용함으로 인해 발생할 수 있는 다양한 문제를 예방할 수 있다.

JVM에서 실행되는 정적 타입 지정 언어로서 코틀린은 애플리케이션의 타입 안전성을 보장한다.

하지만 자바보다 더 적은 비용으로 타입 안전성을 사용할 수 있다.

가장 중요한 내용으로 코틀린은 프로그램의 NPE를 없애기 위해 노력한다. 코틀린의 타입 시스템은 Null이 될 수 없는 값을 추적하며, 실행 시점에 NPE가 발생할 수 있는 연산을 사용하는 코드를 금지한다.

어떤 타입이 널이 될 수 있는지 여부를 표시하기 위해서는 오직 ? 한 글자만 추가하면 된다.

val s: String? = null // null이 될 수 있음
val s2: String = ""    // null이 될 수 없음

이런 기능은 애플리케이션이 NPE로 인해 갑자기 중단되는 경우를 많이 줄여준다.

코틀린이 방지해주는 다른 예외로는 ClassCastException 이 있다. 어떤 객체를 다른 타입으로 캐스트 하기 전에 타입을 미리 검사하지 않으면 ClassCastException 이 발생할 수도 있다.

자바에서는 타입 검사와 그 직후 이뤄지는 타입 캐스트에서 같은 타입 이름을 반복 사용하는 것이 귀찮아서 타입 검사를 생략하는 개발자가 많다.

↔ 코틀린에서는 타입 검사와 캐스트가 한 연산자에 의해 이뤄진다.

→ 코틀린에서는 타입 검사를 생략할 이유가 없고, 검사를 생략하지 않으면 검사를 생략해서 생기는 오류가 발생할 일도 없다.

if (value is String)
		println(value.toUpperCase()) // 해당 타입의 메소드를 사용한다.

1.4.4 상호운용성

1.5 코틀린 도구 사용

1.5.1 코틀린 코드 컴파일

코틀린 소스코드를 저장할 때는 보통 .kt 라는 확장자를 파일에 붙인다.

가장 간단한 방식은 커맨드라인에서 kotlinc 명령을 통해 코틀린 코드를 컴파일 후 java 명령으로 그 코드를 실핸다.

kotlinc <소스파일 또는 디렉토> -include-runtime -d <jar >
java -jar <jar이>

1.5.6 자바-코틀린 변환기

메뉴 Code → Convert Java File to Kotlin File 선택하기

Last updated