본문 바로가기

Dev Book/Kotlin IN ACTION

(21)
CH6(6.1-1). 널 가능성 1. 널이 될 수 있는 타입 - 코틀린과 자바의 가장 중요한 차이는 코틀린 타입 시스템이 널이 될 수 있는 타입을 지원한다는 점이다. 자바에서는, 어떤 변수가 널이 될 수 있다면 그 변수에 대해 메소드를 호출할 시 NullPointerException이 발생할 수 있으므로 안전하지 않다. 코틀린은 그런 메소드 호출을 금지함으로써 많은 오류를 방지한다. (NPE의 경우 런타임 시 발생하지만, 코틀린에서는 컴파일 시 오류를 발생시킨다.) - strLen 함수의 경우 파라미터 s의 타입인 String이 널로 넘어오지 못하게 컴파일 오류를 발생시킨다. 이 함수가 널과 문자열을 인자로 받을 수 있게 하려면 타입 이름 뒤에 물음표(?)를 명시해야 한다. fun strLenSafe(s:String?) = ... ty..
CH5(5.5). 수신 객체 지정 람다 1. with 함수 fun alphabet(): String { val result = StringBuilder() for(letter in 'A'..'Z'){ result.append(letter) } result.append("\nNow I know the alphabet!") return result.toString() } >>>println(alphabet()) ABCDE....XYZ Now I know the alphabet! 위의 예제에서는 result에 대해 다른 여러 메소드를 호출하면서 매번 result를 반복 사용했다. 이 예제를 with로 다시 작성한 결과는 다음과 같다. fun alphabet(): String { val stringBuilder = StringBuilder() ret..
CH5(5.3). 지연 계산 컬렉션 연산 1. 지연 계산 컬렉션 연산 - map이나 filter 같은 함수들은 결과 컬렉션을 즉시 생성한다. 이는 컬렉션 함수를 연쇄하면 매 단계마다 계산 중간 결과를 새로운 컬렉션에 임시도 담는다는 뜻이다. 시퀀스를 사용하면 중간 임시 컬렉션을 사용하지 않고도 컬렉션 연산을 연쇄할 수 있다. people.map(Person::name).filter{ it.startWith("A") } -코틀린 표준 라이브러리 참조 문서에는 filter와 map이 리스트를 반환한다고 써 있다. 이는 이 연쇄 호출이 리스트를 2개 만든다는 뜻이다. 한 리스트는 filter의 결과를 담고, 다른 하나는 map의 결과를 담는다. 만약 원소가 수백만개가 되면 효율이 떨어질 것이다. 이를 효율적으로 하기 위해서는 각 연산이 컬렉션을 직접..
CH5(5.2). 컬렉션 함수형 API 1. filter와 map - filter 함수는 컬렉션을 이터레이션하면서 주어진 람다에 각 원소를 넘겨서 람다가 true를 반환하는 원소만 모은다. >>> val list = listOf(1,2,3,4) >>> println(list.filter { it%2 == 0 }) [2,4] - map 함수는 주어진 람다를 컬렉션의 각 원소에 적용한 결과를 모아서 새 컬렉션을 만든다. >>>val list = listOf(1,2,3,4) >>>println(list.map{ it*it }) [1,4,9,16] 2. all, any, count, find - 컬렉션의 모든 원소가 어떤 조건을 만족하는지 판단하는 연산이다. val canBeInClub27 = {p:Person -> p.age>> val people..
CH5(5.1). 람다 식과 멤버 참조 1. 람다 소개 - 함수형 프로그래밍에서는 함수를 값처럼 다루는 방식을 통해 코드를 함수에 넘기거나 변수에 저장할 수 있게 한다. 클래스를 선언하고 그 클래스의 인스턴스에 함수를 넘기는 대신, 함수형 언어에서는 함수를 직접 다른 함수에 전달할 수 있다. 람다 식을 이용하면 함수를 선언할 필요가 없고 코드 블록을 직접 함수의 인자로 전달할 수 있다. 2. 람다와 컬렉션 - 람다를 사용해 컬렉션 검색하기 >>> val people = listOf(Person("Alice", 29), Person("Bob", 31)) >>> println(people.maxBy{ it.age }) Person(name=Bob, age=31) maxBy는 가장 큰 원소를 찾기 위해 비교에 사용할 값을 돌려주는 함수를 인자로 받..
CH4(4.2). 뻔하지 않은 생성자와 프로퍼티를 갖는 클래스 1. 클래스 초기화 class User(val nickname:String) - 다음과 같이 클래스 이름 뒤에 오는 괄호로 둘러싸인 코드를 주 생성자라고 한다. 주 생성자는 생성자 파라미터를 지정하고 그 생성자 파라미터에 의해 초기화되는 프로퍼티를 정의하는데 쓰인다. - 함수 파라미터와 마찬가지로 생성자 파라미터에도 디폴트 값을 정의할 수 있다. - 클래스에 기반 클래스가 있다면 주 생성자에서 기반 클래스의 생성자를 호출해야 한다. 기반 클래스를 초기화 하려면 기반 클래스 이름 뒤에 괄호를 치고 생성자 인자를 넘긴다. 인자가 없는 기반 클래스를 상속해도 하위 클래스는 반드시 기반 클래스의 생성자를 호출해야 하므로 꼭 빈 괄호가 들어가야 한다. - 인터페이스는 생성자가 없기 때문에, 어떤 클래스가 인터페이..
CH4(4.3~4.4). 데이터 클래스와 클래스 위임, object 키워드 4.3. 1. 모든 클래스가 정의해야 하는 메소드 - 자바와 마찬가지로 코틀린 클래스도 toString, equals, hashCode 등을 오버라이드 할 수 있다. 하지만 이 경우, hashCode 정의를 빠뜨리면 해당 메소드를 오버라이드한 클래스가 제대로 동작하지 않는 경우가 있다. why? JVM 언어에서는 hashCode가 지켜야 하는 "equals()가 true를 반환하는 두 객체는 반드시 같은 hashCode()를 반환해야 한다" 라는 제약이 있는데, 이를 어기면 제대로 된 결과값을 얻을 수 없다. HashSet을 이용할 경우 이는 먼저 객체의 해시 코드를 비교하고 해시 코드가 같은 경우에만 실제 값을 비교한다. 따라서 원소 객체들이 해시 코드에 대한 규칙을 지키지 않는 경우 HashSet은 ..
CH4(4.1). 클래스 계층 정의 1. 코틀린 인터페이스 - 코틀린 인터페이스 안에는 추상 메소드뿐 아니라 구현이 있는 메소드도 정의할 수 있다. implements를 쓰는 자바와는 다르게, 클래스 상속과 마찬가지로 콜론(:)을 붙이고 인터페이스 이름을 적는 것으로 구현을 처리한다. 자바와 똑같이 인터페이스는 다중 구현이 가능하고, 클래스는 오직 하나만 확장할 수 있다. - 자바의 @overried 애노테이션과 비슷한 overried 변경자가 있다. 하지만 이는 상위 클래스, 인터페이스에 있는 프로퍼티나 메소드를 오버라이드 할 때 꼭 사용해야 한다. - 인터페이스 메소드도 디폴트 구현을 제공할 수 있다. 이 경우 그냥 메소드 본문을 메소드 시그니쳐 뒤에 추가하면 된다. 만약 한 클래스가 같은 메소드에 대해서 서로 다른 디폴트 구현이 있는..