개발 언어/코틀린
인프런 - 코틀린 고급편 (2) 지연과 위임
jjiiiinn
2024. 7. 1. 07:31
728x90
8강. lateinit, lazy()
class Person(
private val name: String
) {
val isKim: Boolean
get() = this.name.startsWith("최")
// 홍길동 -> 홍**
val maskingName: String
get() = name[0] + (1 until name.length).joinToString("") { "*" }
}
fun main() {
val person = Person("홍길동")
}
- 클래스 인스턴스화가 이뤄지며
name
에 '홍길동'이 들어감
만약, 인스턴스화 시점과 프로퍼티 초기화 시점을 분리하고 싶다면?
- 테스트 코드 작성
- 테스트 코드의 특징은 각 테스트 메소드가
Person
을 각각 인스턴스화 하고있음 - 두 개의 테스트 메소드의 Person 초기값이 다름
- 테스트 코드의 특징은 각 테스트 메소드가
class PersonTest {
@Test
fun isKimTest() {
val person = Person("김수한무")
assertTrue(person.isKim)
}
@Test
fun maskingNameTest() {
val person = Person("홍길동")
assertEquals(person.maskingName, "홍**")
}
}
테스트 코드 리팩토링
- 인스턴스화를 한번만 하고 테스트할때 변수를 초기화하기
- 인스턴스화 할때 초기값을 넣고싶지 않음
방법1. name에 기본값 넣어주기
- 변수가 변경 가능해야하니
val
->var
로 변경 - 기본값이 있으니 생성자에 있을 필요가 없음
class Person {
var name: String = "홍길동" // 초기값 설정
...
}
class PersonTest {
private val person = Person()
@Test
fun isKimTest() {
val person = this.person.apply { name = "김수한무" }
assertTrue(person.isKim)
}
@Test
fun maskingNameTest() {
val person = this.person.apply { name = "홍길동" }
assertEquals(person.maskingName, "홍**")
}
}
방법1의 문제점
- 위와 같은 방식은
name
을 초기화하지 않더라도 예외가 발생하지 않아 알수 없음
방법2. name을 nullable
하게 만들기
- 초기화하지 않았을때 에러가 발생해 알수 있고, 누군가의 이름이
null
인 경우는 없음
class Person {
var name: String? = null // nullable
val isKim: Boolean
get() = this.name!!.startsWith("김")
// 홍길동 -> 홍**
val maskingName: String
get() = name!![0] + (1 until name!!.length).joinToString("") { "*" }
}
방법2의 문제점
- 실제
name
이 null이 되면 안되기에 계속 널처리(?.
,?:
,!!
)가 들어가게 됨
방법3. lateinit 사용하기
- 핵심은 인스턴스화 시점과 변수 초기화시점을 분리하는것!
lateinit
을 사용하면 초기값을 지정하지 않고, null이 들어갈수 없는 변수를 선언 가능
class Person {
lateinit var name: String
val isKim: Boolean
get() = this.name.startsWith("김")
// 홍길동 -> 홍**
val maskingName: String
get() = name[0] + (1 until name.length).joinToString("") { "*" }
}
lateinit의 원리
lateinit
변수는 컴파일 단계에서nullable
변수로 바뀌고, 변수에 접근하려 할때null
이면 에러 발생- 위와같은 특징으로
lateinit
은 primitive type에 사용하지 못함 (null 할당 불가)
- 위와같은 특징으로
이번에는 변수를 초기화 할때 지정된 로직은 1회만 실행하고 싶음
- 값을 가져오는 비용이 크고 변수가 사용되지 않을수도 있을때 유용함
- 예를 들어 아래와같이
name
을 가져오는데 2초가 걸리는 변수가 존재 - name을 호출할때 마다 2초가 걸림
class LazyPerson { val name: String get() { Thread.sleep(2_000) return "김수한무" } }
- 아래와같이
init
블록에 넣으면 1회만 호출되나name
을 사욯하지 않는 경우에도sleep
이 호출됨
class LazyPerson {
val name: String
init {
Thread.sleep(2_000)
name = "김수한무"
}
}
backing property
name
이 호출되지 않으면 backing property 초기화가 일어나지 않음name
이 호출되면 최초 한번만 초기화가 일어남
class LazyPerson {
private var _name: String? = null // backing property
val name: String
get() {
if (this._name == null) {
Thread.sleep(2_000)
this._name = "김수한무"
}
return this._name!!
}
}
by lazy
- backing property를 사용할때와 같은 동작을 하면서 간단하게 구현 가능
lazy block
은name
의 getter가 실행될때 최초 1번만 실행되며 Thread-safe 함class LazyPerson { val name: String by lazy { Thread.sleep(2_000) "김수한무" } }
응용 및 실제 상황 질문
- 테스트 코드에서 lateinit을 사용하는 이유는 무엇인가요?
- 테스트 코드 작성 시 lateinit을 사용하면 어떤 이점이 있나요?
- 실제 프로젝트에서 lazy를 사용하는 예를 들어주세요.
- 실제 프로젝트에서 lazy를 어떻게 사용해보았나요? 또는 사용한다면 어떤 상황에서 유용할까요?
- lateinit과 lazy를 함께 사용할 수 있는 시나리오를 설명해주세요.
- lateinit과 lazy를 함께 사용하는 시나리오가 있다면 어떤 경우일까요?
- lateinit과 nullable 변수의 차이점
- lateinit을 사용하는 것과 변수를 nullable하게 만드는 것의 차이점은 무엇인가요?
- 초기화 비용이 큰 변수를 처리하는 방법
- 초기화 비용이 큰 변수를 처리할 때 lateinit과 lazy 중 어떤 것을 선택해야 할까요? 그 이유는 무엇인가요?
9강. by lazy의 원리와 위임 프로퍼티
아래 코드를 좀더 재사용 가능한 구조로 변경 할 예정
class LazyPerson {
private var _name: String? = null
val name: String
get() {
if (_name == null) {
Thread.sleep(2_000)
this._name = "김수한무"
}
return this._name!!
}
}
LazyInitProperty
클래스를 만들어 템플릿화 함Person
의name
getter가 호출되면 곧바로LazyInitProperty
의 getter가 호출됨- 위임 패턴
- 위임 패턴
class LazyPerson {
private val delegateProperty = LazyInitProperty {
Thread.sleep(2_000)
"김수한무"
}
val name: String
get() = delegateProperty.value
}
class LazyInitProperty<T>(val init: () -> T) {
private var _value: T? = null
val value: T
get() {
if (_value == null) {
this._value = init()
}
return this._value!!
}
}
by lazy
역시 완전히 동일한 원리!!
- `by`: 코틀린에 존재하는 키워드, `name`의 getter는 뒤 객체의 getter로 이어줌
class LazyPerson {
val name: String by lazy {
Thread.sleep(2_000)
"김수한무"
}
}
lazy
함수는 Lazy()객체를 반환하므로 아래와 같이 변환됨public actual fun <T> lazy(initializer: () -> T): Lazy<T> = SynchronizedLazyImpl(initializer)
class Person {
// by: name의 getter를 Lazy객체의 getter로 이어줌
val name: String by Lazy()
}
by
뒤에 위치한 클래스는getValue
또는setValue
함수를 가지고 있어야함.
getValue
자세히 알아보기
operator fun getValue(thisRef: R, property: KProperty<*>): T {
}
thisRef
: 위임 프로퍼티를 가지고있는 클래스의 인스턴스 (Person)property
: 위임 프로퍼티 정보 (name)
LazyInitProperty
에 getValue
추가해보기
class LazyPerson {
// getValue를 추가했으므로 by 키워드 사용가능
val name: String by LazyInitProperty {
Thread.sleep(2_000)
"김수한무"
}
}
class LazyInitProperty<T>(val init: () -> T) {
private var _value: T? = null
val value: T
get() {
if (_value == null) {
this._value = init()
}
return this._value!!
}
operator fun getValue(thisRef: Any, property: KProperty<*>): T {
return value
}
}
setValue
자세히 알아보기
getValue
와 거의 동일- setter에서는 값이 변경되니, 변경될 값을 파라미터로 받음
operator fun setValue(thisRef: R, property: KProperty<*>, value: T) {
}
질문 내용
by lazy
에 대한 질문
by lazy
의 기본 개념을 설명해주세요.by lazy
키워드는 무엇을 위해 사용되며, 어떻게 작동하나요?
by lazy
의 초기화 타이밍by lazy
로 선언된 변수가 언제 초기화되나요? 이 초기화는 몇 번 발생하나요?
by lazy
와 Thread-safetyby lazy
의 기본 구현은 어떻게 thread-safe를 보장하나요?
by lazy
의 사용 예시- 실제 프로젝트에서
by lazy
를 어떻게 사용해보았나요? 또는 사용한다면 어떤 상황에서 유용할까요?
- 실제 프로젝트에서
by lazy
의 장점과 단점by lazy
를 사용하는 것의 장점과 단점은 무엇인가요?
위임 프로퍼티에 대한 질문
- 위임 프로퍼티의 기본 개념을 설명해주세요.
- 위임 프로퍼티란 무엇이며, 어떻게 사용되나요?
getValue
메소드의 역할- 위임 프로퍼티에서
getValue
메소드는 어떤 역할을 하나요?
- 위임 프로퍼티에서
setValue
메소드의 역할- 위임 프로퍼티에서
setValue
메소드는 어떤 역할을 하나요?
- 위임 프로퍼티에서
- 위임 패턴의 이점
- 위임 패턴을 사용하는 것의 이점은 무엇인가요? 예시를 들어 설명해주세요.
by lazy
와 위임 프로퍼티의 관계by lazy
와 위임 프로퍼티의 관계를 설명해주세요. 어떻게 연관되어 있나요?
코드 이해 및 적용 질문
LazyInitProperty
클래스의 역할LazyInitProperty
클래스는 어떤 역할을 하나요? 해당 클래스의getValue
메소드는 어떻게 작동하나요?
- 위임 프로퍼티의 재사용성
LazyInitProperty
클래스를 사용하면 코드의 재사용성이 어떻게 향상되나요?
by lazy
와LazyInitProperty
의 차이점by lazy
와LazyInitProperty
를 사용하는 것의 차이점은 무엇인가요?
- 실제 상황에서의 적용
- 실제 상황에서 위임 프로퍼티를 사용해본 경험이 있나요? 있다면 어떤 상황이었고, 어떻게 적용했나요?
- 위임 프로퍼티의 활용 예제
- 위임 프로퍼티를 활용한 다른 예제 코드를 작성해보세요. 그 코드에서
getValue
와setValue
를 어떻게 구현할 수 있을까요?
- 위임 프로퍼티를 활용한 다른 예제 코드를 작성해보세요. 그 코드에서
10강. 코틀린의 표준 위임 객체
notNull()
lateinit
과 비슷한 역할을 함- 아직 초기화되지 않았다면
IllegalStateException
발생 - primity type에는
lateinit
을 사용할 수 없지만notNull()
은 사용가능!
class LazyPerson2 {
var age: Int by notNull()
}
observable()
observable
함수는 초기값과onChange
함수를 받음onChange
함수는 setter가 호출될 때마다 호출됨// 함수 시그니쳐, 간략화한 코드 public inline fun <T> observable( initialValue: T, onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Unit )
class LazyPerson2 {
var age: Int by observable(20) { _, oldValue, newValue ->
println("이전 값 : $oldValue, 새로운 값: $newValue")
}
}
fun main() {
val p = ObservablePerson()
p.age = 30
}
// 출력 결과
// 이전 값 : 20, 새로운 값: 30
vetoalbe()
observable
과 비슷하나onChange
함수가 Boolean을 반환- setter가 호출될때
onChange
함수가true
를 반환하면 변경 적용,false
를 반환하면 이전값이 그대로 남음
// 함수 시그니쳐, 간략화한 코드
public inline fun <T> vetoable(
initialValue: T,
onChange: (property: KProperty<*>, oldValue: T, newValue: T) -> Boolean
)
class VetoablePerson {
// age가 0 이상일 경우만 셋팅됨
var age: Int by vetoable(20) { _, _, newValue ->
newValue > 0
}
}
또 다른 프로퍼티로 위임하기
- 사람의 나이를
num
프로퍼티에 저장하고 있음 - 프로퍼티의 이름을 변경하고 싶으나 호환성을 유지해야함
class AgePerson {
var num: Int = 0
}
- 프로퍼티 앞에
::
을 붙이면 위임객체로 사용 가능 - 코드 사용자들이
age
로 코드를 변경하면 그때num
을 제하면 됨 class AgePerson { @Deprecated("age를 사용하세요!", ReplaceWith("age")) var num: Int = 0 var age: Int by this::num }
map
- getter가 호출되면
map["name"]
또는map["age"]
를 찾음- ex)
MapPerson
의name
프로퍼티 접근시map
에서name
키의 값을 가져오도록 위임 - map에
name
이나age
키값이 없다면 에러 발생
- ex)
MutableMap
사용시val
대신var
도 사용 가능
class MapPerson(map: Map<String, Any>) {
val name: String by map
val age: Int by map
}
질문 내용
notNull()에 대한 질문
notNull()
의 기본 개념을 설명해주세요.notNull()
키워드는 무엇을 위해 사용되며, 어떻게 작동하나요?
notNull()
과lateinit
의 차이점notNull()
과lateinit
의 차이점은 무엇인가요?
notNull()
의 사용 예시notNull()
을 사용하는 실제 예시를 들어보세요. 어떤 상황에서 유용할까요?
notNull()
을 사용한 초기화 검사notNull()
을 사용한 변수가 초기화되지 않았을 때 발생하는 예외는 무엇인가요?
notNull()
을 primitive 타입에 사용할 수 있는 이유- 왜
notNull()
은 primitive 타입에 사용할 수 있는지 설명해주세요.
- 왜
observable()에 대한 질문
observable()
의 기본 개념을 설명해주세요.observable()
함수는 무엇을 위해 사용되며, 어떻게 작동하나요?
observable()
함수의 시그니처observable()
함수의 시그니처와 매개변수를 설명해주세요.
observable()
의 사용 예시observable()
을 사용하는 실제 예시를 들어보세요. 어떤 상황에서 유용할까요?
observable()
의 onChange 함수observable()
의onChange
함수는 언제 호출되며, 어떤 역할을 하나요?
observable()
을 사용한 상태 변화 추적observable()
을 사용하여 객체의 상태 변화를 추적하는 방법을 설명해주세요.
vetoable()에 대한 질문
vetoable()
의 기본 개념을 설명해주세요.vetoable()
함수는 무엇을 위해 사용되며, 어떻게 작동하나요?
vetoable()
함수의 시그니처vetoable()
함수의 시그니처와 매개변수를 설명해주세요.
vetoable()
의 사용 예시vetoable()
을 사용하는 실제 예시를 들어보세요. 어떤 상황에서 유용할까요?
vetoable()
과observable()
의 차이점vetoable()
과observable()
의 차이점은 무엇인가요?
vetoable()
을 사용한 조건부 변경vetoable()
을 사용하여 조건부로 프로퍼티 값을 변경하는 방법을 설명해주세요.
또 다른 프로퍼티로 위임하기에 대한 질문
- 프로퍼티 위임의 기본 개념을 설명해주세요.
- 프로퍼티를 다른 프로퍼티로 위임하는 것은 무엇을 의미하나요?
- 프로퍼티 위임의 사용 예시
- 프로퍼티 위임을 사용하는 실제 예시를 들어보세요. 어떤 상황에서 유용할까요?
- 위임 프로퍼티의 장점
- 프로퍼티를 위임해서 얻는 장점은 무엇인가요?
- 호환성을 유지하는 프로퍼티 위임
- 호환성을 유지하면서 프로퍼티 이름을 변경하는 방법을 설명해주세요.
- 위임 프로퍼티의 @Deprecated 어노테이션
- 위임 프로퍼티에
@Deprecated
어노테이션을 사용하는 이유는 무엇인가요?
- 위임 프로퍼티에
map에 대한 질문
- map 위임의 기본 개념을 설명해주세요.
- map 위임이란 무엇이며, 어떻게 작동하나요?
- map 위임의 사용 예시
- map 위임을 사용하는 실제 예시를 들어보세요. 어떤 상황에서 유용할까요?
- map 위임의 장점과 단점
- map 위임을 사용하는 것의 장점과 단점은 무엇인가요?
- MutableMap을 사용한 프로퍼티 변경
MutableMap
을 사용하여 프로퍼티 값을 변경하는 방법을 설명해주세요.
- map 위임의 키와 값
- map 위임에서 키와 값이 어떻게 매핑되는지 설명해주세요.
11강. 위임과 관련된 몇 가지 추가 기능
- 위임 객체를 만들기위해 필요한것
getValue()
/setValue()
- 시그니처를 외우지 않고
ReadOnlyProerty
와ReadWriteProperty
를 사용
ReadOnlyProerty
와 ReadWriteProperty
getValue()
/setValue()
의 시그니처를 기억하지 않아도 됨- 익명 클래스를 사용할 수 있음
public fun interface ReadOnlyProperty<in T, out V> {
public abstract operator fun getValue(thisRef: T, property: kotlin.reflect.KProperty<*>): V
}
public interface ReadWriteProperty<in T, V> : ReadOnlyProperty<T, V> {
public override operator fun getValue(thisRef: T, property: KProperty<*>): V
public operator fun setValue(thisRef: T, property: KProperty<*>, value: V)
}
예시
getValue()
/setValue()
의 시그니처class LazyInitProperty<T>(val init: () -> T): ReadOnlyProperty<Any, T> { ... override fun getValue(thisRef: Any, property: KProperty<*>): T { return value }
}
- 익명 클래스를 사용
```kotlin
class LazyInitProperty<T>(val init: () -> T): ReadOnlyProperty<Any, T> {
...
val status: String by object: ReadOnlyProperty<Any, String> {
private var isGreen = false
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return if (isGreen) {
"Happy"
} else {
"Sad"
}
}
}
}
위임 프로퍼티와 위임 객체를 연결할 때 로직 끼워넣기
- 예를들어 프로퍼니의 이름이
name
일때만 정상 동작해야하는 위임객체가 필요class DelegateNamePerson { val name by DelegateProperty("최태현") // 정상 동작 O val country by DelegateProperty("한국") // 정상 동작 X }
class DelegateProperty(
private val initValue: String
): ReadOnlyProperty<Any, String> {
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return initValue
}
}
### 방법1. `propertyName` 파라미터 추가
- 프로퍼티 명을 직접 넣어줘야 해서 불편
- 비슷한 요구사항이 나올때 마다 작업을 해줘야함
```kotlin
class DelegateNamePerson {
val name by DelegateProperty("최태현", "name")
val country by DelegateProperty("한국", "country")
}
class DelegateProperty(
private val initValue: String,
propertyName: String, // 추가
): ReadOnlyProperty<Any, String> {
init {
// property name 검사
if (propertyName != "name") {
throw IllegalArgumentException("name에서만 사용가능!")
}
}
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return initValue
}
}
방법2. provideDelegate
함수 사용
- 어떤 객체가
provideDelegate
를 가지고있으면 위임객체 대신by
뒤에 사용 가능
class DelegateNamePerson {
val name by DelegateProvider("최태현")
val country by DelegateProvider("한국")
}
// property와 delegate 사이의 중간다리 역할
class DelegateProvider(
private val initValue: String,
): PropertyDelegateProvider<Any, DelegateProperty> {
override fun provideDelegate(thisRef: Any, property: KProperty<*>): DelegateProperty {
if (property.name != "name") {
throw IllegalArgumentException("${property.name}은 안됩니다! name만 사용가능!")
}
return DelegateProperty(initValue)
}
}
class DelegateProperty(
private val initValue: String,
): ReadOnlyProperty<Any, String> {
override fun getValue(thisRef: Any, property: KProperty<*>): String {
return initValue
}
}
위임클래스
- 아래와 같이
Fruit
인터페이스가 있고Fruit
를 구현한Apple
이 존재함 - 여기서
GreenApple
을 추가하려면 어떻게 해야할까?interface Fruit { val name: String val color: String fun bite() }
class Apple: Fruit {
override val name: String
get() = "사과"
override val color: String
get() = "빨간색"
override fun bite() {
println("냠냠 사과")
}
}
### 방법1) `Fruit`을 구현한 `GreenApple` 클래스 생성
- `Apple`과 중복이 많음
- `name`, `bite()`가 중복됨
```kotlin
class GreenApple: Fruit {
override val name: String
get() = "사과"
override val color: String
get() = "초록색"
override fun bite() {
println("냠냠 사과")
}
}
방법2) Apple
을 상속받아 GreenApple
클래스를 새로 구현
Apple
을 불필요하게 상속받을 경우가 생길수 있음- 상속 보단 합성!
open class Apple: Fruit { override val name: String get() = "사과" override val color: String get() = "빨간색" override fun bite() { println("냠냠 사과") } }
class GreenApple2: Apple() {
// 필요한 부분만 재구성
override val color: String
get() = "초록색"
}
### 방법3) 합성 사용
- 방법2의 상속보다 코드양이 많아짐
```kotlin
class GreenApple3(private val apple: Apple): Fruit {
override val name: String
get() = this.apple.name
override val color: String
get() = "초록색"
override fun bite() {
this.apple.bite()
}
}
방법4) 클래스 위임 사용
by
키워드를 사용하여 클래스 위임을 사용가능 (합성을 편하게 사용 가능)class GreenApple3(private val apple: Apple): Fruit by apple { override val color: String get() = "초록색" }
질문내용
- 기본적인 내용 확인
- ReadOnlyProperty와 ReadWriteProperty의 기본적인 역할과 차이점은 무엇인가요?
- getValue()와 setValue() 메서드의 시그니처를 외울 필요 없이 ReadOnlyProperty와 ReadWriteProperty를 사용하는 것이 어떤 점에서 유용한가요?
- 코드 이해와 적용
- LazyInitProperty 클래스에서 익명 클래스를 사용하여 프로퍼티를 정의할 때의 장점은 무엇인가요?
- DelegateProperty와 DelegateProvider 클래스를 사용하는 예시에서, provideDelegate 함수의 역할은 무엇인가요?
- DelegateProperty 클래스의 getValue() 메서드에서 initValue를 반환하는 방식 대신 다른 로직을 추가하려면 어떻게 해야 할까요?
- 심화된 주제 탐구
- 위임 프로퍼티와 위임 객체를 연결할 때 로직을 끼워넣는 두 가지 방법의 장단점은 무엇인가요?
- DelegateProvider 클래스를 사용하여 특정 프로퍼티에만 위임 객체를 사용하도록 제한할 때 발생할 수 있는 문제점은 무엇인가요?
- 위임 클래스와 합성
- GreenApple을 구현할 때 상속 대신 합성을 사용하는 이유는 무엇인가요?
- 합성을 사용할 때 코드량이 많아지는 단점에도 불구하고 합성을 선호해야 하는 이유는 무엇인가요?
- 클래스 위임을 사용하여 GreenApple3 클래스를 정의할 때 Fruit 인터페이스의 다른 메서드를 재정의하지 않고도 Apple의 메서드를 활용할 수 있는 이유는 무엇인가요?
- 실전 적용과 응용
- 실무에서 provideDelegate를 사용할 수 있는 다른 예시에는 어떤 것들이 있을까요?
- 클래스 위임을 사용하여 복잡한 객체의 기능을 확장하는 다른 예시를 들어 설명해 줄 수 있나요?
12강. Iterable과 Sequence (feat. JMH)
Collection
- 우리는 데이터를 조작할때
Collection
을 사용함- 이러한
Iterable
은 연산의 각 단계마다 중간Collection
이 임시로 생성됨
- 이러한
- 중간
Collection
을 만들지 않는 방법을 없을까?
data class MyFruit(
val name: String,
val price: Long,
)
fun main() {
val fruits = listOf(
MyFruit("사과", 1000L),
MyFruit("바난ㅏ", 3000L),
)
val avg = fruits
.filter { it.name == "사과" }
.map { it.price }
.take(10_000)
.average()
}
Sequence
- 중간
Collection
을 만들지 않고 데이터를 조작할 수 있음 asSequence()
를 통해 만들수 있음
val avg = fruits.asSequence()
.filter { it.name == "사과" }
.map { it.price }
.take(10_000)
.average()
Sequence
의 동작원리
- 각 단계(filter, map)가 모든 원소에 적용되지 않을수 있음
- 한 원소에 대해 모든 연산을 진행하고 다음 원소로 넘어감
- 최종 연산이 나오기전까지 계산 자체를 미리 하지 않음 (지연연산)
Sequence
가 Iterable
보다 빠를까?
- JMH 벤치마크 진행
- 대용량일때
Sequence
가 더빠름 Sequence
는 연산 순서에 큰 차이가 날수 있음
질문 내용
- 기본적인 내용 확인
- Collection과 Iterable의 차이점은 무엇인가요?
- Sequence를 사용하는 주된 이유는 무엇인가요?
- 코드 이해와 적용
- fruits 리스트에서 asSequence()를 사용했을 때와 사용하지 않았을 때의 차이점은 무엇인가요?
- 심화된 주제 탐구
- Sequence가 중간 Collection을 생성하지 않기 때문에 성능상 이점이 있는 이유는 무엇인가요?
- Sequence의 동작 원리에서 지연 연산(lazy evaluation)이란 무엇인가요? 이 개념이 어떻게 성능을 향상시키나요?
- 실전 적용과 응용
- Sequence를 사용하지 않으면 filter와 map 연산에서 중간 Collection이 어떻게 생성되는지 설명해 주세요.
- Sequence가 모든 상황에서 Iterable보다 더 나은 선택일까요? 어떤 경우에는 그렇지 않을 수 있을까요?
- 벤치마크와 성능
- JMH 벤치마크는 무엇이며, 왜 Sequence의 성능을 평가하는 데 유용한가요?
- 대용량 데이터를 처리할 때 Sequence가 더 빠른 이유는 무엇인가요?
- Sequence의 연산 순서에 따라 성능 차이가 발생할 수 있다고 했는데, 예시를 들어 설명해 주세요.
- 일반적인 고려 사항
- Sequence를 사용할 때 주의해야 할 점은 무엇인가요?
- 작은 데이터셋에서도 Sequence를 사용하는 것이 좋은 선택일까요? 이유는 무엇인가요
위 내용은 인프런 코틀린 고급편강의를 시청하고 작성했습니다
인프런
728x90