본문 바로가기

Kotlin

Kotlin In Action - 2장. 코틀린 기초

함수와 변수

fun main(args: Array<String>) {
    println("Hello World$args")
}

 

 

  • 클래스 위에 선언 가능
  • 변수 선언 , 타입 선언
  • System.out.println 표준 라이브러리 함수를 wrapping 한 kotlin 표준 라이브러리임
  • 세미 콜론 없어도 됨
fun max(a:Int, b:Int) : Int {
  return if(a>b) a else b
}

식(expression)이 본문인 함수

fun max(a:Int,b:Int)=if(a>b) a else b
  • 인텔리제이에서는 이 둘의 변환을 지원해 준다 ( Convert to expression body, Convert to block body )
fun max(a:Int, b:Int) = if (a>b) a else b
  • 함수 return 타입 생략 가능
  • 이유 : 컴파일러가 함수 본문 식을 분석하여 식의 결과 타입을 함수 반환 타입으로 정해줌
    => 타입 추론 ( type inference )
  • 식이 본문인 함수만 생략 가능 ( 코틀린 개발 팀의 의도 -> block과 같이 긴 함수는 가독성을 위해 리턴 타입 필요 )

변수

val answer = 42
val answer:Int = 42
var yearsToCompute = 7.5e6 // 7.5 * 10^6

val answer: Int
answer=42
  • val : immutable 
  • var : mutable
  • 기본적으로 val을 사용하고 나중에 필요하다면 var로 변경하는 식의 코딩 권장 => 이유 : 이런 코드가 함수형 코드에 가까워짐
val message: String  // 초기화 한번만 가능하지만 이렇게 컴파일러가 확인할 수 있으면 아래와 같은 코드 가능
if(canPerformOperation()){
	message = "Success"
}
else {
	message = "Failed"
}
var answer = 42
answer = "no answer" // error : type mismatch
  • 컴파일러는 변수 선언 시점의 초기화 식으로부터 변수의 타입을 추론
  • 원시 타입의 변환 방법이 있는데 6.2.3절에 나온다

문자열 템플릿

fun main(args : Array<String>) {
	val name = if (args.size>0) args[0] else "Kotlin"
    println("Hello, $name" ) // string template 기능
    println("Hello, ${args[0]}" )
}
  • String template 사용시 주의점 : 한글+영어가 아래와 같이 붙어있으면 unresolved reference에러 발생
    -> {}로 감싸는게 좋은 습관
${name}님 반가워요
$name님 반가워요

클래스

class Person(val name: String)
  • 데이터만 저장하는 클래스 = 값 객체 ( value object )
  • 자바->코틀린으로 변환하면 public visibility modifier가 사라짐을 확인 할 수 있다. 왜냐하면 코틀린의 기본 가시성은 public이다.
코틀린의 기본 가시성이 public인 이유?
코틀린의 클래스는 기본적으로 final이다
https://dzone.com/articles/defending-public-by-default-in-kotlin


프로퍼티

class Person (
	val name: String, // 읽기 전용 프로퍼티 
    var isMarried: Boolean // 쓸 수 있는 프로퍼티
)


val person = Person("Ted", true)
println(person.name) // 코틀린이 자동으로 게터를 호출해 줌
println(person.isMarried)
class Person (
	var id = 0
      get() = 100
    var name = "Ted"
      set(value) { name = value }
)
public final void setName(@NotNull String value)
{
	Intrinsics.checkParamaeterIsNotNull(value,"value");
    this.setName(value);
}

자바로 변환된 코드를 보면 StackOverFlow 에러가 발생한다. 실제로 IntelliJ에서도 알려준다.

field 식별자는 오직 property 접근자에서만 사용 가능하다.

class Person {
	var name = "Ted"
    	set(value) { field = value }
}

커스텀 접근자

  • custom getter vs 파라미터가 없는 함수?
    • 구현 성능 차이 없음
    • 가독성 측면에서 custom getter
class Rectangle(val height:Int, val width:Int) {
	val isSquare: Boolean
    	get() { return height == width } // get()=height==width
       
}

enum, when

enum class Color {
	GREEN, BLUE;
}

enum class Color(
	val r: Int, val g: Int, val b: Int
) {
	RED(255,0,0);
    
    fun rgb() = (r*256 + g ) * 256 + b
}

println(Color.RED.rgb()) // 255
fun getMnemonic(color: Color) =
	when(color) {
    	Color.Red -> "Richard"
    }
    
  
fun getWarmth(color: Color) =
	when(color) {
    	Color.Red, Color.YELLOW -> "warm",
        Color.BLUE -> "cold"
    }
    
fun getWarmth(color: Color) = when(color) {
	RED, YELLOW -> "warm",
    BLUE -> "cold"
}

 

fun mix(c1:Color, c2:Color) {
	when(setOf(c1,c2)) {
    	setOf(RED,YELLOW) -> ORANGE
        else -> throw Exception("Dirty Color")
    }
}
  • 인스턴스 생성 낭비를 막기 위한 인자 없는 when 사용 -> But 가독성이 떨어짐..
fun mixOptimized(c1:Color, c2:Color) =
	when {
    	(c1 == RED && c2 == YELLOW ) -> ORANGE,
        (c1 == YELLOW && c2 == BLUE ) -> GREEN
        
        else -> throw Exception("dirty color")
    }

스마트 캐스트

/**
 * Smart cast
 */
interface Expr

class Num(val value: Int) : Expr
class Sum(val left: Expr, val right: Expr) : Expr

fun eval(e: Expr): Int {
    if (e is Num) {
        val n = e as Num
        return n.value
    }

    if (e is Sum) {
        return eval(e.right) + eval(e.left) // 캐스팅 명시할 필요 없음 ( IDE 에서 표시해줌ㅎㅎ )
    }
    throw IllegalArgumentException("Unknown expressions")
}

fun evalRefactor(e: Expr): Int {
    when (e) {
        is Num -> e.value
        is Sum -> eval(e.right) + eval(e.left)
        else -> throw IllegalArgumentException("Unknown expressions")
    }
}

예외처리

/**
 * exception
 * - throw 식 활용 ( 6.2.6 )
 * - 코틀린 개발자들은 일반 개발자들이 checked exception 을 제대로 쓰지 않다고 판단하여 코틀린에는 checked 안해도 되도록 구현
 */
val number = 10
val percentage =
    if (number in 0..100) number
    else throw IllegalArgumentException("number must be between 0 and 100 : ${number}")