Kotlin 1.4-M2 미리 살펴보기: 표준 라이브러리 개선 사항

게시일: 작성자: jessie.cho@jetbrains.com

Kotlin 1.1.4 작업이 계속 진행되는 가운데 다음 테스트 버전인 1.4-M2가 곧 출시됩니다. 지금부터 이번 테스트 버전의 일부 개선 사항을 공개하려 합니다. 이 글에서는 표준 라이브러리의 변경 내용에 관해 알려 드리겠습니다.

1.4-M2의 표준 라이브러리에서 구현된 핵심 개선 사항 중 몇가지는 다음과 같습니다.

Kotlin 1.4-M2는 아직 출시되지 않았지만 조기 버전이 Kotlin playground에 추가되어 있으므로 이 글에서 확인한 모든 기능을 사용해볼 수 있습니다. 이 글의 코드 샘플은 새 버전에서도 실행됩니다.

새 버전을 사용해보고 싶으시다면, Kotlin 블로그 뉴스레터를 구독하면 출시일에 바로 소식을 받아볼 수 있습니다.

 

공통 라이브러리 확장

Android 및 iOS 또는 JVM 및 JS 등 다양한 플랫폼에서 공유되는 ‘공통’ 코드로 된 표준 라이브러리를 사용할 수 있습니다. 공통 라이브러리는 점차 확대하여 누락된 기능을 추가하고 이동할 예정입니다.

Kotlin/JVM에서 이전 appendln의 구현은 시스템별 줄 구분 기호를 추가했었습니다(UNIX 시스템에서는 \n, Windows에서는 \r\n). 그러나 공통 코드에 관해 논의할 것이면 운영 체제와 기반 플랫폼에 관계없이 동일한 동작을 보장하는 것이 중요하다고 생각합니다. 이것이 새로운 appendLine 함수를 위해 appendln을 더 이상 사용하지 않는 이유입니다. 이 함수는 항상 단일 \n 문자로 줄을 종료합니다.

JVM에서 플랫폼 고유의 구분 기호가 필요한 경우 System.lineSeparator()를 계속 사용할 수도 있습니다.

이제 공통 코드에서 사용되는 다른 함수를 통해, 지정된 스택 추적의 문자열 표현을 사용할 수 있습니다. Throwable.stackTraceToString() 확장은 스택 추적과 함께 이 throwable에 관한 자세한 설명을 반환하고 Throwable.printStackTrace()는 이 설명을 표준 오류 출력으로 인쇄합니다.

또한 공통 코드에서는 Throwable.addSuppressed() 함수로예외를 전달하기 위해 억제된 예외를 지정할 수 있으며 Throwable.suppressedExceptions 속성으로 전체 억제 예외 목록을반환할 수 있습니다.

새로운 배열 함수

다양한 컨테이너 유형으로 작업할 때 일관된 환경을 이용할 수 있도록 배열에 대한 새로운 확장 함수를 추가했습니다.

  • shuffle() – 배열 요소를 임의의 순서로 넣습니다.
  • onEach() – 각 배열 요소에 대해 지정된 액션을 수행하고 배열 자체를 반환합니다.

이러한 함수는 목록을 사용하는 사람들에게 친숙한 것으로, 배열에서도 같은 방식으로 작동합니다.

배열 하위 범위를 정렬하는 새로운 함수도 추가했습니다. 이전에는 매개변수가 fromIndextoIndexsort()가 있었으며 이는 JVM 전용이었습니다. 이제는 공통으로 사용할 수 있고 reverse()sortDescending()의 하위 범위 버전인 2개의 새로운 관련 함수가 생겼습니다. 각 함수는 이름에서 자명하게 파악되는 방식으로 2개의 색인을 취하여 해당 범위 사이의 요소를 재정렬합니다(fromIndex는 포함하지만 toIndex는 제외).

  • 배열 하위 범위에 대한 reverse()는 하위 범위의 요소 순서를 반대로 바꿉니다.
  • 배열 하위 범위에 대한 sortDescending()은 하위 범위의 요소를 내림차순으로 정렬합니다.

Collections API 내 새로운 함수

1.4-M2는 실제 사례에 더 효과적으로 대응할 수 있도록 표준 라이브러리의 Collections API 확장을 계속 하고 있습니다.

  • 새로운 집합 생성 함수 setOfNotNull()은 제공된 인수 중 null이 아닌 모든 항목으로 구성된 집합을 만듭니다.
  • 이제 shuffled()를 시퀀스에도 사용할 수 있습니다.
  • onEachIndexed()reduceIndexedOrNull()이 각각 onEach()reduceOrNull()의 대응 항목으로 추가되었습니다. 아시다시피 컬렉션 처리 함수의 이름에서 색인되었다는 것은적용된 작업에 요소 색인이 매개변수로 있음을 의미합니다.
  • runningFold()runningReduce()scan()scanReduce()의 동의어로 도입되었습니다. 이러한 이름은 관련 함수 fold()reduce()와 더 일치합니다. scan()은 이 작업에서 일반적으로 알려진 이름이므로 나중에 runningFold()와 함께 제공될 예정입니다. 그러나 실험적인 scanReduce()는 더 이상 사용되지 않으며 곧 제거될 것입니다.

기존 API 개선

Kotlin 1.4는 주요 ‘기능’ 릴리스이므로 언어에 새로운 기능을 추가하고 표준 라이브러리에 새로운 함수 또는 인터페이스를 추가할 수 있습니다. 새로운 실험적 선언은 부가적인 릴리스(예: 1.3.70)에서만 추가합니다. Kotlin 1.3.70을 사용하여 코드를 작성하지만 실험적 선언을 사용하지 않으면 작성한 코드가 Kotlin 1.3.40을 사용하는 동료에게도 올바르게 컴파일됩니다.

기능 릴리스는 부가적 릴리스와 동일한 엄격한 규칙을 준수할 필요가 없습니다.
따라서 새 기능 또는 API를 사용하는 경우 1.3 버전의 Kotlin 컴파일러는 Kotlin 1.4로 작성된 코드를 컴파일하지 못할 수 있습니다. 이를 개선하기 위해 API에 일부 변경 내용을 도입하게 되었습니다. 이전 버전용으로 작성된 코드가 이전처럼 계속 컴파일되고 작동할 수 있도록 이전 버전과의 호환성을 주의 깊게 관찰하려고 합니다.

Kotlin 1.4에서는 null을 허용하도록 몇가지 함수 규칙을 완화했습니다.

Kotlin 1.3은 String.toBoolean()의 리시버가 null 가능하도록 허용하지 않기 때문에 이 코드를 컴파일하지 않습니다. Kotlin 1.4는 리시버를 null 가능 문자열인 String?.toBoolean()으로 변경합니다. 이에 따라 이전에 작성된 모든 코드는 Kotlin 1.4에서 계속 컴파일되고 작동합니다.

동일한 논리가 contentEquals, contentHashCode, contentToString 함수의 Array 리시버에도 적용되어 이 리시버도 null 가능해졌습니다. 또한, String.format()은 로컬라이제이션이 적용되지 않은 경우 nulllocale 인수로 허용합니다.

DoubleFloat에 정의된 다음 상수는 이제 ‘진짜’ 상수입니다.

이제 이러한 상수가 const 변수로 정의되어 어노테이션 인수로 사용할 수 있습니다.

SIZE_BITSSIZE_BYTESDoubleFloat의 새로운 상수이므로 2진 형식으로 유형의 인스턴스를 나타내는 데 사용되는 비트 및 바이트 수를 포함합니다.

Kotlin/JS에서 Float.MAX_VALUEFloat.MIN_VALUE 값도 변경되었습니다. 이전에 이 값은 Kotlin/JS에서 FloatDouble과 본질적으로 동일하므로 JavaScript Number.MAX/MIN_VALUE 또는 Double.MAX/MIN_VALUE와 동일했습니다. 이제 이러한 Float 범위의 상수는 모든 플랫폼에서 동일합니다.

vararg가 사용되는 maxOf() 및 minOf()

표준 라이브러리의 maxOf()minOf() 함수는 두 값 중 더 큰 값과 작은 값을 찾습니다. 1.4-M1부터 maxOf()minOf()인수의 가변 숫자(vararg)를 허용하므로 숫자 또는 기타 비교 가능한 항목 집합에서 해당 함수를사용할 수 있습니다.

속성 위임 개선 사항

Kotlin에서 위임된 속성은 인터페이스가 아닌 규칙을 통해 작동합니다. 따라서 위임으로 사용하려는 유형은 필요한 인터페이스를 구현하는 대신 연산자 함수를 정의해야 합니다. 이는 특정 인터페이스에 구속되지 않기 때문에 유연성을 제공하지만 많은 실제 사용 사례에서는 여전히 인터페이스를 사용하는 것이 좋습니다.

Kotlin 1.4에서는 이러한 보완 인터페이스를 더욱 효과적으로 사용할 수 있도록 새로운 PropertyDelegateProvider 인터페이스를 도입하였습니다.
또한 ReadWritePropertyReadOnlyProperty를 상속합니다. 자세한 내용은 계속 읽으면서 확인해 주세요.

Delegate 표현식

사용자 지정 클래스 또는 익명 객체로 위임을 구현하는 경우 속성 위임을 정의할 때 ReadWritePropertyReadOnlyProperty 인터페이스를 편리하게 사용할 수 있습니다.

1.4부터는 ReadWritePropertyReadOnlyProperty를 상속합니다. 이에 따라 delegate 표현식을 더 유연하게 사용하여 작업할 수 있게 되었습니다. 이 예시에서는 ReadOnlyProperty가 필요할 때마다 myDelegate() 호출을 전달할 수 있습니다.

여기서는 읽기 전용 목록이 변경 불가능한 목록이 아니듯이 Kotlin의 ‘읽기 전용’이 ‘불변’과 동일하지 않다는 점을 강조하고 싶습니다. ‘읽기 전용’이란 ‘이 인터페이스는 해당 객체에 대한 읽기 전용 액세스만 제공’한다는 것을 의미합니다.

위임 제공

위임을 제공하는 메커니즘을 사용하면 속성 구현이 위임되는 “delegate” 객체를 생성하는 논리를 확장할 수 있습니다. 작동 방식에 대한 자세한 내용은 문서에서 확인할 수 있습니다. 1.4에서는 이 메커니즘을 좀 더 편리하게 이용할 수 있도록 새로운 PropertyDelegateProvider 인터페이스를 추가했습니다. 이는 추가로 클래스를 만들고 싶지 않고 위의 myDelegate() 예시에 나온 것과 유사한 익명 객체 사용을 선호하는 경우에 사용할 수 있습니다.

다른 속성에 위임

1.4부터 속성은 해당 getter와 setter를 다른 속성에 바로 위임할 수 있습니다. 예를 들어 이는 이전 버전과 호환되는 방식으로 속성의 이름을 바꾸려는 경우 유용할 수 있습니다. 새 속성을 삽입하고 @Deprecated 어노테이션을 이전 속성에 추가한 다음, 구현을 위임하세요.

앞에서 설명한 컴파일된 위임 속성의 최적화는 이 경우에 사용할 수 있습니다. 위임 연산자 구현은 위임되는 속성(oldName)에 대한 정보를 사용하지 않으므로 컴파일러가 해당 정보를 사용하여 KProperty 인스턴스를 생성할 필요가 없습니다. 향후에는 위임(newName)에 대한 추가 KMutableProperty 인스턴스도 생성할 필요가 없을 수 있습니다.

체험 방법

이상 설명된 모든 변경 내용은 Kotlin 1.4-M2 테스트버전의 일부이지만 play.kotl.in에서 온라인으로 체험해 볼 수 있습니다. 단, 설정에서 1.4-M2 버전을 선택해야 하는 점을 잊지 말아주세요.

사전 릴리스 노트

이전 버전과의 호환성은 사전 릴리스 버전에는 적용되지 않습니다. 기능 및 API는 사용자의 피드백에 따라 후속 릴리스에서 변경될 수 있습니다.

의견을 공유해 주세요

이슈 트래커에 버그를 리포트해주신 모든 분께 감사드립니다. 그 다음 Kotlin 릴리스에서 문제가 해결되기를 기다리실 필요가 없도록 최종 릴리스 전에 최선을 다하여 모든 중요한 문제를 해결하겠습니다.

궁금한 점이 있거나 토론에 참여하고 싶거나 새로운 테스트 버전 빌드에 관한알림을 받고 싶으신 경우 Kotlin Slack의 #eap 채널에 언제든지 참여할 수 있습니다(여기에서 초대받기).

Let’s Kotlin!

이 게시물은 Pavel Semyonov가 작성한 First Look at Kotlin 1.4-M2: Standard Library Improvements를 번역한 글입니다.