Kotlin ‐ use를 사용하여 리소스를 닫아라[Effective Kotlin Item 8] - thought-corner/Backend-PlayGround GitHub Wiki

use를 사용하여 리소스를 닫아라

  • 자동으로 닫히지 않는 리소스가 더 이상 필요하지 않다면 명시적으로 close() 메서드를 호출해야 한다.
  • 코틀린/JVM에서 사용하는 자바 표준 라이브러리에는 다음과 같은 리소스가 포함되어 있다.
    • InputStreamOutputStream
    • java.sql.Connection
    • java.io.Reader(FileReader, BufferedReader, CSSParser)
    • java.new.Socketjava.util.Scanner
  • 이런 모든 리소스는 AutoCloseable을 확장하는 Closeable 인터페이스를 구현한다.
  • 문제는 이런 리소스들은 비용이 많이 들고 자동으로 닫히기 어려우므로 사용하고 난 후에는 반드시 close() 메서드를 호출해야 한다.
  • 리소스에 대한 참조가 최종적으로 없어지게 되면 GC가 처리하게 되지만 처리하는데 시간이 걸린다.
  • 리소스를 닫기 위해 전통적으로 try-finally 블록으로 래핑하고 close() 메서드를 호출한다.
  • 코틀린에서는 리소스를 올바르게 닫고 예외를 처리하려면 use() 메서드를 사용해야 한다. 이 함수는 모든 Closeable 객체에 사용할 수 있다.
// ⭕ Good
fun countCharactersInFile(path: String): Int {
    val reader = BufferedReader(FileReader(path))
    reader.use {
        return reader.lineSequence().sumBy { it.length }
    }
}
  • use() 함수는 파일을 다루는 데 자주 사용되지만 파일을 한 줄씩 읽는 것이 일반적이므로 코틀린 표준 라이브러리는 파일을 줄 단위 시퀀스로 읽고 처리가 끝난 뒤 닫는 useLines() 함수도 제공한다.
  • 시퀀스를 사용하여 필요에 따라 한 줄씩 읽기 때문에 한 줄 분량의 메모리만 차지하므로 대규모의 파일을 처리할 때 적합하다.
  • 시퀀스의 단점은 파일을 한 번씩밖에 못 읽는다는 점이다. 만약 파일을 두 번 이상 반복해서 읽어야 한다면 해당 파일을 두 번 이상 열어야 한다.
  • useLines() 함수는 표현식으로도 사용할 수 있다.
// ⭕ Good
fun countCharactersInFile(path: String): Int = 
    File(path).useLines { lines ->
        lines.sumBy { it.length }
    }
  • 시퀀스 덕분에 파일 전체를 불러오는 대신 한 줄씩 읽을 수 있게 되었다.