목록Book (47)
시배's Android
21장 플로우 만들기 원시값을 가지는 플로우 flowOf를 활용해 간단하게 플로우를 만들 수 있다. flowOf(1, 2, 3, 4,5 ).colect { // TODO } 값이 없는 플로우면 emptyFlow의 형태로 제공 컨버터 asFlow를 활용해 다음과 같은 타입을 플로우로 바꿀 수 있다. Iterable Iterator Sequence Mono Flux List 등등 함수를 플로우로 선언하기 함수가 플로우를 반환하도록 할 수 있다. fun someFunction(): Flow = flow { // Do Something emit(2) } 플로우와 리액티브 스트림 Flux, Mono또한 라이브러리에서 플로우의 변환을 제공한다. kotlinx-coroutines-reactor라이브러리를 활용하라 채..
20장 플로우의 실제 구현 플로우의 내부구현에 대해 알아보자. Flow 이해하기 간단한 람다식 @Test fun main() = runTest { val f: () -> Unit = { println("A") println("B") println("C") } f() } // 출력 겨로가 A B C 플로우는 위의 람다식과 별반 다를것이 없다. 아래는 실제 플로우의 내부 구현을 간단하게 구현해본 것이다. @Test fun main() = runTest { val f: suspend ((String) -> Unit) -> Unit = { emit -> emit("A") emit("B") emit("C") } f { println(it) } f { println(it) } } // 출력 결과 A B C A B ..
아이템49. 하나 이상의 처리 단계를 가진 경우에는 시퀀스를 사용하라 sequence 는 지연(lazy) 처리 된다. 따라서 시퀀스 처리 함수들을 사용하면, 데코레이터 패턴으로 꾸며진 새로운 시퀀스가 리턴된다. 시퀀스 처리 함수는 최정 연산이 이루어지기 전까지는 각 단계에서 연산이 일어나지 않는다. Iterable 은 처리 함수를 사용할 때마다 연산이 이루어져 List 가 만들어진다. 컬렉션 처리 연산은 호출할 때 연산이 이루어진다. 시퀀스의 지연 처리 장점 자연스러운 처리 순서를 유지 최소한만 연산 무한 시퀀스 형태로 사용 각각의 단계에서 컬렉션을 만들어 내지 않는다. 시퀀스가 빠르지 않은 경우 컬렉션 전체를 기반으로 처리해야 하는 연산은 시퀀스를 사용해도 빨라지지 않는다. sorted 는 Sequen..
아이템45. 불필요한 객체 생성을 피하라 Int 와 같은 기본형을 사용하면, 일반적으로 기본 자료형 int 로 컴파일 된다. 하지만 nullable 로 만들거나, 타입 아규먼트로 사용할 경우에는 Integer 로 컴파일 된다. 기본 자료형은 null 일 수 없고, 타입 아규먼트로도 사용할 수 없기 때문이다. 객체 생성 비용은 항상 클까? 현대 64비트 JDK 에서 객체는 8바이트의 배수만큼 공간을 차지한다. 앞부분 12바이트는 헤더로서 반드시 있어야 하므로, 최소 크기는 16바이트이다. 추가로 객체에 대한 레퍼런스도 공간을 차지한다. 일반적으로 레퍼런스는 -Xmx32G 까지는 32/64비트 플랫폼 모두 4바이트다. 64비트 플랫폼에서는 32G(-Xmx32G)부터는 8바이트이다. 캐시를 활용하는 팩토리 함..
36. 상속보다는 컴포지션을 사용하라 상속은 관계가 명확하지 않을 때 사용하면, 여러 가지 문제가 발생할 수 있습니다. (‘is-a’ 관계에서 사용) class ProfilerLoader { fun load() { // 프로그래스 바를 보여 줌 // 프로파일을 읽어 들임 // 프로그레스 바를 숨김 } } class ImageLoader { fun load() { // 프로그래스 바를 보여 줌 // 이미지를 읽어 들임 // 프로그레스 바를 숨김 } } 상속을 이용하면 위의 코드를 아래와 같이 시용할 수 있습니다. abstract class LoaderWithProgress { fun load() { // 프로그래스 바를 보여 줌 innerLoad() // 프로그래스 바를 숨김 } abstract fun i..
아이템 33. 생성자 대신 팩토리 함수를 사용하라 클라이언트가 클래스의 인스턴스를 만들게 하는 가장 일반적인 방법은 기본 생성자(Primary constructor)를 사용하는 방법이다. class MyLinkedList{ val head : T val tail : MyLinkedList? } val list = MyLinkedList(1, MyLinkedList(2, null)) 하지만 생성자가 객체를 만들수 있는 유일한 방법은 아니다. 헬퍼 클래스를 생각해보자. fun myLinkedListOf( ): MyLinkedList? { if(elements.isEmpty()) return null val head = elements.first() val elementsTail = elements. copy..
아이템26. 함수 내부의 추상화 레벨을 통일하라 계층이 잘 분리되면 무엇이 좋을까요? 어떤 계층에서 작업할 때 그 아래의 계층은 이미 완성되어 있으므로, 해당 계층만 생각하면 된다는 것입니다. 즉, 전체를 이해할 필요가 없어지는 것입니다. 추상화 레벨 높은 레벨로 갈수록 물리 장치로부터 점점 멀어집니다. 프로그래밍에서는 일반적으로 높은 레벨일수록 프로세서로부터 멀어진다고 표현합니다. 높은 레벨일수록 걱정해야 하는 세부적인 내용들이 적습니다. 높은 레벨일수록 단순함을 얻지만, 제어력을 잃습니다. 예를 들어 C언어는 메모리 관리를 직접 할 수 있습니다. 반면, 자바는 가비지 컬렉터가 자동으로 메모리를 관리해 줍니다. 추상화 레벨 통일 함수도 높은 레벨과 낮은 레벨을 구분해서 사용해야 한다는 원칙이 있습니다...
플로우는 비동기적으로 계산해야 할 값의 스트림을 나타냅니다. Flow 인터페이스 자체는 떠다니는 원소들을 모으는 역할을 하며, 플로우의 끝에 도달할 때까지 각 값을 처리하는 걸 의미합니다. 플로우를 사용하면 코루틴이 연산을 수행하는 데 필요한 기능을 전부 사용할 수 있습니다. 플로우의 빌더와 연산은 중단 함수이며 구조화된 동시성과 적절한 예외 처리를 지원합니다. 플로우는 어딘가에서 시작되어야 합니다. 플로우 빌더, 다른 객체에서의 변환, 또는 헬퍼 함수로부터 시작됩니다. 플로우의 마지막 연산은 최종 연산이라 불리며, 중단 가능하거나 스코프를 필요로 하는 유일한 연산이라는 점에서 아주 중요합니다. 시작 연산과 최종 연산 사이에 플로우를 변경하는 중간 연산을 가질 수 있습니다. 웹소켓이나 RSocket 알림..