DEV Community

Cover image for Kotlin Programming Language
Juyae
Juyae

Posted on

Kotlin Programming Language

Why Kotlin ?

Kotlin이란 무엇이며, 왜 필요할까요 ?

최근 받았던 피드백으로 저의 부족한 점을 보완하고자 Kotlin 언어에 대한 공부를 해보았습니다. 지금까지 Kotlin으로 개발을 해왔지만, Kotlin 언어 자체에 대한 공부는 부족했던 것 같아 Kotlin Compiler 개발자가 작성한 문서를 바탕으로 공부한 것을 정리해보겠습니다.

Google은 Google I/O 2019에서 안드로이드 개발이 점차 Kotlin 우선으로 될 것이라고 발표했습니다. 그만큼 Kotlin은 간결하고 실용적이며 타입 추론을 지원하는 정적 타입 지정 언어 입니다. 여기서 말하는 정적 타입 지정의 장점은 다음과 같습니다.

  1. 실행 시점에 어떤 메소드를 호출할지 알아내는 과정이 필요 없으므로 매소드 호출이 더 빠릅니다.
  2. 컴파일러가 프로그램의 정확성을 검증하기 때문에 실행 시 프로그램이 오류로 중단될 가능성이 더 적어집니다.
  3. 코드에서 다루는 객체가 어떤 타입에 속하는지 알 수 있기 때문에 처음 보는 코드를 다룰 때도 더 쉽습니다.
  4. 더 안전하게 리팩토링 할 수 있고, 도구 지원으로 더 정확한 코드 완성 기능을 제공할 수 있으며 IDE 다른 지원 기능도 더 잘 만들 수 있습니다.

요약

✔️ 코틀린은 타입 추론을 지원하는 정적 타입 지정 언어입니다. 소스 코드의 정확성과 성능을 보장하면서도 소스코드를 간결하게 유지할 수 있습니다.

✔️ 코틀린의 런타임 라이브러리는 크기가 작고, 코틀린 컴파일러는 안드로이드 API, 주요 IDE, 빌드 시스템을 완전 지원합니다.

✔️ @Nullable, @NonNullable 성격을 가지고 있어 NPE를 방지합니다.

✔️ 자바와의 유연한 상호운용성 : Kotlin 코드는 JVM 바이트 코드로 컴파일 되기 때문에 Kotlin 코드는 자바 코드로 직접 호출될 수 있으며 그 반대의 경우도 마찬가지입니다. 즉, 기존 자바 라이브러리를 Kotlin에서 직접 활용할 수 있습니다.

Data Class

Data class는 편리함을 제공하는 유용한 메소드를 자동으로 생성해주는 클래스입니다. 데이터 클래스가 기본적으로 제공해주는 기능들만 해도, 보일러 플레이트 코드를 줄일 수 있어 매우 간결하며 개발자가 데이터를 담을 수 있는 클래스를 다루기에 매우 편리해졌습니다. 다음은 데이터 클래스 생성시 같이 만들어지는 메소드들 입니다.

✔️hashCode() : 두 객체가 같은 객체인지 객체의 고유한 주소 값을 int값으로 변환하여 출력해서 확인
✔️copy() : immutable 정의에서 매우 유용하게 사용할 수 있으며 특정 필드값만 바꿔서 복사하기 간편
✔️equals() : 두 객체가 동일한 값(내용)을 담고 있는지 Boolean 값을 출력
✔️toString() : 프로퍼티의 값들이 알아서 출력
✔️componentsN() : 각 프로퍼티에 번호가 붙어 구조 분해가 가능한 형태

특징

  1. 상속을 받을 수 없습니다.
  2. val 또는 var로 선언해야 합니다. (immutable better)
  3. abstract, open, sealed, inner를 붙일 수 없습니다.

Equals와 hashCode

Data class를 활용하면 Kotlin 언어 수준에서 알아서 equals/hashCode를 정의해주기 때문에 data class를 적극 활용하는 게 좋지만 각각 어떤 역할을 하고 있는지, 또 어떤 차이점이 있는지 이번 기회를 통해 알고 넘어가보겠습니다.
몇 가지 규칙을 정리해보면 아래와 같습니다.

  1. 클래스에 equals를 정의했다면 반드시 hashCode도 재정의해야 합니다.
  2. 2개의 객체의 equals가 동일하다면 반드시 hashCode도 동일합니다.
  3. 위의 조건을 지키지 않을 경우, HashMap과 HashSet 등의 컬렉션 사용시 문제가 생길 수 있습니다.

그렇다면 equals와 hashCode를 왜 같이 재정의 해야하는 걸까?

hashCode를 equals와 함께 재정의하지 않으면 코드가 예상과 다르게 작동하는 문제가 생긴다. 정확히 말하면 hash 값을 사용하는 Collection(HashSet, HashMap, HashTable)을 사용할 때 문제가 발생합니다. hashCode 메소드의 리턴값이 우선 일치하고 equals 메소드의 리턴 값이 true여야 논리적으로 같은 객체라고 판단합니다.

Sealed Class

sealed 클래스는 자기 자신이 추상 클래스이고, 자신을 상속 받는 여러 서브 클래스들을 가질 수 있습니다. 이를 사용하면 enum 클래스와 다르게 상속을 지원하게 때문에 상속을 활용하여 풍부한 동작을 구현할 수 있습니다. sealed 클래스는 자신을 상속 받는 서브 클래스의 종류를 제한할 수 있습니다. 또한, 상태값이 바뀌지 않는 서브 클래스의 경우에는 object를 사용하는 것을 권장합니다.

  • sealed 클래스는 private 생성자만 갖습니다.
  • 기본적으로 추상 클래스이며 sealed 클래스의 서브 클래스들은 반드시 같은 파일 내에 선언되어야 합니다.
  • state 값을 포함 하고 있는 여러 개의 instance를 가질 수 있고 생성자도 각각의 특징에 따라서 유동적으로 가져갈 수 있습니다. 정적 상태의 single instance가 아닌 다양한 state를 사용할 수 있다는 뜻입니다.
  • sealed 클래스는 when문 사용시 효과적으로 쓸 수 있고 제한적인 계층 관계를 표현할 수 있습니다. enum class의 확장판과도 같다고 할 수 있습니다.

Kotlin Scope Function

특정 객체의 컨텍스트내에서 특정 동작을 실행하기 위한 목적으로 코드 블록을 실행할 수 있게 하는 함수입니다. lambda expression이 제공된 객체에서 Scope Function을 호출하게 되면 해당 함수는 일시적인 범위를 형성하며 해당 범위에서는 객체 이름 없이 객체에 접근할 수 있어 간결한 코딩을 가능하게 해줍니다. Scope Functions는 5가지 종류를 가지고 있습니다.

  • let : 객체의 값이 명확해야 할 때 사용하는 함수
  • run : 객체의 값에 접근을 쉽게 할 때 사용하는 함수
  • with : (생성과 동시에 초기화, null값이 될 수 없는) 결과가 필요하지 않을 경우
  • apply : 생성과 동시에 초기화하며 자기 자신을 return
  • also : 자기 자신이 필요한데 초기화를 좀 더 쉽게 (수신 객체를 사용하지 않거나 수신 객체의 속성을 변경하지 않고 사용할 때)

Top comments (0)