티스토리 뷰

study/kotlin in action

2. 코틀린 기초

pansy0319 2022. 1. 1. 18:36
반응형

[Kotlin in Action - http://www.yes24.com/Product/Goods/55148593]

 

2.1 기본 요소: 함수와 변수

2.1.1 Hello, World!

fun main(args: Array<String>) {
    println("Hello, World!")
}
  • 함수를 선언할 때 fun 키워드를 사용한다
  • 파라미터 이름 뒤에 그 파라미터의 타입을 쓴다
  • 함수를 최상위 수준에 정의할 수 있다
  • 배열도 일반적인 클래스와 마찬가지다
  • 코틀린 표준 라이브러리는 여러 가지 표준 자바 라이브러리 함수를 간결하게 사용할 수 있게 감싼 래퍼(wrapper)를 제공한다
  • 줄 끝에 세미콜론(;)을 붙이지 않아도 된다

2.1.2 함수

  • 함수 선언은 fun 키워드로 시작한다
  • fun 다음에는 함수 이름이 온다
  • 함수 이름 뒤에는 괄호 안에 파라미터 목록이 온다
  • 함수의 반환 타입은 파라미터 목록의닫는 괄호 뒤에 오는데, 괄호와 반환 타입 사이를 콜론(:)으로 구분해야 한다
  • 코틀린 if는 문장(statement)이 아니고 결과를 만드는 식(expression)이다
    • 문(statement)와 식(expression)의 구분
      • 식은 값을 만들어 내며 다른 식의 하위 요소로 계산에 참여할 수 있는 반면
        문은 자신을 둘러싸고 있는 가장 안쪽 블록의 최상위 요소로 존재하며 아무런 값을 만들어내지 않는다
      • 코틀린에서는 루프를 제외한 대부분의 제어 구조가 식이다
      • 대입문은 자바에서 식이었으나 코틀린에서는 문이 됐다
  • 식이 본문인 함수
    • 블록이 본문인 함수 : 본문이 중괄호로 둘러싸인 함수
      식이 본문인 함수 : 등호와 식으로 이뤄진 함수
    • 식이 본문인 함수의 경우 굳이 사용자가 반환 타입을 적지 않아도 컴파일러가 함수 본문 식을 분석해서 식의 결과 타입을 함수 반환 타입으로 정해준다
      • 타입추론(type inference)컴파일러가 타입을 분석해 프로그래머 대신 프로그램 구성 요소의 타입을 정해주는 기능
    • 식이 본문인 함수의 반환 타입만 생략 가능하다

2.1.3 변수

  • 코틀린에서는 키워드로 변수 선언을 시작하는 대신 변수 이름 뒤에 타입을 명시하거나 생략하게 허용한다
  • 타입을 지정하지 않으면 컴파일러가 초기화 식을 분석해서 초기화 식의 타입을 변수 타입으로 지정한다
  • 초기화 식을 사용하지 않고 변수를 선언하려면 변수 타입을 반드시 명시해야 한다
  • 변경 가능한 변수와 변경 불가능한 변수
    • val(값을 뜻하는 value에서 따옴) : 변경불가능한(immutable) 참조를 저장하는 변수
      • 일단 초기화하고 나면 재대입이 불가능하다
      • 자바로 치면 final 변수
      • 블록을 실행할 때 정확히 한 번만 초기화돼야 한다
      • 참조 자체는 불변일지라도 그 참조가 가리키는 객체의 내부 값은 변경될 수 있다
    • var(변수를 뜻하는 variable에서 따옴) : 변경 가능한(mutable) 참조
      • 자바의 일반 변수에 해당
      • 변수의 값을 변경할 수 있지만 변수의 타입은 고정돼 바뀌지 않는다
    • 기본적으로는 모든 변수를 val 키워드를 사용해 불변 변수로 선언하고 나중에 꼭 필요할 때만 var로 변경해라
    • 변경 불가능한 참조와 변경 불가능한 객체를 부수효과가 없는 함수와 조합해 사용하면 코드가 함수형 코드에 가까워진다
    • 컴파일러는 변수 선언 시점의 초기화 식으로부터 변수의 타입을 추론하며, 변수 선언 이후 변수 재대입이 이뤄질 때는 이미 추론한 변수의 타입을 염두에 두고 대입문의 타입을 검사한다

2.4.1 더 쉽게 문자열 형식 지정: 문자열 템플릿

  • 문자열 템플릿(string template)
    • 문자열 리터럴의 필요한 곳에 변수를 넣되 변수 앞에 $를 추가하면 된당

 

2.2 클래스와 프로퍼티

  • 값 객체(value object) : 코드가 없이 데이터만 저장하는 클래스
  • 코틀린의 기본 가시성은 public

2.2.1 프로퍼티

  • 클래스의 목적 : 데이터를 캡슐화(encapsulate)하고 캡슐화한 데이터를 다루는 코드를 한 주체 아래 가두는 것
  • 자바에서는 필드(field, 데이터 저장)와 접근자(access method, 데이터에 접근하는 통로)를 한데 묶어 프로퍼티라고 부르는데
    코틀린의 프로퍼티(property)는 자바의 필드와 접근자 메소드를 완전히 대신한다
    • 클래스에서 프로퍼티를 선언할 때는 val(읽기 전용), var(변경 가능)을 사용한다
    • 기본적으로 코틀린에서 프로퍼티를 선언하는 방식은 프로퍼티와 관련 있는 접근자를 선언하는 것이다
    • 코틀린은 값을 저장하기 위한 비공개 필드와 그 필드에 값을 저장하기 위한 세터, 필드의 값을 읽기 위한 게터로 이뤄진 간단한 디폴트 접근자 구현을 제공한다
class Person(
    val name: String, // (비공개) 필드, (공개) 게터
    var isMarried: Boolean, // (비공개) 필드, (공개) 게터, (공개) 세터
)
  • 이름이 is로 시작하는 프로퍼티의 게터에는 get이 붙지 않고 원래 이름을 그대로 사용하며, 세터에는 is를 set으로 바꾼 이름을 사용한다
val person = Person("Bob", true) // new 키워드를 사용하지 않고 생성자를 호출한다
println(person.name) // 프로퍼티 이름을 직접 사용해도 코틀린이 자동으로 게터를 호출해준다
println(person.isMarried)
person.isMarried = false // 프로퍼티 이름을 직접 사용해도 코틀린이 자동으로 세터를 호출해준다
  • 대부분의 프로퍼티에는 그 프로퍼티의 값을 저장하기 위한 필드가 있다 -> 뒷받침하는 필드(backing field)
    • 커스텀 게터를 작성해서 프로퍼티 값을 그때그때 계산할 수도 있다

2.2.2 커스텀 접근자

class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean
        get() {	// 프로퍼티 게터 선언
            return height == width
        }
}
  • 클라이언트가 프로퍼티에 접근할 때마다 게터가 프로퍼티 값을 매번 다시 계산

2.2.3 코틀린 소스코드 구조: 디렉터리와 패키지

  • 코틀린 파일의 맨 앞에 package 문을 넣으면 그 파일 안에 있는 모든 선언이 해당 패키지에 들어간다
    • 같은 패키지에 속해 있다면 다른 파일에서 정의한 선언일지라도 직접 사용할 수 있다
    • 다른 패키지에 정의한 선언을 사용하려면 임포트를 통해 선언을 불러와야 한다
  • 코틀린에서는 클래스 임포트와 함수 임포트에 차이가 없으며, 모든 선언을 import 키워드로 가져올 수 있다
    • 최상위 함수는 그 이름을 써서 임포트할 수 있다
  • 패키지 이름 뒤에 .*를 추가하면(start import) 패키지 안의 모든 선언을 임포트할 수 있다
    • 패키지 안의 모든 클래스, 최상위 함수, 프로퍼티 를 모두 불러온다
  • 코틀린에서는 여러 클래스를 한 파일에 넣을 수 있고 파일의 이름도 마음대로 정할 수 있다
  • 코틀린에서는 디스크상의 어느 디렉터리에 소스코드 파일을 위치시키든 관계없다
  • 하지만 대부분의 경우 자바와 같이 패키지별로 디렉터리를 구성하는 편이 낫다

 

2.3 선택 표현과 처리: enum과 when

2.3.1 enum 클래스 정의

  • 코틀린에서 enum은 소프트 키워드로 class 앞에 있을 때만 특별한 의미를 지닌다
  • enum 클래스 안에 프로퍼티나 메소드, 생성자를 정의할 수 있다
  • enum 클래스 안에 메소드를 정의하는 경우 반드시 enum 상수 목록과 메소드 정의 사이에 세미콜론을 넣어야 한다

2.3.2 when으로 enum 클래스 다루기

fun getMnemonic(color: Color) = // 함수의 반환 값으로 when식을 직접 사용
    when (color) {
        Color.RED -> "Richard"
        Color.ORANGE -> "Of"
        Color.YELLOW -> "York"
        Color.GREEN -> "Gave"
        Color.BLUE -> "Battle"
        Color.INDIGO -> "In"
        Color.VIOLET -> "Vain"
    }
  • when도 값을 만들어내는 식
  • 자바와 달리 각 분기의 끝에 break를 넣지 않아도 된다
  • 한 분기 안에서 여러 값을 매치 패턴으로 사용할 수도 있다. 그럴 경우 값 사이를 콤마(,)로 분리한다

2.3.3 when과 임의의 객체를 함께 사용

fun mix(c1: Color, c2: Color) =
    when (setOf(c1, c2)) {
        setOf(RED, YELLOW) -> ORANGE
        setOf(YELLOW, BLUE) -> GREEN
        setOf(BLUE, VIOLET) -> INDIGO
        else -> throw Exception("Dirty color") // 매치되는 분기 조건이 없으면 이 문장을 실행
    }
  • 코틀린 when의 분기 조건은 임의의 객체를 허용한다
  • when 식의 인자로 아무 객체나 사용할 수 있다. when은 이렇게 인자로 받은 객체가 각 분기 조건에 있는 객체와 같은지 테스트한다
    • 여기서 동등성(equality)을 사용한다
  • when의 분기 조건 부분에 식을 넣을 수 있기 때문에 많은 경우 코드를 더 간결하고 아름답게 작성할 수 있다

2.3.4 인자 없는 when 사용

  • when에 아무 인자도 없으려면 각 분기의 조건이 Boolean 결과를 계산하는 식이어야 한다
    • 추가 객체를 만들지 않는다는 장점이 있지만 가독성은 더 떨어진다

2.3.5 스마트 캐스트: 타입 검사와 타입 캐스트를 조합

  • 클래스가 구현하는 인터페이스를 지정하기 위해서 콜론(:) 뒤에 인터페이스 이름을 사용
  • 코틀린에서는 is를 사용해 변수 타입을 검사한다
  • 스마트 캐스트
    • 어떤 변수가 원하는 타입인지 is로 검사하고 나면 굳이 변수를 원하는 타입으로 캐스팅하지 않아도 마치 처음부터 그 변수가 원한느 타입으로 선언된 것처럼 사용할 수 있다. 하지만 실제로는 컴파일러가 캐스팅을 수행해준다
    • 스마트 캐스트는 is로 변수에 든 값의 타입을 검사한 다음에 그 값이 바뀔 수 없는 경우에만 작동한다
    • 클래스의 프로퍼티에 대해 스마트 캐스트를 사용한다면 그 프로퍼티는 반드시 val이어야 하고 커스텀 접근자를 사용한 것이어도 안 된다
  • 원하는 타입으로 명시적으로 타입 캐스팅하려면 as 키워드를 사용한다

2.3.6 리팩토링: if를 when으로 변경

  • 코틀린에서는 if가 값을 만들어 내기 때문에 자바와 달리 3항 연산자가 따로 없다
  • if 분기에 블록을 사용하는 경우 그 블록의 마지막 식이 그 분기의 결과 값이다

2.3.7 if와 when의 분기에서 블록 사용

  • if나 when 모두 분기에 블록을 사용할 수 있고 그런 경우 블록의 마지막 분장이 블록 전체의 결과가 된다
  • '블록의 마지막 식이 블록의 결과'라는 규칙은 블록이 값을 만들어내야 하는 경우 항상 성립한다
  • 식이 본문 함수는 블록을 본문으로 가질 수 없고 블록이 본문인 함수는 내부에 return 문이 반드시 있어야 한다

 

2.4 대상을 이터레이션: while과 for 루프

  • for는 자바의 for-each 루프에 해당하는 형태만 존재

2.4.1 while 루프

while (조건) { // 조건이 참인 동안 본문을 반복 실행한다
    /*...*/
}

do { // 맨 처음에 무조건 본문을 한 번 실행한 다음,
     // 조건이 참인 동안 본문을 반복 실핸한다
    /*...*/
} while (조건)

2.4.2 수에 대한 이터레이션: 범위와 수열

  • 범위(range) : 두 값으로 이뤄진 구간
    • 보통은 그 두 값은 정수 등의 숫자 타입의 값이며 . 연산자로 시작 값과 끝 값을 연결해서 범위를 만든다
    • 코틀린의 범위는 폐구간(닫힌 구간)
    • step 으로 증가값을 나타낼 수 있음
      • ex) 100 downTo 1 step 2 : 100부터 1까지 2씩 작아지는 역방향 수열(100, 98, ... 2)
  • 수열(progression) : 어떤 범위에 속한 값을 일정한 순서로 이터레이션하는 경우
  • until 함수를 사용해서 반만 닫힌 범위를 할 수 있음
    • ex) x in 0 until size는 x in 0..size-1과 동일하다

2.4.3 맵에 대한 이터레이션

  • .. 연산자를 숫자 타입의 값뿐 아니라 문자 타입의 값에도 적용할 수 있다
  • get 과 put 을 사용하는 대신 map[key] 나 map[key]=value 를 사용해 값을 가져오고 설정할 수 있다
  • 맵에 상요했던 구조 분해 구문을 맵이 아닌 컬렉션에서도 사용할 수 있다
    • 구조분해 -> for((letter, binary) in binaryReps){... 요거
    • 구조 분해 구문을 사용하면 원소의 현재 인덱스를 유지하면서 컬렉션을 이터레이션할 수 있다
      인덱스를 저장하기 위한 변수를 별도로 선언하고 루프에서 매번 그 변수를 증가시킬 필요가 없다
val list  = arrayListOf("10", "11", "1001")
for ((index, element) in list.withIndex()) { // 인덱스와 함께 컬렉션을 이터레이션한다
    println("$index: $element")
}

2.4.4 in으로 컬렉션이나 범위의 원소 검사

  • in 연산자를 사용해 어떤 값이 범위에 속하는지 검사할 수 있음
    !in을 사용하면 어떤 값이 범위에 속하지 않는지 검사할 수 있음
    • when 식, 컬렉션에서 사용해도 된다
  • 비교가 가능한 클래스라면(java.lang.Comparable 인터페이스를 구현한 클래스라면) 그 클래스의 인스턴스 객체를 사용해 범위를 만들 수 있다
    • Comparable을 사용하는 범위의 경우 그 범위 내이 모든 객체를 항상 이터레이션하지는 못한다
    • 하지만 in연산자를 사용하면 값이 범위안에 속하는지 항상 결정할 수 있다

 

2.5 코틀린의 예외 처리

  • 예외 인스턴스를 만들 때 new를 붙일 필요가 없다
  • 코틀린의 throw는 식이므로 다른 식에 포함될 수 있다

2.5.1 try, catch, finally

  • 함수가 던질 수 있는 예외를 명시할 필요가 없음 -> throws 절을 안 적어도 된다
    • 코틀린은 체크 예외(checked exception)과 언체크 예외(unchecked exception)을 구분하지 않는다

2.5.2 try를 식으로 사용

  • 코틀린의 try는 식이므로 try의 값을 변수에 대입할 수 있다
  • if와 달리 try의 본문을 반드시 중괄호 {}로 둘러써야 한다
  • try의 본문도 내부에 여러 문장이 있으면 마지막 식의 값이 전체 결과 값이다
  • catch 블록도 그 안의 마지막 식이 블록 전체의 값이 된다

 

2.6 요약

  • 함수를 정의할 때 fun 키워드를 사용한다. val과 var는 각각 읽기 전용 변수와 변경 가능한 변수를 선언할 때 쓰인다
  • 문자열 템플릿을 사용하면 문자열을 연결하지 않아도 되므로 코드가 간결해진다. 변수 이름 앞에 $를 붙이거나, 식을 ${식}처럼 ${ }로 둘러싸면 변수나 식의 값을 문자열 안에 넣을 수 있다
  • 코틀린에서는 값 객체 클래스를 아주 간결하게 표현할 수 있디
  • 디른 언어에도 있는 if는 코틀린에서 식이며, 값을 만들어낸다
  • 코틀린 when은 자바의 swtich와 비슷하지만 더 강력하다
  • 어떤 변수의 타입을 검사하고 나면 굳이 그 변수를 캐스팅하지 않아도 검사한 타입의 변수처럼 사용할 수 있다. 그런 경우 컴파일러가 스마트 캐스트를 할용해 자동으로 타입을 바꿔준다
  • for, while, do-while 루프는 자바가 제공하는 같은 키워드의 기능과 비슷하다. 하지만 코틀린의 for는 자바의 for보다 더 편리하다. 특히 맵을 이터레이션하거나 이터레이션하면서 컬렉션의 원소와 인덱스를 함께 사용해야 하는 경우 코틀린의 for가 더 편리하다
  • 1..5와 같은 식은 범위를 만들어낸다. 범위와 수열은 코틀린에서 같은 뭄법을 사용하며, for 루프에 대해 같은 추상화를 제공한다. 어떤 값이 범위 안에 들어 있거나 들어있지 않은지 검사하기 위해서 in이나 !in을 사용한다
  • 코틀린 예외 처리는 자바와 비슷하다. 다만 코틀린에서는 함수가 던질 수 있는 예외를 선언하지 않아도 된다
반응형

'study > kotlin in action' 카테고리의 다른 글

부록E. 코루틴과 Async/Await  (0) 2022.04.18
3. 함수 정의와 호출  (0) 2022.01.09
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
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
글 보관함