코틀린에서는 close메서드를 통해 명시적으로 닫아줘야 하는 리소스들이 있습니다.
- InputStream, OutputStream
- java.sql.Connection
- java.io.Reader
- java.new.Socket, java.util.Scanner
이러한 리소스들은 AutoCloseable을 상속받는 Closeable인터페이스를 구현하고 있습니다. 이러한 모든 리소스는 최종적으로 리소스에 대한 레퍼런스가 없어질 때 가비지 컬렉터가 처리해 주지만, 느리며 그동안 리소스 유지비용이 많이 들어갑니다. 그렇기 때문에 위에서 말한 데로 명시적으로 리소스를 닫아줘야 합니다.
try {
return reader.lineSequence().sumBy {it.lentgh}
} finally {
reader.close()
}
이렇게 try finally문으로 리소스를 닫아줄 수 있지만 이러한 코드는 좋은 코드라고 볼 수 없습니다. 리소스를 닫을 때 예외가 발생할 수 있는데 이러 예외를 따로 처리하지 않기 때문에 좋은 코드라고 볼 수는 없습니다. 또한 위코드에서 예외가 생길 경우 둘 중 하나만 전파됩니다. 그래서 코틀린에서는 Closeable인터페이스의 확장함수로 use를 지원하고 있습니다.
BufferReader(FileReader(path)).use { reader ->
return reader.lineSequence().sumBy { it.length }
}
@InlineOnly
@RequireKotlin("1.2", versionKind = RequireKotlinVersionKind.COMPILER_VERSION, message = "Requires newer compiler version to be inlined correctly.")
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의 사용예시와 use의 내부 로직입니다. 이 밖에도 File같이 한 줄씩 읽어오는 useLines 같은 함수도 지원합니다.
fun countCharInFile(path:String): Int {
File(path).useLines { lines ->
return lines.sumBy { it.length }
}
}
결과적으로 명시적으로 리소스를 닫아줘야하는경우 use를 사용하는 것이 좋습니다.
'코틀린 > Effective Kotlin' 카테고리의 다른 글
[Effective Kotlin] 안정성파트를 끝내며 (0) | 2023.08.03 |
---|---|
[Effective Kotlin] 10. 안정성 - 단위 테스트(Unit Test)를 만들어라 (0) | 2023.08.02 |
[Effective Kotlin] 8. 안정성 - 적절하게 null을 처리하라 (0) | 2023.07.28 |
[Effective Kotlin] 7. 안정성 - 결과 부족이 발생할 경우 null과 Failure를 사용하라 (0) | 2023.07.24 |
[Effective Kotlin] 6. 안정성 - 사용자 정의 오류보다는 표준 오류를 사용 하라 (0) | 2023.07.21 |