Kotlin in Action - 1,2장

김정욱·2021년 9월 27일
2

Kotlin

목록 보기
1/5
post-thumbnail

해당 글은 Kotlin in Action 도서를 읽으며 정리한 내용입니다

[1장] 코틀린이란 무엇이며 왜 필요한가

코틀린의 주요 특성

[ 정적 타입 지정 언어 ]

  • 특징
    • 모든 프로그램 구성 요소의 타입컴파일 시점에 알 수 있다
    • 객체의 필드나 메소드를 사용할 때 마다 컴파일러타입을 검증
    • Java와 달리 '타입 추론(type inference)' 를 통해 컴파일러가 문맥을 고려해 변수 타입을 결정
      --> 모든 변수의 타입을 프로그래머가 직접 명시할 필요가 없음
    • 널이 될 수 있는 타입(nullable type)을 지원
  • 장점
    • 성능
      • 실행 시점에 어떤 메소드를 호출할지 알아내는 과정이 필요 없어서, 메소드 호출이 빠르다
    • 신뢰성
      • 컴파일러가 프로그램의 정확성(correctness)를 검증해서 실행시 프로그램이 오류로 중단될 가능성이 적다
    • 유지 보수성
      • 코드에서 다루는 객체가 어떤 타입에 속하는지 알 수 있기 때문에 처음 보는 코드를 다루기 쉽다
    • 도구 지원
      • 안전하게 리팩토링 가능
      • 도구는 더 정확한 코드 완성 기능을 제공 가능
  • 동적 타입 언어란? (ex: 그루비 / JRuby)
    • 타입과 관계 없이 모든 값을 변수에 넣을 수 있다
    • 메소드나 필드 접근에 대한 검증이 실행 시점에 일어난다
      • 장점 : 코드가 짧고, 데이터 구조가 유연
      • 단점 : 컴파일 시 간단한 타입 오류도 체크하지 못하고, 실행시점에 체크

[ 함수형 프로그래밍 ]

  • 함수형 프로그래밍의 특징
    • 일급 시민인(first-class) 함수
      • 함수를 일반 값(value)처럼 사용 가능
        => 변수에 저장 / 파라미터로 전달 등
    • 불변성(immutability)
      • 일단 만들어지고 나면 내부 상태가 절대로 바뀌지 않는 불변 객체를 사용해 프로그램을 작성
    • 부수 효과(side effect) 없음
      • 입력이 같으면 항상 같은 출력을 낸다
      • 다른 객체의 상태를 변경하지 않고, 함수 외부와 상호작용 하지 않는 순수 함수(pure function)을 사용
  • 함수형 프로그래밍 장점
    • 코드의 간결성
      • 순수함수를 통해 더 강력한 추상화 가능
      • 코드 중복을 줄일 수 있음
    • 다중 스레드 안정성
      • 불변 데이터 구조와 순수 함수를 통해 같은 데이터를 여러 스레드가 변경하지 못하게 한다
    • 테스트의 용이성
      • 부수효과가 없어서 환경을 구성하기 위해 필요한 준비 코드(setup-code)가 필요하지 않다
        (독립적 실행 가능)

코틀린의 철학

[ 실용성 ]

  • 실제 문제를 해결하기 위해 만들어진 실용적인 언어
  • 항상 도구의 활용을 염두에 두고 설계되어 왔다
  • 더 간결한 구조로 바꾸는 대부분의 코드 패턴을 도구가 자동으로 감지해서 수정하라고 제안

[ 간결성 ]

  • 코드를 읽을 때 의도를 쉽게 파악할 수 있는 구문 구조를 제공
  • 의도를 달성하는 방법을 이해할 때 방해가 될 수 있는 부가적 코드가 적다
  • getter, setter 생성자 파라미터 등 부가적 코드를 묵시적으로 제공
  • 기능이 다양한 표준 라이브러리를 제공 => 반복되는 코드를 라이브러리로 대체 가능

[ 안전성 ]

  • 프로그램에서 발생할 수 있는 오류중에서 일부 유형의 오류를 프로그램 설계가 원천적으로 방지
  • 안전성과 생산성은 트레이드 오프(trade-off) 관계
    => 더 큰 안전성을 얻기 위해서는 더 많은 정보를 덧붙여야 하기 때문
  • JVM 기반으로 메모리 안전성 / 버퍼 오버플로 방지 / 동적 메모리 관리 측면의 안전성 제공
  • 타입 추론(type inference)을 통해서 적은 비용으로 타입 안전성 사용 가능
  • 컴파일 시점 검사를 통해 오류를 방지
  • ? 연산자를 통해 null이 될 수 있는지 여부를 표시 가능
  • 타입 검사(type check)와 캐스트(cast)가 한 연산자에 의해 이뤄진다

[ 상호 운용성 ]

  • 자바(Java) 코드에서 코틀린(Kotlin) 코드를 호출할 때에서 아무런 노력이 필요 없다
  • 자체 컬렉션 라이브러리 제공 X => 기존 자바 라이브러리를 가능하면 최대한 활용
  • Java와 Kotlin 코드가 섞여 있어도 컴파일 문제 X

[ 요약 ]

  • Kotlin은 타입 추론지원하는 정적 타입 지정 언어
  • Kotlin은 객체지향함수형 프로그래밍 스타일을 모두 지원한다
  • Kotlin은 일급 시민 함수를 사용해 높은 추상화가 가능하며, 불변 값 지원을 통해 다중 스레드 개발을 더 쉽게 할 수 있다
  • Kotlin은 무료오픈소스이다

[2장] 코틀린 기초

기본 요소 : 함수와 변수

[ 함수 ]

  • println()
    • Kotlin의 표준 출력
    • 표준 Java 라이브러리를 감싼 래퍼(wrapper)클래스의 일종
  • 식(expression)
    • 문(statement)와 다르게, 값을 만들어 내며 다른 식의 하위 요소로 계산에 참여
    • Java에서는 모든 제어 구조가 문(statement)였지만, Kotlin에서는 대부분의 제어 구조가 식(expression)
  • 식이 본문인 함수
    • 함수의 본문이 등호와 식으로 이루어진 함수
    • Kotlin에서 식이 본문인 함수가 매우 많이 사용된다
    • 식이 본문인 함수인 경우, 함수의 반환 타입이 생략 가능
      (블록이 본문인 함수는 불가능)
/* 반환타입 O */
fun max(a: Int, b: Int) : Int = if(a > b) a else b

/* 반환타입 X */
/* 컴파일러가 함수 본문을 분석해서 타입 추론(type inference)를 해줘서 생략 가능 */
fun max(a: Int, b: Int) = if(a > b) a else b

[ 변수 ]

  • val과 var (기본적으로 val을 권장)
    • val(value)
      • 변경 불가능한 참조를 저장하는 변수
      • 초기화하고 나면 재대입이 불가능
      • Java의 final에 해당
    • var(variable)
      • 변경 가능한 참조
      • Java의 일반변수에 해당
/* val 변수는 참조 자체는 불변, 참조가 가리키는 객체 내부 값은 변경 가능! */
val langs = arrayListOf("Java")
langs.add("Kotlin")
  • 초기화 식이 있는 경우 변수 타입을 생략할 수 있다
    • 초기화 식이 없으면 컴파일러가 추론할 수 없음;
    • 정수는 Int / 부동소수점 상수는 Double로 기본 추론
    • 컴파일러는 초기화식으로 부터 변수의 타입을 추론
/* 변수 타입 생략 전 */
val answer : Int = 3
/* 변수 타입 생략 후 */
val answer = 3;

[ 문자열 템플릿 ]

  • 문자열 템플릿(string template)
    • 문자열 리터럴 안에서 변수를 사용하는방법
    • $ 연산자를 통해서 변수를 사용 가능
    • ${} 처럼 중괄호를 쓰면 식을 대입할 수 있다
    • 문자 $를 넣고 싶다면 \$ 처럼 역슬래시를 사용
    • 한글 처리를 할 때에도 $만 쓰면 오류
      -> 이러한 오류들이 있어서 ${} 로 문자열 템플릿을 쓰는 습관을 권장
val name : String = "hue"
println("${name}님 반갑습니다.")

클래스(class)와 프로퍼티(property)

[ 값 객체 ]

  • 코드가 없이 데이터만 저장하는 클래스
/* Kotlin은 기본적으로 public 접근제한자를 사용해서 생략 가능 */
class Person (val name: String)

[ 프로퍼티(property) ]

  • 필드와 접근자를 묶어 말하는 것
  • Kotlin에서는 val과 var을 사용 + getter, setter도 함께 제공
    • val
      • 읽기 전용
      • getter만 제공
    • var
      • 읽기 / 쓰기 가능
      • getter / setter 모두 제공
class Person{
  val name: String // 읽기 전용, getter만 존재
  var isMarried: Boolean // 읽기, 쓰기 가능, getter setter 모두 존재
}

/* 객체 생성, Kotlin에서는 new 연산자 사용 X */
val person = Person("Hue", false) 

/* Java와 다르게 필드의 이름으로 직접 접근 */
println(person.name)
println(person.isMarried)

/* setter역시 이름으로 접근 */
person.isMarried = true

enum과 when

[ enum 클래스 ]

  • 정의
    • enum은 유일하게 Java보다 Kotlin 선언에서 더 많은 키워드를 쓴다;
    • enum class 키워드 사용
enum class Color {
  RED, ORANGE, YELLOW, GREEN 
}
  • 프로퍼티와 메소드를 갖는 enum
enum class Color {
  val r: Int, val g: Int, val b: Int
}{
  /* 상수 생성시 프로퍼티 값을 지정할 때 반드시 마지막에 세미콜론(;) 필요 */
  RED(255,0,0), ORANGE(255,165,0), YELLOW(255,255,0), GREEN(0,255,0);
  fun rgb() = (r * 256 + g) * 256 + b
}

[ when ]

  • 다른 언어의 Switch와 키워드와 같은 역할
  • 분기 조건에 상수만을 사용하는 Java의 Switch와 달리, Kotlin은 임의의 객체를 허용
  • when에 아무 인자가 없으면 -> 각 분기의 조건이 Boolean 결과를 계산하는 식이어야 한다
/* 값을 Set객체로 만드는 setOf() 메소드 사용 */
fun mix(c1: Color, c2: Color) = 
  when(setOf(c1, c2)){
    setOf(RED, YELLOW) -> ORANGE
    setOf(RED, GREEN) -> YELLOW
    else -> BLACK
  }

[ 스마트 캐스트 ]

  • 스마트 캐스트(smart cast)
    • 타입 검사(type check)와 타입 캐스트(type cast)를 한번에 해결
    • Kotlin에서는 is 키워드를 사용해서 변수의 타입을 검사
    • Java는 타입검사 이후 사용하려면 명시적으로 타입 캐스트를 해줬어야 했다
      => Kotlin은 타입을 검사할 때 파악해서 컴파일러가 대신 해준다!
    • 주의
      • 반드시 값이 바뀔 수 없는 val 이어야 한다 (커스텀 접근자도 X)
        => 그렇지 않으면 항상 같은 타입을 반환한다고 보장할 수 없기 때문
      • var이라서 명시적으로 타입 캐스팅(type casting)을 하려면 as 키워드 사용
/* is 키워드로 e의 타입을 검사 */
if(e is Sum) {
  /* 타입을 검사하며 컴파일러가 e의 캐스팅을 해주기 떄문에 명시적 캐스팅 필요 X -> 바로 사용 가능! */
  return eval(e.right) + eval(e.left)
}
  • 블록(Block) 사용
    • if나 when에서 Block을 사용할 경우 마지막 문장이 블록 전체의 결과가 된다
    • 블록이 본문인 함수인 경우에 해당
      => 내부에 반드시 return을 가지고 있어야 하기 때문
fun eval(e: Expr): Int = 
  when(e) {
    is Num -> {
     ...
     e.value // 결과(return)
    }
    is Sum -> {
      ...
      ...
      e.value + 5 // 결과(return)
    }
  }

While / for 루프

[ while ]

  • Java의 while과 동일
    • while / do~while 존재

[ for ]

  • Java의 for 루프처럼 초깃값, 증가 값, 최종 값을 사용한 루프가 없다
  • 이를 대신하기 위해 범위(range)를 사용
    • 기본적으로 for(v in array) 구문 사용
    • Kotlin의 구간은 폐구간(close)이다 => 양 끝을 포함하는 구간
    • .. 연산자를 통해서 범위 지정
    • 1..10 처럼 범위에 속한 정수를 일정한 순서로 이터레이션 하는 경우를 '수열' 이라고 함
  • 관련 키워드
    • untill : 끝 값을 제외
    • downTo : 역방향을 만드는 키워드
    • step : 증가값을 설정
/* 기본 */
for( value in array ) => value이 array의 요소를 순회
/* .. 연산자 */
for( i in 1..100 ) => i가 1부터 100까지 순회
for( c in 'a'..'z' ) => c가 'a'부터 'z'까지 순회
for( c in 'A'..'Z' ) => c가 'A'부터 'Z'까지 순회
/* step 키워드 */
for( i in 1..100 step 2 ) => i가 1부터 100까지 순회하는데 2개의 스텝으로 이동., 1,3,5,7,999 해당
/* untill 키워드 */
for( i in 1 until 100 ) => 1부터 100 아래인 99까지 순회
/* 비구조화 할당으로도 접근 가능 */
for( (name, age) in person ) => 인덱스와 값을 동시에 참조 가능

[ in ]

  • in 연산자
    • 어떤 값이 범위에 속하는지 검사하는 연산자
    • !in 은 속하지 않는지를 검사할 수 있음
    • 내부적인 로직은 라이브러리의 범위 클래스 구현 안에 숨겨져 있음
/* when에서 사용 */
fun recognize(c: Char) = when(c) {
  in '0'..'9' -> "digit!"
  in 'a'..'z', 'A'..'Z' -> "letter!"
  else -> "I don't know"
}

/* 특정 문자열 비교 */
println("Kotlin in setOf("Java", "Scala")") // false

Kotlin 예외 처리

  • Java처럼 try ~ catch ~ finally 사용
  • Kotlin에서는 함수가 던질 수 있는 예외를 선언하지 안아도 된다 (throws)
  • try의 본문은 반드시 중괄호 {} 로 둘러 싸야 한다
  • Kotlin은 체크 예외(checked exception)와 언체크 예외(unchecked exception)를 구분하지 X
    • 체크 예외(checked exception) : Exception 및 하위
    • 언체크 예외(unchecked exception) : RuntimeException 및 하위
    • 예외처리를 강제하는 것이 오히려 불필요한 코드를 만드는경우가 많아서 최신 언어에서는 구분 X
/* ? 연산자가 있으면 nullable type을 의미 */
fun readNumber(reader: BufferReader): Int? {
  try{
    val line = reader.readLine()
    return Integer.parseInt(lint)
  }
  catch(e: NumberFormatException){
    return null
  }
  finally{
    reader.cloase()
  }
}

[ 요약 ]

  • 함수를 정의할 때 fun 키워드를 사용하며, valvar은 각각 읽기 전용 변수변경 가능한 변수를 선언할 때 사용
  • 문자열 템플릿을 통해서 ${}{} 로 변수나 식의 값을 문자열 안에 넣을 수 있다
  • if는 Kotlin에서 이며, 을 만들어 낸다
  • Kotlin의 when은 타 언어의 switch와 유사하지만 강력하다
  • Kotlin 컴파일러스마트 캐스트를 통해 타입 검사를 한 뒤, 캐스팅 없이 사용할 수 있도록 지원한다
  • Kotlin의 예외 처리는 Java와 비슷하지만, 함수가 던질 수 있는 예외를 선언하지 않아도 된다(throws)
profile
Developer & PhotoGrapher

0개의 댓글