안드로이드 개발자 노트
[이펙티브 코틀린] Item9. use를 사용하여 리소스를 닫아라 본문
반응형
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 |