✅ 실행 시 제네릭스의 동작 : 소거된 타입 파라미터와 실체화된 타입 파라미터 JVM의 제네릭스는 보통 타입 소거를 사용해 구현된다. 이는 실행 시점에 제네릭 클래스의 인스턴스에 타입 인자 정보가 들어있지 않다는 뜻이다. 타입 소거(type erasure)란? - 원소 타입을 컴파일 타임에만 검사하여 런타임에는 해당 타입 정보를 알 수 없게 하는 것 - 컴파일 타임에만 타입에 대한 제약 조건이 적용되며, 런타임에는 타입에 대한 정보를 제거한다는 뜻이다. 이번 절에서는 코틀린 타입 소거가 실용적인 면에서 어떤 영향을 끼치는지 살펴보고 함수를 inline으로 선언함으로써 이런 제약을 어떻게 우회할 수 있는지 살펴본다. 함수를 inline으로 만들면 타입 인자가 지워지지 않게 할 수 있다. 코틀린에서는 이를 ..
✅ 제네릭 타입 파라미터 제네릭스를 사용하면 타입 파라미터를 받는 타입을 정의할 수 있다. 제네릭 타입의 인스턴스를 만들려면 타입 파라미터를 구체적인 타입 인자로 치환해야 한다. 예를 들어 List라는 타입이 있으면 그 안에 들어가는 원소의 타입을 알 경우 쓸모가 있을 것이다. 타입 파라미터를 사용하면 "이 변수는 리스타"라고 말하는 대신 정확하게 "이 변수는 문자열을 담는 리스트다"라고 말할 수 있다. 코틀린에서는 자바와 마찬가지로 List과 같이 작성할 수 있다. 코틀린 컴파일러는 보통 타입과 마찬가지로 타입 인자도 추론할 수 있다. listOf에 전달된 두 값이 문자열이기 때문에 컴파일러는 여기서 생기는 리스트가 List임을 추론한다. 반면에 빈 리스트를 만들어야 한다면 타입 인자를 추론할 근거가 ..
✅ 고차 함수 안에서 흐름 제어 루프와 같은 명령형 코드를 람다로 바꾸기 시작했을 때 우리는 return 문제에 부딪칠 수 있다. 루프의 중간에 있는 return문의 의미를 이해하기는 쉽지만 그 루프를 filter와 같이 람다를 호출하는 함수로 바꾸고 인자로 전달하는 람다 안에서 return을 사용하면 어떻게 될까? 몇 가지 예제를 살펴보도록 하자. 📌 람다 안의 return문 : 람다를 둘러싼 함수로부터 반환 먼저 컬렉션에 대한 이터레이션을 두 가지 살펴보자. 다음 코드의 실행 결과는 이름이 Alice인 경우 lookForAlice 함수로부터 반환된다는 사실을 알 수 있다. /* 일반 루프 안에서 return 사용하기 */ data class Person(val name: String, val age:..
✅ 인라인 함수 : 람다의 부가 비용 없애기 코틀린에서 람다를 함수 인자로 넘기는 구문은 if나 for와 같은 일반 문장과 비슷하다. 5장에서 살펴본 with와 apply 함수가 그런 예다. [Kotlin In Action] 5장. 람다로 프로그래밍(5) - 수신 객체 지정 람다 : with와 apply ✅ 수신 객체 지정 람다 : with와 apply 코틀린에서 정의하고 있는 with와 apply 함수는 매우 편리하며 많은 사람들이 이용 중이며 이러한 코틀린 만의 람다식에는 독특한 특징이 있다. 그 기능은 바로 dahoonkk.tistory.com 그렇다면 람다를 활용한 코드의 성능은 어떨까에 대해 생각을 해봤을 때 일반 함수보다 덜 효율적일 수 있다. 람다 식을 사용하는 경우 일반 함수 구현에 비해 ..
✅ 고차 함수 정의 고차 함수란 다른 함수를 인자로 받거나 함수를 반환하는 함수를 말한다. 코틀린에서는 람다나 함수 참조를 사용해 함수를 값으로 표현할 수 있다. 따라서 고차 함수는 람다나 함수 참조를 인자로 넘길 수 있거나 람다나 함수 참조를 반환하는 함수이다. 이번 절에서는 이러한 고차 함수를 정의하는 방법에 대해 살펴보며 정의하기 전에 함수 타입에 대해 먼저 알아보자. 📌 함수 타입 람다를 인자로 받는 함수를 정의하려면 먼저 람다 인자의 타입을 어떻게 선언할 수 있는지 알아야 한다. 인자 타입을 정의하기 전에 더 단순한 경우로 람다를 로컬 변수에 대입하는 경우를 살펴보자. 코틀린의 타입 추론으로 인해 변수 타입을 지정하지 않아도 람다를 변수에 대입할 수 있다. 각 변수에 구체적인 타입 선언을 추가해..
✅ 프로퍼티 접근자 로직 재활용 : 위임 프로퍼티 코틀린이 제공하는 관례에 의존하는 특성 중 독특하면서 강력한 기능으로 위임 프로퍼티(delegated property)가 있다. 위임 프로퍼티를 사용하면 값을 뒷받침하는 필드에 단순히 저장하는 것보다 더 복잡한 방식으로 작동하는 프로퍼티를 쉽게 구현할 수 있다. 이러한 과정에서 접근자 로직을 매번 재구현할 필요가 없다. 예를 들어 프로퍼티는 위임을 사용해 자신의 값을 필드가 아닌 데이터베이스 테이블이나 브라우저 세션, 맵 등에 저장할 수 있다. 이러한 특성의 기반에는 위임이 있다. 위임은 객체가 직접 작업을 수행하지 않고 다른 도우미 객체가 그 작업을 처리하게 맡기는 디자인 패턴이다. 이때 작업을 처리하는 도우미 객체를 위임 객체(delegate)라 부른..
✅ 위임 패턴(Delegation Pattern)이란? 위임 패턴(Delegation Pattern)은 객체 지향 기반의 디자인 패턴으로 상속처럼 코드의 재사용성을 향상 시켜주기 위한 패턴이다. 객체 A가 특정 기능을 직접 처리하지 않고 다른 객체 B에게 위임하여 처리하도록 하는 방식이다. 📌 위임을 사용해야 하는 이유 프로그래밍을 하다보면 하위 클래스에서 상위 클래스를 상속하여 프로퍼티를 오버라이드 하는 경우가 많다. 이러한 오버라이딩 상황에서 상위 클래스의 내용이 변경될 경우 상위 클래스를 참조하고 있는 하위 클래스의 내용들이 틀어지게 되며 이는 곧 에러를 발생시키게 된다. 그 뿐만 아니라 상속은 다음과 같은 문제가 있다. 상위 클래스에 대한 하위 클래스의 의존도가 높아져 상위 클래스의 내용 변경 시..
✅ 구조 분해 선언과 component 함수 코틀린에서 사용하는 관례 중 하나로 구조 분해 선언이라는 것이 있다. 구조 분해를 사용하면 복합적인 값을 분해하여 여러 다른 변수를 한꺼번에 초기화할 수 있다. 아래 예제를 통해 구조 분해를 사용하는 방법을 알 수 있다. val p = Point(10, 20) val (x, y) = p // x와 y 변수를 선언한 다음에 p의 여러 컴포넌트로 초기화한다. println(x) // 10 println(y) // 20 구조 분해 선언은 일반 변수 언언과 비슷해 보이지만 =의 좌변에 여러 변수를 괄호로 묶는 다는 점에서 다르다. 구조 분해 선언의 내부에서는 다시 관례를 사용한다. 구조 분해 선언의 각 변수를 초기화하기 위해 componentN이라는 함수를 호출한다...
✅ 컬렉션과 범위에 대해 쓸 수 있는 관례 컬렉션을 다룰 때 가장 많이 쓰는 연산은 인덱스를 사용해 원소를 읽거나 쓰는 연산과 어떤 값이 컬렉션에 속해있는지 검사하는 연산이다. 이러한 연산 모두 연산자 구문으로 사용할 수 있다. 그렇다면 이런 연산을 지원하기 위해 어떤 관례를 사용하는지 알아보자. 📌 인덱스로 원소에 접근 : get과 set 우리는 이미 코틀린에서 맵의 원소에 접근할 때나 자바에서 배열 원소에 접근할 때 모두 각괄호( [ ] )를 사용한다는 사실을 알고 있다. 같은 연산자를 사용해 변경 가능 맵에 키 / 값 쌍을 넣거나 이미 맵에 들어있는 키 / 값 관계를 변경할 수 있다. mutableMap[key] = newValue 이제 이 코드가 어떻게 동작하는지 살펴보면 코틀린에서는 인덱스 연산..
✅ 비교 연산자 오버로딩 코틀린에서는 산술 연산자와 마찬가지로 원시 타입 값뿐 아니라 모든 객체에 대해 비교 연산을 수행할 수 있다. equals나 compareTo를 호출해야 하는 자바와 달리 코틀린에서는 == 비교 연산자를 직접 사용할 수 있다. 이로 인해 코드를 더 간결하고 이해하기 쉽게 작성할 수 있다. 이번 절에서는 이런 비교 연산자를 지원하는 관례에 대해 알아보자. 📌 동등성 연산자 : equals 코틀린에서는 ==와 !=를 사용해 equals를 호출하여 내부의 인자가 널인지 아닌지 검사하게 된다. a==b 라는 비교 처리를 할 때 a가 널이 아닌 경우에만 a.equals(b)를 호출한다. 이때, a가 널이면 b도 널인 경우에만 결과가 true이다. /* equals 메소드 구현하기 */ cl..
✅ 연산자 오버로딩과 기타 관례 언어 기능을 타입에 의존하는 자바와 달리 코틀린은 함수 이름을 통한 관례에 의존한다. 코틀린이 이런 관례를 채택한 이유는 기존 자바 클래스를 코틀린 언어에 적용하기 위함이다. 기존 자바 클래스에 대해 확장 함수를 구현하면서 관례에 따라 이름을 붙이면 기존 자바 코드를 바꾸지 않아도 새로운 기능을 쉽게 부여할 수 있다. 이번 절에서는 코틀린이 지원하는 여러 관례와 그 관례의 사용법에 대해 알아본다. ✅ 산술 연산자 오버로딩 코틀린에서 관례를 사용하는 가장 단순한 예는 산술 연산자이다. 자바에서는 원시 타입에 대해서만 산술 연산자를 사용할 수 있고, 추가로 String에 대해 + 연산자를 사용할 수 있다. 다른 클래스에서도 산술 연산자를 유용하게 사용하면 어떨까?? 컬렉션에 ..
✅ 컬렉션과 배열 코틀린 컬렉션이 자바 라이브러리를 바탕으로 만들어졌고 확장 함수를 통해 추가할 수 있다는 것을 배웠다. 이 외에 코틀린의 컬렉션 지원과 자바와 코틀린 컬렉션 간의 관계에 대해 더 살펴보도록 하자. 📌 널 가능성과 컬렉션 컬렉션 안에 널 값을 넣을 수 있는지 여부는 어떤 변수의 값이 널이 될 수 있는지 여부와 마찬가지로 중요하다. 변수 타입 뒤에 ?를 붙이면 그 변수에 널을 저장할 수 있다는 뜻인 것처럼 타입 인자로 쓰인 타입에도 같은 표시를 사용할 수 있다. fun addValidNumbers(numbers: List) { var sumOfValidNumbers = 0 var invalidNumbers = 0 for (number in numbers) { // 리스트에서 널이 될 수 있..