본문으로 바로가기
반응형


이 글은 Kotlin In Action을 참고 하였습니다.

더욱 자세한 설명이나 예제는 직접 책을 구매하여 확인 하시기 바랍니다

본격적으로 코틀린의 코드에 대해서 설명합니다.


2.1 기본요소: 함수, 변수

2.1.1 Hello world

코틀린을 시작했으니, Hello, world를 찍어보겠습니다.

fun main(args: Array<String>) {
    println("Hello, world!")
}
  • fun: 함수임을 나타내는 키워드 입니다.
  • main: 함수 이름이겠죠? 
  • (args: Array<Sting>): 함수인자를 표기할때 "변수명: 타입" 순서로 씁니다. 여기서 제너릭은 자바와 같습니다.
  • println("Hello, world!"): System.out.println을 println으로 간단하게 사용할 수 있습니다. 이는 표준 자바 라이브러리 함수를 간소화해주는 wrapper를 제공하기 때문입니다.


2.1.2 함수

fun max(a: Int, b: Int): Int {
    return if (a > b) a else b
}

fun main(args: Array<String>) {
    println(max(1, 2))
}

먼저 max 함수에서 return 값으로 if~else문을 사용했습니다.

자바에서는 3항연산자를 사용해서 아래와 같이 했어야 했습니다만, Kotlin에서 if문은 expression이기 때문에 위와 같이 사용이 가능합니다.

//Java
public int max(int a, int b) {
    return a > b ? a : b
}


여기서 expression은 값을 반환하는 형태이고 statement는 아무런 값을 만들어 내지 않습니다.

자바에서는 모든 제어문이 statement이나, kotlin에서는 반복문만 제외하고는 모두 expression입니다.

따라서 아래와 같이 쓸수도 있습니다.

//if문은 expression
fun max(a: Int, b: Int): Int = if (a > b) a else b

// type inference를 이용한 추가 간소화
fun max(a: Int, b: Int): = if (a > b) a else b


인텔리J에서는 block 형태와 expression 형태의 함수를 서로 변환하는것을 메뉴로 만들어 두고 있습니다.

  • Convert to expression body
  • Convert to block body


두번째 예제에서는 type inference를 컴파일러에서 해주기 때문에 return type을 생략할 수 있습니다.

단, expression 형태의 함수에서만 가능합니다.


2.1.3 변수

코틀린 변수는 반드시 val, 또는 var로 시작해야 합니다.
이 키워드는 변수의 시작을 알리면서 변수가 immutable type인지 mutable type인지를 나타냅니다.
따라서 val로 지정된 불변타입변수는 추후에 값을 변경할 수 없으며, 변경시 compile error가 납니다.
Java의 final과 같습니다.

mutable 변수인 var는 계속 값을 바꾸어 넣을 수 있는 일반 자바 변수와 같습니다.


// 불변 변수
val name = "hong"

// 가변 변수
var subject:String = "music"

// 초기화
val grade: Int
grade = 1

변수역시 타입추론이 가능합니다.

또한 초기화시 값을 할당하지 않는다면 반드시 type을 명시해야 합니다.


2.1.4 문자열 템플릿

코틀린은 문자열을 만들때 "$"기호를 이용하여 좀더 쉬운 방법으로 문자를 조합할 수 있도록 도와 줍니다.

fun main(args: Array<String>) {
    val name = if (args.size > 0) args[0] else "Kotlin"
    println("Hello, $name!")
}

위 예제처럼, "~~~ $name!" 사이에 변수를 넣으면 해당 변수가 string이 되어 문자열이 완성됩니다.

Java에서 + "..." + 변수 + "..." 이런 식보다 훨씬 간결해 집니다.


fun main(args: Array<String>) {
    if (args.size > 0) {
        println("Hello, ${args[0]}!")
    }
}

fun main(args: Array<String>) {
    println("Hello, ${if (args.size > 0) args[0] else "someone"}!")
}


단순히 변수가 아니라 추가적인 기능인 함수 호출이 된다면, 위와 같이 ${...} block으로 사용해야 합니다.

ex) ${args[0].size}

반대로 {} 안에서는 문자를 표기하기 위해 ${name "입니다."} 처럼 나타낼 수 있습니다.


추가적으로 한글같은 경우 "안녕 $name" 이라고 하면 컴파일러가 전체를 변수로 인식하면서 오류가 발생합니다.
이런경우 ${name} 처럼 블럭으로 묶어서 사용해야 합니다. 


2.2 클래스와 프로퍼티 (Class & Property)

코틀린에서 함수나, 변수에 한정자를 명시적으로 나타내지 않으면 모두 public 입니다.


2.2.1 property

자바에서 property란, 멤버변수와 이 멤버변수의 getter, setter를 의미합니다. (꼭 정확하지는 않습니다)

코틀린에서는 이런게 분리되어 있는 property를 간단하게 표시할 수 있도록 하는 요소를 가지고 있습니다.

즉 멤버 변수를 선언하면, 그에 따른 getter, setter는 컴파일러가 자동으로 생성해 줍니다.


class Person(
    val name: String //불변이므로 읽기전용이며, 컴파일러가 getter만 생성한다. 
    var isMarried: Boolean // 읽고 쓰기가 가능한 var type 변수 이므로 컴파일러가 자동으로 getter / setter를 만들어 낸다.
)

fun main(args: Array<String>) {
    val person = Person("Bob", true)
    println(person.name) // 실제로는 getter가 불린다.
    println(person.isMarried) //실제로는 getter가 불린다.
}
Person이란 class를 만들어 이름과 결혼 여부를 나타내는 멤버변수를 만들었습니다.
단 두줄만 class에 추가 했지만 사실 컴파일러가 자동으로 gettersetter를 만들어 줍니다.
물론 코드상에 보이지는 않죠~

일반 변수 이름을 경우 "getName" 처럼 "get"이나 "set"을 붙인 함수를 자동 생성 합니다.
따라서 자바에서는 "person.getName()"으로 값을 얻거나 set 할수 있습니다.

단 "isXXXX"인 이름의 멤버변수의 경우 setter에만 set을 붙이고 getter에서는 "isXXXX"를 그대로 사용합니다.
예) person.isMarried() / person.setMarried(true)


2.2.2 Custom property

물론 getter와 setter에 특정 구현부를 넣고 싶은 경우도 있습니다.
이런 경우 직접 get()과 set() 메서드를 구현하여 넣을 수 있습니다.
class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean
        get() {
            return height == width
        }
}

fun main(args: Array<String>) {
    val rectangle = Rectangle(41, 43)
    println(rectangle.isSquare)
}

위 예제에서 isSquare란 변수의 getter를 직접 만들었습니다.
간략하니, 코드만 봐도 이해가 가시죠?

2.2.3 Directory & package

자바에서는 Directory 구조와 package 구조는 동일합니다.
또한 class의 이름이 java 파일의 이름이 되어야 합니다.
또한!! 기본적으로 class에는 하나의 class만 만들도록 되어 있습니다.

당연해서 제약이 인줄 몰랐던 것들이죠?

코틀린에서는 아래와 같은일들이 가능합니다.
  • 여러 클래스를 한 파일에 넣는다
  • 파일 이름을 마음대로 할 수 있다
  • 소스파일을 상관없는 디렉토리에 위치 시킬수 있다.

그리고 위치가 다르더라도 package를 같게 선언하면 다른 파일에 선언한 정의도 사용할 수 있습니다.
물론 다른 패키지에 접근하려면 import를 하면 됩니다.

package geometry.shapes

import java.util.Random

class Rectangle(val height: Int, val width: Int) {
    val isSquare: Boolean
        get() = height == width
}

fun createRandomRectangle(): Rectangle {
    val random = Random()
    return Rectangle(random.nextInt(), random.nextInt())
}

사실 이런 부분들은 java와 마찬가지로 IDE에서 자동으로 해줍니다.

하지만 개념을 알고 지나가야겠죠? ㅎㅎ


마지막으로 이런거 막무가내??로 사용이 가능하지만 가능한 JAVA와 package 형태나 class 이름등의 구조를 맞추는것이 좋습니다.

보톤 Java와 kotlin을 같이 사용하기 때문입니다.

(뭐 kotlin으로 100% 만든다면야...)


반응형