[이펙티브 코틀린] Item9. use를 사용하여 리소스를 닫아라

2023. 9. 16. 14:14·Kotlin/이펙티브 코틀린
반응형

close 메서드를 사용해서 명시적으로 닫아야 하는 리소스가 있습니다.

 

  • InputStream과 OutputStream
  • java.sql.Connection
  • java.io.Reader(FileReader, BufferedReader, CSSParser)
  • java.new.Socket과 java.util.Scanner

이러한 리소스들은 AutoCloseable을 상속받는 Closeable 인터페이스를 구현하고 있습니다.

// Closeable
public interface Closeable extends AutoCloseable {
    void close() throws IOException;
}
// AutoCloseable
public interface AutoCloseable {
    void close() throws Exception;
}

 

최종적으로 리소스에 대한 레퍼런스가 없어질 때, 가비지 컬렉터가 처리하지만 굉장히 느리며 비용이 많이 들어갑니다.

따라서 명시적으로 close 메서드를 호출해 주는 것이 좋으며, 전통적으로 try-finally 블록을 사용해서 처리했습니다.

 

fun countCharactersInFile(path: String): Int {
    val reader = BufferedReader(FileReader(path))
    try {
        return reader.lineSequence().sumBy { it.length }
    } finally {
        reader.close()
    }
}

 

리소스를 닫을 때 예외가 발생할 수 있는데, 이러한 예외를 따로 처리하지 않기 때문에 좋은 코드가 아닙니다.
또한 try-finally를 사용하여 처리하면, try 블록이나 finllay 블록 내부에서 오류가 발생하면 둘 중 하나만 전파됩니다.

use 함수 내부 구현을 보면 try와 finally 각각에서 오류를 핸들링 해주고 있으며, 이를 직접 구현하려면 코드가 길고 복잡해집니다.

@InlineOnly
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    var exception: Throwable? = null
    try {
        return block(this)
    } catch (e: Throwable) {
        exception = e
        throw e
    } finally {
        when {
            apiVersionIsAtLeast(1, 1, 0) -> this.closeFinally(exception)
            this == null -> {}
            exception == null -> close()
            else ->
                try {
                    close()
                } catch (closeException: Throwable) {
                    // cause.addSuppressed(closeException) // ignored here
                }
        }
    }
}

 

use 함수를 사용해서 위 코드를 적절하게 변경하면 다음과 같습니다.

fun countCharactersInFile(path: String): Int {
    val reader = BufferedReader(FileReader(path))
    reader.use {
        return reader.lineSequence().sumBy { it.length }
    }
}

 

람다 매개변수로 리시버가 전달되는 형태로도 작성할 수 있습니다.

fun countCharactersInFile(path: String): Int {
    BufferedReader(FileReader(path)).use { reader ->
        return reader.lineSequence().sumBy { it.length }
    }
}

 

파일을 한 줄씩 처리할 때 활용할 수 있는 useLines 함수도 제공합니다.

fun countCharactersInFile(path: String): Int {
    File(path).useLines { lines ->
        return lines.sumBy { it.length }
    }
}

 

 

 


 

정리

 

use를 사용하면 Closeable/AutoCloseable을 구현한 객체를 쉽고 안전하게 처리할 수 있습니다.

반응형

'Kotlin > 이펙티브 코틀린' 카테고리의 다른 글

[이펙티브 코틀린] item10. 단위 테스트를 만들어라  (0) 2023.09.16
[이펙티브 코틀린] Item8. 적절하게 null을 처리하라  (0) 2023.09.09
[이펙티브 코틀린] Item7. 결과 부족이 발생할 경우 null과 Failure를 사용하라  (0) 2023.09.03
'Kotlin/이펙티브 코틀린' 카테고리의 다른 글
  • [이펙티브 코틀린] item11. 가독성을 목표로 설계하라
  • [이펙티브 코틀린] item10. 단위 테스트를 만들어라
  • [이펙티브 코틀린] Item8. 적절하게 null을 처리하라
  • [이펙티브 코틀린] Item7. 결과 부족이 발생할 경우 null과 Failure를 사용하라
어리둥절범고래
어리둥절범고래
    반응형
  • 어리둥절범고래
    안드로이드 개발자 노트
    어리둥절범고래
  • 전체
    오늘
    어제
    • 분류 전체보기 (111)
      • Android (14)
      • Kotlin (94)
        • 이펙티브 코틀린 (52)
        • 코틀린 완벽 가이드 (14)
        • 코틀린 코루틴 (17)
        • 코루틴의 정석 (11)
      • Conference (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
어리둥절범고래
[이펙티브 코틀린] Item9. use를 사용하여 리소스를 닫아라
상단으로

티스토리툴바