본문 바로가기
개발&프로그래밍

[kotlin] 자주 사용되는 관용구(idiom) 모음

by 재아군 2024. 8. 9.

이 글은 Kotlin 프로그래밍 언어에서 자주 사용되는 관용구(idiom)들의 모음입니다.


각 관용구에 대한 설명과 예제 코드를 함께 설명합니다.

공식 홈페이지 kotlinlang.org의 내용을 참고합니다.

 





1. 데이터 클래스 생성 (Create DTOs)


Kotlin에서는 data class를 사용하여 간단하게 DTO(Data Transfer Object)를 만들 수 있습니다.
이는 자동으로 getter, setter, equals(), hashCode(), toString() 등의 메서드를 제공합니다.

data class Customer(val name: String, val email: String)



이 코드는 다음과 같은 기능을 제공하는 Customer 클래스를 생성합니다:

- 모든 속성에 대한 getter (그리고 var의 경우 setter)

- equals()
- hashCode()
- toString()
- copy()
- component1(), component2(), ... (모든 속성에 대해)

 

 

2. 함수 매개변수의 기본값 (Default values for function parameters)

 

함수 정의 시 매개변수에 기본값을 지정할 수 있어, 호출 시 일부 인자를 생략할 수 있습니다.

fun foo(a: Int = 0, b: String = "") { ... }



3. 리스트 필터링 (Filter a list)


filter 함수를 사용하여 리스트에서 조건에 맞는 요소만 선택할 수 있습니다.

val positives = list.filter { x -> x > 0 }

 


더 간단한 방법:

val positives = list.filter { it > 0 }

 


4. 컬렉션 내 요소 확인 (Check the presence of an element in a collection)

 

in 키워드를 사용하여 컬렉션에 특정 요소가 있는지 쉽게 확인할 수 있습니다.

 

if ("john@example.com" in emailsList) { ... } 

if ("jane@example.com" !in emailsList) { ... }

 

 

5. String interpolation


$ 기호를 사용하여 문자열 내에 변수 값을 쉽게 삽입할 수 있습니다.

println("Name $name")

 

 


6. 안전한 표준 입력 읽기 (Read standard input safely)


readln().toIntOrNull()을 사용하여 안전하게 정수 입력을 받을 수 있습니다.

// 문자열을 읽고 정수로 변환할 수 없는 경우 null을 반환합니다. 예: "안녕하세요!"
val wrongInt = readln().toIntOrNull()
println(wrongInt)
// null

// 정수로 변환 가능한 문자열을 읽고 정수를 반환합니다. 예: 13
val correctInt = readln().toIntOrNull()
println(correctInt)
// 13

 


7. 타입 검사 (Instance checks)


when 표현식과 is 키워드를 사용하여 객체의 타입을 검사할 수 있습니다.

when (x) { 
	is Foo -> ... 
	is Bar -> ... 
	else -> ... 
}



8. 읽기 전용 리스트와 맵 (Read-only list and map)


listOf와 mapOf를 사용하여 변경 불가능한 리스트와 맵을 생성할 수 있습니다.

val list = listOf("a", "b", "c")
val map = mapOf("a" to 1, "b" to 2, "c" to 3)

 

 

 

9. 범위 반복 (Iterate over a range)


다양한 방식으로 숫자 범위를 반복할 수 있습니다.

for (i in 1..100) { ... }  // 1부터 100까지 (100 포함)
for (i in 1..<100) { ... } // 1부터 99까지 (100 미포함)
for (x in 2..10 step 2) { ... }
for (x in 10 downTo 1) { ... }
(1..10).forEach { ... }

 


10. 지연 속성 (Lazy property)


lazy 키워드를 사용하여 필요할 때만 값을 계산하는 속성을 정의할 수 있습니다.

val p: String by lazy { // 값은 첫 접근 시에만 계산됩니다
    // 문자열 계산
}

 


11. 확장 함수 (Extension functions)


기존 클래스에 새로운 메서드를 추가할 수 있습니다.

fun String.spaceToCamelCase() { ... }

"Convert this to camelcase".spaceToCamelCase()

 


12. 싱글톤 생성 (Create a singleton)

 

object 키워드를 사용하여 싱글톤을 쉽게 만들 수 있습니다.

object Resource {
    val name = "Name"
}

 


13. Null 안전성 (Null safety)

 

?., ?:, let 등을 사용하여 null 값을 안전하게 처리할 수 있습니다.

// If-not-null 단축 표현
val files = File("Test").listFiles()
println(files?.size) // files가 null이 아닌 경우 size를 출력

// If-not-null-else 단축 표현
println(files?.size ?: "empty") // files가 null인 경우 "empty" 출력

// null인 경우 실행
val email = values["email"] ?: throw IllegalStateException("Email is missing!")

// null이 아닌 경우 실행
value?.let {
    // null이 아닌 경우 이 블록 실행
}

 


14. 표현식으로서의 try-catch와 if (try-catch and if expressions)


예외 처리와 조건문을 표현식으로 사용할 수 있습니다.

// try-catch 표현식
val result = try {
    count()
} catch (e: ArithmeticException) {
    throw IllegalStateException(e)
}

// if 표현식
val y = if (x == 1) {
    "one"
} else if (x == 2) {
    "two"
} else {
    "other"
}

 


15. 간결한 함수 정의 (Single-expression functions)

 

단일 표현식 함수를 간단히 정의할 수 있습니다.

fun theAnswer() = 42

 


16. 객체 설정을 위한 apply와 with (Configure properties of an object with apply and with)


객체의 여러 속성을 한 번에 설정하거나 여러 메서드를 호출할 때 사용합니다.

val myRectangle = Rectangle().apply {
    length = 4
    breadth = 5
    color = 0xFAFAFA
}

with(myTurtle) { //100픽셀 정사각형 그리기
    penDown()
    for (i in 1..4) {
        forward(100.0)
        turn(90.0)
    }
    penUp()
}


이 문서는 Kotlin의 특징적인 문법과 기능들을 간결하게 보여주고 있어, Kotlin 초보자부터 중급 개발자까지 유용하게 참고할 수 있는 자료입니다. 각 관용구는 Java와 비교했을 때 Kotlin의 장점을 잘 보여주고 있습니다.

 

17. 추상 클래스 인스턴스화 (Instantiate an abstract class)

Kotlin에서는 익명 객체를 사용하여 추상 클래스의 인스턴스를 쉽게 생성할 수 있습니다.

 

abstract class MyAbstractClass {
    abstract fun doSomething()
    abstract fun sleep()
}

fun main() {
    val myObject = object : MyAbstractClass() {
        override fun doSomething() {
            // ...
        }

        override fun sleep() { 
            // ...
        }
    }
    myObject.doSomething()
}

 

 

18. Null 안전성 관련 추가 예제 (Additional Null Safety Examples)

If-not-null 단축 표현

val files = File("Test").listFiles()

println(files?.size) // files가 null이 아닌 경우에만 size 출력

 

 

 

If-not-null-else 단축 표현

val files = File("Test").listFiles()

// 간단한 대체값 사용:
println(files?.size ?: "empty") // files가 null이면 "empty" 출력

// 복잡한 대체값 계산을 위해 `run` 사용:
val filesSize = files?.size ?: run {
    val someSize = getSomeSize()
    someSize * 2
}
println(filesSize)

 

Null인 경우 예외 발생

val values = ...
val email = values["email"] ?: throw IllegalStateException("Email is missing!")

 

가능한 빈 컬렉션의 첫 번째 항목 가져오기

val emails = ... // 빈 리스트일 수 있음
val mainEmail = emails.firstOrNull() ?: ""

 

Null이 아닌 경우 실행

val value = ...

value?.let {
    ... // value가 null이 아닌 경우 이 블록 실행
}

 

Null이 아닌 경우 변환

val value = ...

val mapped = value?.let { transformValue(it) } ?: defaultValue
// value나 변환 결과가 null인 경우 defaultValue 반환

 

19. when 표현식을 사용한 반환 (Return on when statement)

when 표현식을 사용하여 간결하게 값을 반환할 수 있습니다.

fun transform(color: String): Int {
    return when (color) {
        "Red" -> 0
        "Green" -> 1
        "Blue" -> 2
        else -> throw IllegalArgumentException("Invalid color param value")
    }
}

 

 

 

20. 객체의 여러 메서드 호출하기 (with)

with 함수를 사용하면 객체의 여러 메서드를 연속해서 호출할 때 객체 이름을 반복하지 않아도 됩니다.

 

class Turtle {
    fun penDown()
    fun penUp()
    fun turn(degrees: Double)
    fun forward(pixels: Double)
}

val myTurtle = Turtle()
with(myTurtle) { // 100픽셀 정사각형 그리기
    penDown()
    for (i in 1..4) {
        forward(100.0)
        turn(90.0)
    }
    penUp()
}

 

 

21. 객체 속성 구성하기 (apply)

 

apply 함수를 사용하면 객체를 생성하고 즉시 그 속성들을 설정할 수 있습니다.

val myRectangle = Rectangle().apply {
    length = 4
    breadth = 5
    color = 0xFAFAFA
}

 

 

22. Java 7의 try-with-resources와 유사한 기능

Kotlin에서는 use 함수를 사용하여 자원을 자동으로 닫을 수 있습니다.

val stream = Files.newInputStream(Paths.get("/some/file.txt"))
stream.buffered().reader().use { reader ->
    println(reader.readText())
}

이 예제는 파일을 읽은 후 자동으로 리소스를 닫습니다.

 

 

23. 제네릭 타입 정보가 필요한 제네릭 함수

 

reified 키워드를 사용하여 런타임에 제네릭 타입 정보를 유지할 수 있습니다.

//  public final class Gson {
//     ...
//     public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
//     ...

inline fun <reified T: Any> Gson.fromJson(json: JsonElement): T = this.fromJson(json, T::class.java)

이 예제는 Gson 라이브러리의 fromJson 메서드를 더 간단하게 사용할 수 있게 해줍니다.

 

 

24. 두 변수 교환하기

Kotlin에서는 also 함수를 사용하여 두 변수의 값을 쉽게 교환할 수 있습니다.

var a = 1
var b = 2
a = b.also { b = a }

 

이 코드 실행 후 a는 2가 되고 b는 1이 됩니다.

 

25. 미완성 코드 표시하기 (TODO)

 

Kotlin 표준 라이브러리에는 TODO() 함수가 있어 아직 구현되지 않은 코드를 표시할 수 있습니다. 이 함수는 항상 NotImplementedError를 던집니다.

fun calcTaxes(): BigDecimal = TODO("Waiting for feedback from accounting")

 

TODO() 함수의 반환 타입은 Nothing이므로 어떤 타입이 예상되는 곳에서도 사용할 수 있습니다.

IntelliJ IDEA의 Kotlin 플러그인은 TODO()의 의미를 이해하고 자동으로 TODO 도구 창에 코드 포인터를 추가합니다.

 

 

이러한 Kotlin의 관용구들은 코드를 더 간결하고 표현력 있게 만들어줍니다. with와 apply 같은 함수들은 객체를 다룰 때 코드의 가독성을 크게 향상시킵니다. use 함수는 리소스 관리를 더 안전하고 간편하게 만들어주며, reified 키워드를 사용한 제네릭 함수는 타입 안전성을 높여줍니다. TODO() 함수는 개발 과정에서 미완성 코드를 명확히 표시하는 데 도움이 됩니다.

 

이러한 관용구들을 적절히 활용하면 Kotlin 코드의 품질과 유지보수성을 크게 향상시킬 수 있습니다.

 

kotlin의 다른 글 : 

 

2024.08.07 - [개발&프로그래밍] - [kotlin] 입문시 알아야 할 8가지 핵심 문법

 

[kotlin] 입문시 알아야 할 8가지 핵심 문법

Kotlin의 주요 문법 특징들을 간략히 정리한 것입니다.각 항목은 Kotlin의 간결하고 표현력 있는 코드 작성을 지원하는 특징들을 보여줍니다. 아래 문서는 kotlinlang.org 공식 홈페이지를 참조합니다.

observerlife.tistory.com

 

2024.08.07 - [개발&프로그래밍] - [kotlin] 입문시 알아야 할 7가지 핵심 문법

 

[kotlin] 입문시 알아야 할 7가지 핵심 문법

Kotlin의 기본적인 문법 요소들을 간략하게 설명하고 있습니다.각 항목은 Kotlin 프로그래밍의 기초를 이해하는 데 중요한 개념들을 포함하고 있습니다. 아래 문서는 kotlinlang.org 공식 홈페이지를

observerlife.tistory.com

 

댓글