지연 계산 컬렉션

lazy collection 연산에 대해 정리한다.

지연 계산 (lazy) 켈렉션 연산

다음 예를 보자.

1
2
3
people
.map(Person::name)
.filter { it.startsWith("A") }

filter 와 map 은 리스트를 반환한다.
즉 위 코드는, 한 리스트는 filter 의 결과를 담고 다른 리스트는 map 의 결과를 담는다.
원소의 개수가 수백만 개라면 효율이 떨어질 수 있다.

그래서, 각 연산이 컬렉션을 직접 사용하는 대신 시퀀스를 사용하게 만들어 효율을 높일 수 있다.

1
2
3
4
people.asSequence()     // 원본 컬렉션을 시퀀스로 변환
.map(Person::name)
.filter { it.startsWith("A") }
.toList() // 결과 시퀀스를 다시 리스트로 변환

시퀀스 연산 실행 : 중간 연산, 최종 연산

자바 8의 스트림과 코틀린의 시퀀스의 개념은 같다.

중간 연산은 다른 시퀀스를 반환한다.
최종 연산은 결과를 반환한다.

Read more

표준 라이브러리

컬렉션을 다루는 코틀린 표준 라이브러리를 정리한다.

  • filter, map
  • all, any, count, find
  • groupBy
  • flatMap, flatten
  • with, apply

filter, map

filter 는 컬렉션에서 원치 않는 원소를 제거한다.

1
2
val list = listOf(1, 2, 3, 4)
println(list.filter { it % 2 == 0 })

결과는,
컬렉션의 원소 중에, 주어진 술어 (==predicate, 참/거짓을 반환하는 함수) 를 만족하는 원소로 이루어진 새로운 컬렉션이다.

map 은 원소를 변환한다.

1
2
val list = listOf(1, 2, 3, 4)
println(list.map { it * it })

결과는,
원본 리스트와 원소 개수는 같지만 각 원소는 주어진 함수에 따라 변환된 새로운 컬렉션이다.

all, any, count, find

Read more

object 키워드

object 키워드가 사용되는 경우인, 다음 내용을 정리한다.

  • 객체 선언
  • 동반 객체
  • 객체 식

객체 선언 : 싱글턴 객체 생성

인스턴스가 하나만 필요한 경우가 있다.
자바에서는 다음과 같이 singleton pattern 으로 구현할 수 있다.

  1. 클래스의 생성자를 private 으로 제한하고,
  2. 정적인 플드에 그 클래스의 유일핸 객체를 저장

코틀린은 ‘객체 선언’ 기능을 통해, 싱글턴 패턴을 언어에서 기본 지원한다.
( 객체 선언 = 클래스 선언 + 그 클래스에 속한 단일 인스턴스 선언 )

object keyword 를 사용해서,
클래스를 정의하고 그 클래스의 인스턴스를 만들어서 변수에 저장하는 모든 작업을 한 문장으로 처리한다.
일반 클래스의 객체와 달리, 싱글턴 객체는 객체 선언문이 있는 위치에서 생성자 호출없이 즉시 만들어진다.

1
2
3
4
5
6
7
8
9
10
11
12
13
object Payroll {
val allEmployees = arrayListOf<Person>()

fun calculateSalary() {
for (person in allEmployees) {
//..
}
}
}

// usage
Payroll.allEmployees.add(Person(name = "jko", isMarried = false))
Payroll.calculateSalary()

클래스 안에 객체로 선언할 수도 있다.

1
2
3
4
5
6
7
8
9
10
data class Person(val name: String) {

object NameComparator : Comparator<Person> {
override fun compare(o1: Person, o2: Person): Int = o1.name.compareTo(o2.name)
}
}

// usage
val persons = listOf(Person("jko"), Person("junhee-ko"))
println(persons.sortedWith(Person.NameComparator))
Read more

데이터 클래스

다음 내용을 정리한다.

  • 데이터 클래스 : toString(), equals(), hashCode(), copy()
  • 클래스 위임 패턴 : by

모든 클래스가 정의해야하는 메서드

간단한 클래스를 작성해보자.

1
class Client(val name: String, val postCode: Int)

이 클래스에 대해서,
toString(), equals(), hashCode() 메서드들이 어떻게 사용되는지 보자.

toString()

기본 제공되는 객체의 문자열 표현은 다음과 같은 형식이다 : Client@5e9f23bf
기본 구현을 바꾸려면 toString 메서드를 오버라이드해야한다.

1
2
3
4
class Client(val name: String, val postCode: Int) {

override fun toString(): String = "Client(name='$name', postCode=$postCode)"
}

equals()

Read more

생성자

다음 내용을 정리한다.

  • 주 생성자, 부 생성자
  • 인터페이스의 프로퍼티
  • field 키워드
  • 접근자 가시성

클래스 초기화 : 주 생성자, 초기화 블록

클래스 이름 뒤에 괄호로 둘러싸인 코드가 주 생성자이다.

1
class User(val nickname: String)

같은 목적을 이룰 수 있는 다은 형태의 코드를 보자.

1
2
3
4
5
6
7
class User constructor(_nickname: String) {
val nickname: String

init {
nickname = _nickname // _ : 프로퍼티와 생성자 파라미터를 구분하기 위해 사용
}
}

constructor 키워드는, 주 생성자나 부 생성자를 정의할 때 사용한다.
init 키워드는, 초기화 블록을 시작한다. 초기화 블록은, 클래스의 객체가 만들어질 때 실행된다.

위 코드에서,

  1. nickname 프로퍼티를 초기화 하는 코드를, nickname 프로퍼티 선언에 포함 가능
  2. 주 생성자 앞에 다른 annotation 이나 가시성 변경자 없다면, constructor 키워드 생략 가능
Read more