(Kotlin/코틀린) use로 리소스 자동 닫기

개요

파일, 스트림, DB 커서, 네트워크 응답 등 닫아야 하는 리소스(Closeable) 를 다룰 때 가장 중요한 원칙은 하나입니다.

무슨 일이 있어도 반드시 닫아라. (정상 종료든 예외든)

코틀린에서는 이를 가장 깔끔하게 해결하는 표준 도구가 use 입니다.


1. use가 필요한 이유 (누수 방지)

❌ 잘못된 예: close 누락 가능

val input = FileInputStream(file)
val text = input.readBytes().toString(Charsets.UTF_8)
// 예외가 발생하면 close() 못 하고 누수
input.close()

읽기 중 예외가 나면 close()까지 도달하지 못해 리소스가 새는 문제가 생깁니다.


2. use 기본 형태

FileInputStream(file).use { input ->
    val text = input.readBytes().toString(Charsets.UTF_8)
}
// 내부적으로 다음과 유사합니다.
val input = FileInputStream(file)
try {
    // 작업
} finally {
    input.close()
}

3. 어떤 리소스에 use를 적용할 수 있나?

일부 타입은 AutoCloseable만 구현하기도 하는데, 코틀린/JDK 버전 및 환경에 따라 확장 함수가 제공됩니다. 실무에서는 대부분 Closeable 리소스에 use를 적용합니다.


4. 실무 예제 1: 파일 읽기/쓰기

// 파일 읽기
val text = FileInputStream(file).use { input ->
    input.readBytes().toString(Charsets.UTF_8)
}

// 파일 쓰기
FileOutputStream(file).use { out ->
    out.write("hello".toByteArray(Charsets.UTF_8))
}

5. 실무 예제 2: BufferedReader + 라인 처리 (useLines)

파일을 라인 단위로 처리할 때는 useLines가 가장 깔끔합니다.

val count = file.bufferedReader().useLines { lines ->
    lines.count()
}

6. 실무 예제 3: Android Cursor도 use로 닫기

ContentResolver 쿼리 결과 Cursor는 반드시 close 해야 합니다.

val names = mutableListOf<String>()

context.contentResolver.query(uri, null, null, null, null)
    ?.use { cursor ->
        val idx = cursor.getColumnIndexOrThrow("name")
        while (cursor.moveToNext()) {
            names.add(cursor.getString(idx))
        }
    }


Related Posts