728x90
- 더 이상 필요하지 않을때, close 메서드를 사용해서 명시적으로 닫아야 하는 리소스가 있다
- InputStream / OutputStream
- java.sql.Connection
- java.io.Reader
- java.new.Socket / java.uti.Scanner
- 등등
- 이러한 리소스들은 AutoCloseable 을 상속받은 Closeable 인터페이스를 구현하고 있다.이러한 모든 리소스는 최종적으로 리소스에 대한 레퍼런스가 없어질 때, 가바지 컬렉터가 처리한다. 하지만, 굉장히 느리며 그동안 리소스를 유지하는 비용이 많이 들어간다.
- public abstract class InputStream implements Closeable {...}
- public interface Closeable extends AutoCloseable {
public void close() throws IOException;
}
- 기존구현은 try-finally 방식으로 많이 처리했지만, 이러한 코드는 굉장히 복잡하고 좋지 않다.
- 리소스를 닫을 때 예외가 발생할 수도 있는데, 이러한 예외를 따로 처리하지 않기 때문이다.
- 또한 try 블록과 finally 블록 내부에서 오류가 발생하면, 둘 중 하나만 전파된다. 둘다 전파될 수 있다면 좋을 것이지만, 이를 직접 구현하려면 코드가 굉장히 길고 복잡해진다.
- use 키워드를 사용하여 close 하자.
- 파일을 한 줄 씩 처리할 때 활용할 수 있는 useLines 함수도 제공한다 -> 메모리에 파일의 내용을 한 줄씩만 유지하므로, 대용량 파일도 적절하게 처리할 수 있다. 다만 파일의 줄을 한 번만 사용할 수 있다는 단점이 있다
- use
- 파일 전체를 한번에 메모리에 로드해야 하는 경우(ex: 전체파일을 String 으로 처리할 경우 등)
- 바이너리 파일을 다루는 경우
- 파일 내 특정 위치로 빠르게 접근하거나, 랜덤 엑세스가 필요한 경우(useLines 는 순차 처리에 최적화 되어 있음)
- uselines
- 파일의 모든 라인을 순차적으로 처리할 때
- 파일의 크기가 크고, 메모리에 파일 전체를 한 번에 로드하지 못할 때
=== test Text
Kotlin은 정적 타입 지정 언어입니다.
Kotlin은 JVM에서 실행됩니다.
=== test Text
// use
@Test
fun useTest5() {
readFileWithUse("/path")
// ===== use =====
// Kotlin은 정적 타입 지정 언어입니다.
// Kotlin은 JVM에서 실행됩니다.
}
fun readFileWithUse(filePath: String) {
FileInputStream(filePath).use { inputStream ->
println("===== use =====")
inputStream.bufferedReader().use { reader ->
reader.lines().forEach { println(it) }
}
}
}
// useLines
@Test
fun useTest6() {
readFileWithUseLines("/path")
// ===== useLines =====
// Kotlin은 정적 타입 지정 언어입니다.
// ===== useLines =====
// Kotlin은 JVM에서 실행됩니다.
}
fun readFileWithUseLines(filePath: String) {
File(filePath).useLines { lines ->
lines.forEach {
println("===== useLines =====")
println(it)
}
}
}
- lineSequence
- useLinse 와 비슷하지만 좀 더 세밀한 제어가 필요하다면 use 와 lineSequence 를 사용할 수 있다
- lineSequence 은 자동으로 닫히지 않기때문에 use 와 함께 사용한다
@Test
fun useTest7() {
readFileWithLinesSequence(path) // Found an kotlin line: KOTLIN은 정적 타입 지정 언어입니다.
}
fun readFileWithLinesSequence(filePath: String) {
val bufferedReader = File(path).bufferedReader()
bufferedReader.use { reader ->
val lineSequence = reader.lineSequence()
val result = lineSequence.map { it.uppercase(Locale.getDefault()) }
.find { it.startsWith("KOTLIN") }
if (result != null) {
println("Found an kotlin line: $result")
}
}
}
참고:
- 직접 리소스 관리 vs GC 에 의해 관리
- 운영체제의 커널 API를 호출하여 리소스를 사용한다면, 이러한 리소스의 생명주기를 개발자가 직접 관리해야 합니다.
생각:
- use, useLinses 는 가끔 써봐서 알고 있었고 lineSequence 에 대한 이점을 좀 더 생각해 볼 수 있었다.
- 데이터 베이스 연결, http 통신시 등에서 라이브러리가 리소스 해제를 잘 해주는것에 감사함을 느꼈다
- 어쩌다 한번 쓰는 api 에 대해서는 책에 적혀있듯이 AutoCloseable 을 상속받은 Closeable 인터페이스를 구현하고 있다면 한번 더 리소스 해제를 해주고 있는지 혹은 직접 해야하는지 확인을 해보는게 좋을것 같다.
- AutoCloseable과 Closeable 인터페이스를 구현한다는 것은 해당 객체를 자동으로 리소스를 해제할 수 있는 능력을 갖추고 있다는것을 의미한다.
728x90
'공부 > 이펙티브코틀린' 카테고리의 다른 글
아이템 11 - 가독성을 목표로 설계하라 (0) | 2024.04.07 |
---|---|
아이템 10 - 단위 테스트를 만들어라 (0) | 2024.04.07 |
아이템 8 - 적절하게 null 을 처리하라 (0) | 2024.04.04 |
아이템 7 - 결과 부족이 발생할 경우 null 과 Failure 를 사용하라 (0) | 2024.03.31 |
아이템 6 - 사용자 정의 오류보다는 표준 오류를 사용하라 (0) | 2024.03.31 |
댓글