Java보다 좋은 Kotlin으로 문제를 풀어 봅시다

Kotlin?

Kotlin은 IntelliJ, Android Studio, PyCharm 등의 IDE를 만든 체코의 JetBrains에서, 개발에 쓸 적절한 JVM 기반 언어를 찾아보다가 필요한 기능들이 없어서 포기하고(예외로 Scala가 있지만 컴파일 속도가 느려서 스킵) 직접 만든 언어입니다.

Kotlin은 기존 자바 코드와 100% 호환되면서도 자바보다 좋은 언어를 만드는 것을 목표로 개발되었습니다. 따라서 기존에 Java로 코딩하셨다면 java.util.* 등의 클래스를 그냥 바로 가져다 쓸 수 있어 적응하기 어렵지 않습니다. 게다가 함수형입니다.

백준 온라인 저지와 Codeforces는 Kotlin을 지원하고 있습니다. ICPC에서는 리저널마다 다르지만 월드 파이널에서는 Kotlin을 지원하고 있습니다. 안타깝게도 한국 리저널에서는 아직 Kotlin을 지원하지 않고 있습니다.

Java보다 지원되는 곳이 적어서 슬프긴 하지만, 쓸 수 있는 곳에서 쓴다면 Kotlin은 똑같은 Java 코드에 비해서 훨씬 직관적이고, 코드를 짜는 데 훨씬 적은 시간이 듭니다! Java 코드와 실행 시간 차이도 얼마 나지 않습니다. Kotlin의 언어 기능들을 이용한 여러 가지 예제를 봅시다.


코드 예제

1000. A + B - 입출력

import java.util.*

fun main(args: Array<String>) = with(Scanner(System.`in`)) {
    println(nextInt() + nextInt())
}
  • Java의 Scanner를 바로 갖다 쓸 수 있습니다. with 문을 쓰면 굳이 스캐너를 하나 선언하고 input.nextInt() 하지 않아도 그냥 nextInt()만 해도 됩니다. 물론 BufferedReader도 갖다 쓸 수 있어요!
  • Kotlin에서는 in이 키워드이기 때문에 저렇게 해주어야 합니다.
  • System.out.println()이 아니라 그냥 println() 입니다.
  • 세미콜론은 붙여도 되고 안 붙여도 됩니다!

10172. 개 - 입출력

fun main(args: Array<String>) = println(
"""|\_/|
|q p|   /}
( 0 )${"\"\"\""}\
|"^"`    |
||_/=\\__|
""")
  • 요런 입출력도 됩니다.

11022. A + B - 8 - 입출력

import java.util.*

fun main(args: Array<String>) = with(Scanner(System.`in`)) {
    for (i in 1..nextInt()) {
        val a = nextInt()
        val b = nextInt()

        println("Case $i: $a + $b = ${a + b}")
    }
}
  • $ 뒤에 변수명을 붙여서 바로 출력해버릴 수 있습니다.
  • ${} 안에 식을 넣어서 출력할 수도 있습니다.

2438. 별 찍기 - 1 - for 루프

import java.util.*

fun main(args: Array<String>) = with(Scanner(System.`in`)) {
    val n = nextInt()

    for (i in 1..n) {
        println("*".repeat(i))
    }
}
  • 모든 변수는 val (바뀌지 않는 변수) 혹은 var (바뀔 수 있는 변수) 입니다. BigDecimal b = input.nextBigDecimal() 같이 코드가 길어지지 않습니다.
  • for 문은 정수 범위를 받습니다. 1..nIntRange로서 for (i in 1..n)은 Java의 for (int i = 1; i <= n; i++)와 같습니다. 물론 IntRange는 모 언어처럼 1부터 n이 담겨 있는 배열을 만드는 게 아니라 그냥 범위만 지정해주는 것이므로 복잡도 걱정도 없습니다!
  • 또한 for (i in 0 until n)은 Java의 for (int i = 0; i < n; i++)와 같습니다.
  • Stringrepeat 할 수 있습니다.

15904. UCPC는 무엇의 약자일까? - when, if

import java.util.*

fun main(args: Array<String>) = with(Scanner(System.`in`)) {
    val str = nextLine()

    var i = 0
    for (c in str) when (i) {
        0 -> if (c == 'U') i++
        1, 3 -> if (c == 'C') i++
        2 -> if (c == 'P') i++
    }

    println("I " + (if (i == 4) "love" else "hate") + " UCPC")
}
  • for (c in str)str에 있는 모든 문자에 대해 루프를 돌리겠다는 뜻입니다.
  • Kotlin은 switch 문이 아닌 when 문을 씁니다. 위와 같은 식으로 동작하지만 다르게도 쓸 수 있습니다. 예를 들어..
    • when (i) { in 0..3 -> () } 같은 식
    • 아니면 소괄호 없이 그냥 when { i % 2 == 0 -> (); j % 3 == 0 -> () } 같은 식 - 엄청나게 많은 if문으로 코드가 길어지는 걸 막아줍니다.
  • Kotlin에서 if, when은 expression입니다. 그래서 println("I " + (if (i == 4) "love" else "hate") + " UCPC") 같은 게 됩니다.

10039. 평균 점수 - 배열, 배열 연산

import java.util.*

fun main(args: Array<String>) = with(Scanner(System.`in`)) {
    val arr = Array(5) { nextInt() }
    println(arr.sum() / 5)
}
  • Array(5) { nextInt() }크기가 5인 배열을 만듦과 동시에 원소들을 입력값으로 채워 넣습니다. 중괄호 안에 있는 식이 각 index마다 실행되는 방식입니다.
  • 물론 index를 쓸 수도 있습니다. Array(5) { i -> i * i }[0, 1, 4, 9, 16]을 만듭니다.
  • arr.sum()은 배열의 원소들의 합을 구합니다. arr.average()도 있지만 이건 Double입니다.

1978. 소수 찾기 - IntProgression

import java.util.*

fun main(args: Array<String>) = with(Scanner(System.`in`)) {
    val sieve = Array(1001) { true }
    sieve[0] = false
    sieve[1] = false

    for (i in 2..1000) {
        if (sieve[i]) {
            for (j in 2 * i..1000 step i) sieve[j] = false
        }
    }

    var primeCount = 0
    repeat(nextInt()) {
        if (sieve[nextInt()]) primeCount++
    }

    println(primeCount)
}
  • Array(1001) { true }는 크기가 1001인 배열을 만듦과 동시에 원소들을 true로 채워 넣습니다.
  • step i를 이용해서 IntRangeIntProgression으로 변합니다. 예상하셨겠지만 for (i in 1..n step x)는 Java의 for (int i = 1; i <= n; i += x)와 같습니다.
  • 또한 for (i in n downTo 1)은 Java의 for (int i = n; i >= 1; i--)와 같습니다.

15740. A + B - 9 - 연산자 오버로드

import java.util.*

fun main(args: Array<String>) = with(Scanner(System.`in`)) {
    println(nextBigInteger() + nextBigInteger())
}
  • 연산자를 오버로드할 수 있습니다. 저 코드를 자바로 쓰면 System.out.println(input.nextBigInteger().add(input.nextBigInteger()))가 됩니다. Java에는 연산자 오버로드가 없으니까요. 물론 일반적인 식 계산하듯이 우선순위도 전부 지켜집니다.

16212. 정열적인 정렬 - map, sort, joinToString

import java.io.BufferedReader
import java.io.InputStreamReader

fun main(args: Array<String>) = with (BufferedReader(InputStreamReader(System.`in`))) {
    readLine()
    val arr = readLine().split(' ').map { it.toInt() }.sorted()

    println(arr.joinToString(" "))
}
  • map은 배열의 모든 원소를 중괄호의 실행값으로 바꿔줍니다. 이 문제의 경우 들어온 문자열을 split 하면 배열 안에 있는 원소들도 문자열이라서, .map{ it.toInt() }를 해 주면 배열 내의 모든 원소가 Int가 됩니다.
  • 또한 Integer.parseInt(str)가 아니라 str.toInt() 인데, 이미 있는 클래스들에 확장 함수를 만들 수 있습니다. toInt()String 클래스에 있는 함수가 아니라 Kotlin STL의 다른 패키지(kotlin.text)에 있는 함수입니다.
  • .sorted()는 정렬된 List를 만듭니다. .sortedDescending()으로 내림차순 정렬도 가능하고, sortedBy() 혹은 sortedWith()Comparator를 이용해 정렬할 수도 있습니다.

이외에도..

  • 배열 연산: filter, join, intersect 등이 있습니다. 예를 들어, Array(10){ i -> i + 1 }.filter{ i -> i % 3 == 0 || i % 5 == 0 }을 하면 [3, 5, 6, 9, 10]이 됩니다.
  • 2-Tuple과 3-Tuple이 PairTriple이라는 이름으로 있고, Pair(1, 3) 같은 식으로 만들 수 있습니다. C++의 Pair와 비슷하게 pair.first, pair.second로 접근합니다. 특히 Pair(1, 3)1 to 3 같은 식으로 만들 수도 있습니다.
  • HashMapmap["str"] = 0 같은 식으로 접근할 수 있습니다. Java의 map.put("str", 0)과 같습니다.
  • C 계열의 typedef처럼 typealias가 있습니다. typealias PII = Pair<Int, Int> 같은 식으로 적어 두면 나중에 val arr = ArrayList<PII>() 같은 식으로 사용할 수 있습니다.
  • 위의 코드에서 보이듯이 new 키워드가 없습니다. ArrayList<Int>()가 생성자입니다.

Kotlin으로 개발과 PS를 하면서 느낀 건데 이건 Java 쓰지 말라고 만든 언어가 확실합니다. Kotlin은 지금까지 설명한 JVM 기반 언어를 제외하고도 자바스크립트로 컴파일되는 Kotlin/JS, 그리고 LLVM 위에서 네이티브로 돌아가는 Kotlin/Native(베타)가 개발되고 있고, JVM에서도 Kotlin STL의 존재 때문에 Kotlin으로 할 수 있는 걸 모두 Java에서 할 수 있는 건 아닙니다. 반면 Java가 할 수 있는 건 Kotlin으로 다 할 수 있습니다. IntelliJ를 쓰고 계시다면 소스 코드에서 Ctrl + Shift + Alt + K를 눌러보세요, Java 코드가 몇 초 안 걸려 Kotlin 코드로 자동 변환됩니다!

Kotlin은 Try Kotlin에서 해볼 수 있고, IntelliJ IDE를 이용해 짤 수 있습니다. 공식 문서는 여기에 있습니다.

Java를 하고 계시다면 Kotlin도 한 번쯤 꼭 해보세요! 좋은 경험이 될 거라고 생각해요.

댓글 (7개) 댓글 쓰기


x32_noah 10달 전

팬이에요 코틀린으로 싸인해주세요!!!


shiftpsh 10달 전

import kotlin.math.*

fun main(args: Array<String>) {
    val arr = Array(11) { y ->
        Array(40) { x ->
            val sinx = (sin(x.toDouble() / (2 * PI)) * 5).toInt()

            when {
                y == 5 - sinx -> '*'
                y == 5 && x == 0 -> '+'
                y == 5 -> '-'
                x == 0 -> '|'
                else -> ' '
            }
        }
    }

    println(arr.joinToString("\n") { it.joinToString("") })
}

eric00513 8달 전

팬이에요 꼭 Kotlin 해 볼게요^^


shiftpsh 8달 전

IntelliJ는 최고의 Kotlin IDE에요 참고하세요!!



chogahui05 7달 전

와아아 :fan: