Kotlin이란 무엇이며 왜 필요한가?

INJE YUN·2020년 12월 8일
3

kotlin-in-action

목록 보기
1/2

코틀린(Kotlin)이란?


코틀린( Kotlin )은 2011년 7월 JetBrains사가 공개한 JVM에서 동작하는 프로그래밍 언어로서, 간결하고 실용적이며 자바코드와의 상호운용성( interoperability )를 중시한 언어이다.

주요 특성


대상 플랫폼

코틀린의 주목적은 현재 자바가 사용되고 있는 모든 용도에 적합하면서도 더 간결하고 생산적이며 안전한 대체 언어를 제공하는 것이다.

  • 서버상의 코드 ( 특히 웹 애플리케이션의 백엔드 ( backend ) )
  • 안드로이드 디바이스에서 실행되는 모바일 애플리케이션

타입 ( type )

정적 타입(statically typed) 지정 언어

자바와 마찬가지로 코틀린도 정적 타입 지정 언어이다. 정적 타입 지정이라는 말은 모든 프로그래밍 구성 요소의 타입을 컴파일 시점에 알 수 있고 프로그램 안에서 객체의 필드나 메소드를 사용할 때마다 컴파일러가 타입을 검증해준다는 뜻이다. 정적 타입 지정 언어의 장점은 다음과 같다.

  • 성능 : 실행 시점에 어떤 메소드를 호출할지 알아내는 과정이 필요 없으므로 메소드 호출이 더 빠르다.

    // 정적 타입 ( Java, Kotlin 등)
    a.call()  // 객체 a의 클래스의 call 메소드 ( 컴파일 단계에서 알고 있음 )
    
    // 동적 타입 ( JavaScript, python 등 )
    b.call()  // 누구의 call 메소드 ? ( 컴파일 단계에서 알 수 없음 )
  • 신뢰성 : 컴파일러가 프로그램의 정확성을 검증하기 때문에 실행 시 프로그램이 오류로 중단될 가능성이 더 적어진다.

  • 유지 보수성 : 코드에서 다루는 객체가 어떤 타입에 속하는지 알 수 있기 때문에 처음보는 코드를 다룰 때도 더 쉽다.

  • 도구 지원 : 도구는 더 정확한 코드 완성 기능을 제공할 수 있으며, IDE의 다른 지원 기능도 동적 타입 지정 언어에 비해 더 잘 만들 수 있다.

타입 추론 ( type inference )

자바와 달리 코틀린에서는 모든 변수의 타입을 프로그래머가 직접 명시할 필요가 없다. 대부분의 경우 코틀린 컴파일러가 문맥으로부터 변수 타입을 자동으로 유추할 수 있기 때문에 프로그래머는 타입 선언을 생략해도 된다.

var x = 1  // Int
var y = 7.5e6  // 7.5 X 10^6 = 7500000.0 :: Double

널이 될 수 있는 타입 ( nullable type )

코틀린은 null이 될 수 있는 타입을 지원함에 따라 컴파일 시점에 null pointer exception이 발생할 수 있는지 여부를 검사할 수 있어서 좀 더 프로그램의 신뢰성을 높일 수 있다.

// **?** : null 가능
var a: String? = null
var b: String? = "bbb"
b = null

// null 불가능
var c: String = "ccc"
c = null  // compile error ( Null can not be a value of a non-null type String )
var d: String = null  // compile error ( Null can not be a value of a non-null type String )

함수형 프로그래밍 ( functional programming )

핵심 개념

  • 일급 객체( first-class )인 함수

    함수(프로그램의 행동을 나타내는 코드 조각)를 일반 값처럼 다룰 수 있다. 함수를 변수에 저장할 수 있고, 함수를 인자로 다른 함수에 전달할 수 있으며, 함수에서 새로운 함수를 만들어서 반환할 수 있다.

    // 함수를 변수에 저장
    val test: () -> Unit = { println("kotlin") }
    
    // 함수를 인자로 다른 함수에 전달
    fun test(func: () -> Unit) {
      func()
    }
    
    // 함수에서 함수를 반환
    fun test() : () -> Unit {
    	{ println("kotlin") }
    }
  • 불변성 ( immutability )

    함수형 프로그래밍에서는 일단 만들어지고 나면 내부 상태가 절대로 바뀌지 않는 불변 객체를 사용해 프로그램을 작성한다.

  • 부수 효과 ( side effect ) 없음

    함수형 프로그래밍에서는 입력이 같으면 항상 같은 출력을 내놓고 다른 객체의 상태를 변경하지 않으며, 함수 외부나 다른 바깥 환경과 상호작용하지 않는 순수 함수(pure function)를 사용한다.

    // 순수 함수
    fun getSum(a: Int, b: Int) = a + b
    
    // 순수하지 않은 함수
    var a = 1
    fun getSum(c: Int) = a + c

이점

  • 간결성

    명령형(imperative) 코드에 비해 더 간결하며 우아하다. 순수 함수를 값처럼 활용할 수 있으면 더 강력한 추상화할 수 있고 강력한 추상화를 사용해 코드 중복을 막을 수 있다.

  • Thread Safe

    불변 데이터 구조를 사용하고 순수 함수를 데이터 구조에 적용한다면 다중 스레드 환경에서 같은 데이터를 여러 스레드가 변경할 수 없다.

  • 테스트 용이

    side effect가 있는 함수는 그 함수를 실행하기 위해 필요한 환경을 구성하는 준비 코드(setup code)가 필요하지만 순수 함수는 준비 코드 없이 독립적인 테스트가 가능하다.

무료 오픈소스

코틀린 언어와 컴파일러, 라이브러리 및 코틀린과 관련된 모든 도구는 모두 오픈소스이며, 어떤 목적에든 무료로 사용할 수 있다. 코틀린은 아파치(Apache) 2 라이선스하에 제공된다. 개발은 깃허브(GitHub)를 통해 이뤄지고 있다.(링크)

철학


실용성

  • 코틀린은 연구를 위한 언어가 아니다. 최신 프로그래밍 언어 설계를 앞서 채택하거나 전산학계에서 연구 중인 혁신적인 아이디어를 코틀린을 통해 탐구하려고 하지 않는다. 대신 코틀린은 다른 프로그래밍 언어가 채택한 이미 성공적으로 검증된 해법과 기능에 의존한다.
  • 코틀린은 어느 특정 프로그래밍 스타일이나 패러다임을 사용할 것을 강제로 요구하지 않는다.
  • 코틀린은 도구를 강조한다. 좋은 언어만큼이나 편리한 개발 환경도 생산성 향상에 필수적이다.

간결성

코드가 더 간단하고 간결할수록 내용을 파악하기가 더 쉽다. 어떤 언어가 간결하다는 말은 그 언어로 작성된 코드를 읽으르 때 의도를 쉽게 파악할 수 있는 구문 구조를 제공하고, 그 의도를 달성하는 방법을 이해할 때 방해가 될 수 있는 부가적인 준비 코드가 적다는 뜻이다.

  • 자바에 존재하는 여러 가지 번거로운 준비 코드를 묵시적으로 제공한다. ( Getter, Setter, 등 )
  • 기능이 다양한 표준 라이브러리를 제공하기 때문에 반복되거나 길어질 수 있는 코드를 라이브러리 함수 호출로 대체할 수 있다.

안정성

일반적으로 프로그래밍 언어가 안전하다는 말은 프로그램에서 발생할 수 있는 오류 중에서 일부 유형의 오류를 프로그램 설계가 원칙적으로 방지해준다는 뜻이다.

  • 메모리 안정성을 보장하고, buffer overflow를 방지하며, 동적으로 할당한 메모리를 잘못 사용함으로 인해 발생할 수 있는 다양한 문제를 예방할 수 있다. ( JVM의 특징 )
  • 정적 타입 지정 언어로서 애플리케이션의 타입 안정성을 보장한다.
  • 컴파일 시점에서 검사를 통해 Null 오류를 방지한다. null이 될 수 없는 값을 추적하며 실행 시점에 NullPointerException이 발생할 수 있는 연산을 사용하는 코드를 금지한다.
  • ClassCastException을 방지한다. 자바에서는 타입 검사 후에 캐스팅이 이뤄지지만, 코틀린에서는 타입 검사와 캐스트가 한 연산자에 의해 이뤄진다.
// Java
if (value instanceOf String) // 타입 체크 후
  System.out.println(((String)value).toUpperCase())	// 캐스팅

// Kotlin
if (value is String) // 타입 체크 + 캐스팅
	println(value.toUpperCase())

상호운용성(interoperability)

  • 자바의 기존 라이브러리들을 그대로 사용할 수 있다. 라이브러리가 어떤 API를 제공하던 간에 코틀린에서는 메소드 호출, 클래스 상속, 인터페이스 구현, 어노테이션 적용 등 모든 일이 가능하다. 자바 코드에서 코틀린 코드를 호출할 때도 마찬가지로 아무런 노력이 필요 없다.
  • 자체 컬렉션 라이브러리를 제공하지 않고, 자바 표준 라이브러리에 의존한다. 또한 컬렉션을 더 쉽게 사용할 수 있도록 몇가지 기능을 추가하였다.
  • 코틀린이 제공하는 도구도 다중 언어 프로젝트를 완전히 지원한다. 코틀린과 자바의 소스 파일이 임의로 섞여 있어도 제대로 프로그램을 컴파일 가능하다.

코틀린 코드 컴파일


간단한 컴파일 방식은 커맨드라인에서 kotlinc 명령을 통해 할 수 있다. 컴파일하고 나서 java 명령으로 그 코드를 실행한다. (링크)

kotlinc <소스파일 또는 디렉터리> -include-runtime -d <jar 이름>
java -jar <jar 이름>

Kotlin Runtime Library

  • Kotlin 프로젝트 빌드 과정

코틀린 컴파일러로 컴파일한 코드는 코틀린 런타임 라이브러리에 의존한다. 이 라이브러리에는 코틀린 자체 표준 라이브러리 클래스와 자바 API의 기능을 확장한 내용이 있다. 코틀린 컴파일한 애플리케이션을 배포할 때는 런타임 라이브러리도 함께 배포해야 한다.

자바에서 사용한 빌드 도구로는 메이븐과 그레이들, 앤트 등이 있다. 이러한 빌드 도구는 애플리케이션을 패키징 할 때, 알아서 코틀린 라이브러리를 포함시켜준다.

  • Java 코드와 Kotlin 코드가 섞여 있는 프로젝트 컴파일 과정

Java 코드와 Kotlin 코드의 빌드 과정은 다음과 같은 순서로 이루어진다.

  1. Kotlin 컴파일러가 Kotlin 코드를 컴파일해 .class 파일을 생성한다. 이 과정에서 Kotlin 코드가 참조하는 Java 코드가 함께 로딩되어 사용된다.
  2. Java 컴파일러가 Java 코드를 컴파일해 .class 파일을 생성한다. 이때 이미 Kotlin이 컴파일한 .class 파일의 경로를 클래스 패스에 추가해 컴파일한다.

코틀린을 사용해도 될까?


코틀린을 사용하더라도 성능 측면에서 아무 손해가 없다.

  • 코틀린 컴파일러가 생성한 바이트코드는 일반적인 자바 코드와 똑같이 효율적으로 실행된다.

  • 코틀린의 런타임 시스템은 상당히 작기 때문에 컴파일 후 패키징한 애플리케이션 크기도 자바 애플리케이션에 비해 그리 많이 늘어나지 않는다.

  • 대부분의 코틀린 표준 라이브러리 함수는 인자로 받은 람다 함수를 인라이닝(inlining)한다. 따라서 람다를 새용해도 새로운 객체가 만들어지지 않으므로 객체 증가로 인해 가비지 컬렉션(GC)이 늘어나서 프로그램이 자주 멈추는 일도 없다.

    Inline X

    fun doSomething(body: () -> Unit) {
    	body()
    }
    
    fun test() {
    	doSomething{ print("문자열 출력") }
    }
    public static final void doSomething(@NotNull Function0 body) {
    	Intrinsics.checkParameterIsNotNull(body, "body");
    	body.invoke();
    }
    
    public static final void test() {
    	doSomething((Function0)null.INSTANCE); // 람다식을 Function0 객체로 생성하여 넘긴다.
    }

    Inline O

    **inline** fun doSomething(body: () -> Unit) {
    	body()
    }
    
    fun test() {
    	doSomething{ print("문자열 출력") }
    }
    public static final void doSomething(@NotNull Function0 body) {
    	int $i$f$doSomething = 0;
    	Intrinsics.checkParameterIsNotNull(body, "body");
    	body.invoke();
    }
    
    public static final void test() {
    	int $i$f$doSomething = false;
    	int var1 = false;
    	String var2 = "문자열 출력";
    	boolean var3 = false;
    	System.out.print(var2); // 람다식의 내용이 test 메소드 안에 포함된다.
    }

출처


PPT


Kotlin이란 무엇이며 왜 필요한가.pptx

profile
신입 개발자입니다.

0개의 댓글