[커니의 Kotlin] Chap1.1
코틀린을 공부하면 정리하는 포스팅.
# 코틀린의 특징
간결한 문법
- 문장 끝에 세미 콜론(;)을 넣지 않는다.
- new 키워드를 사용하지 않고 객체를 생성한다.
- 타입 추론을 지원하므로 타입을 명시하지 않아도 된다.
널 안정성
- 널 값의 허용 여부를 명확히 구분하며 컴파일 단계에서 검사한다.
1 | var a : String? = null |
가변/불변 구분
- val(값) : 값을 한번 할당하고 나면 그 후에 값을 변경할 수 없는 변수. 자바의 final 변수와 유사.
- var(변수) : 할당된 값을 자유자재로 바꿀 수 있는 변수.
- 변수의 가변/불변과 유사하게 컬렉션 자료형에 대해서도 가변/불변 여부를 구분한다.
- 객체에 할당된 값이 아닌 컬렉션 내에 포함된 자료들을 추가,삭제할 수 있는지 여부를 구분한다.
- 불변의 경우 삽입,삭제,수정을 위한 함수가 없다.
1 | var a : String = "a" |
람다표현식 지원
- 람다 표현식을 기본으로 제공.
1 | view.setOnClickListener{ |
스트림API 지원
- 코틀린 표준 라이브러리를 통해 컬렉션 내 자료를 다루는 데 유용한 스트림 API를 지원한다.
완벽한 자바 호환성
- 자바에서 코틀린을 사용할 수 있고, 반대로 코틀린에서 자바 코드를 사용할 수 있다.
# 주요 문법
값 및 변수 선언
1 | var a : String = "a" |
함수 선언
- Unit은 자바의 void와 유사하다. 반환 타입이 없음을 의미한다. 생략 가능하다.
1 | fun sum(a : Int, b : Int) : Int{ |
클래스 및 인터페이스 선언
1 | // Class |
조건문
1 | // if-else |
반복문
- for-each만은 지원한다.
- while, do-while문은 자바와 사용법이 똑같다.
1 | val items = listOf("a","b") |
# 기본 자료형
- 코틀린은 모든 타입을 객체로 표현.
- 원시 타입과 래퍼 클래스를 구분하지 않는다.
원시 타입을 모두 객체로 처리하면 비효율적일 수 있다.
코틀린에서는 코드를 작성하는 시점에 원시 타입과 래퍼를 구분하지 않지만, 컴파일 단계를 거치면서 가장 효율적인 타입으로 변환된다.
- 값이나 변수의 타입으로 사용되는 경우 : 원시 타입으로 변환
- 컬렉션의 타입 인자로 사용되는 경우 : 래퍼로 변환
1 | var a : Int = ... |
숫자
- 숫자를 표현하는 모든 자료형은 Number 클래스를 상속한다.
- 현재 숫자에 해당하는 문자를 반환하는 toChar() 함수를 추가로 제공한다.
- Long 타입은 혼동 방지를 위해 대문자 리터럴 표기만 지원한다.
문자
- 자바에서는 문자에 해당하는 아스키 코드를 char에 숫자 형태로 대입할 수 있었지만, 코틀린에서는 문자만 대입할 수 있으며, 숫자를 대입할 경우 컴파일 에러가 발생한다.
- toChar()를 사용해서 다른 자료형의 값을 문자 자료형에 대입한다.
1 | val code : Int = 65 |
논리
- 자바와 동일하게 사용하며, Boolean을 사용한다.
문자열
- 자바와 거의 동일하게 사용된다.
- 문자열의 특정 문자에 접근하기 위해 charAt() 대신 get() 혹은 대괄호([])와 인덱스를 사용해서 접근한다.
- 문자열 템플릿을 사용해 템플릿 문자열 내에 직접 인자를 대입한다.
- 인자로 값이나 변수 대신 표현식을 넣을 경우 표현식을 중괄호로 구분하면 된다.
1 | val foo : String = "Victory" |
배열
- 배열은 타입 인자를 갖는 Array 클래스로 표현한다.
- arrayOf()는 코틀린 표준 라이브러리에 포함되어 있으며, 입력받은 인자로 구성된 배열을 생성.
- 자바의 원시 타입은 코틀린 배열 클래스의 타입 인자로 사용할 수 없다.
- 자바 원시 타입을 인자로 갖는 배열을 표현하기 위해서 각 원시 타입에 대응하는 특수한 클래스를 제공한다.
1 | val words : Array<String> = arrayOf("a","b","c","d") |
- 가변 인자에 배열을 전달하는 경우에 스프레드 연산자(*)를 사용한다.
1 | fun go(varag args : String){ |
# 컬렉션
- JVM을 기반으로 하는 코틀린에서 컬렉션은 자바에서 제공하는 클래스들을 그대로 사용한다.
- 이때, 타입 별칭을 사용해 컬렉션 내 다른 클래스와의 일관성을 유지한다.
- 컬렉션 내 자료의 수정 가능 여부에 따라 컬렉션의 종류를 구분하며 인터페이스를 통해 사용 가능한 함수를 제한하는 방식으로 구현되어 있다.
Collection, List 인터페이스에는 자료를 조회하는 함수만 포함되어 있으므로 자료가 할당되면 수정이 불가능하다. 그 대신, 각 인터페이스를 상속한 MutableCollection, MutableList 인터페이스에 자료를 수정하는 함수가 포함되어 있다.
Set, Map도 동일한 규칙이 지정되며 아래 표와 같다.
자료구조 | 자료 수정 불가 | 자료 수정 가능 |
---|---|---|
List | kotlin.collections.List | kotlin.collections.MutableList |
Map | kotlin.collections.Map | kotlin.collections.MutableMap |
Set | kotlin.collections.Set | kotlin.collections.MutableSet |
- 다음은 컬렉션을 쉽게 생성하는 함수를 나타낸다.
- listOf, setOf, mapOf는 자료의 수정이 불가능하다.(불변)
함수명 | 자료 수정 가능 여부 | 반환 타입(실제 타입) |
---|---|---|
listOf() | X | kotlin.collections.List |
arrayListOf() | O | kotlin.collections.ArrayList(java.util.ArrayList) |
SetOf() | X | kotlin.collections.Set |
hashSetOf() | O | kotlin.collections.HashSet(java.util.HashSet) |
linkedSetOf() | O | kotlin.collections.LinkedHashSet(java.util.LinkedHashSet) |
sortedSetOf() | O | kotlin.collections.TreeSet(java.util.TreeSet) |
mapOf() | X | kotlin.collections.Map |
hashMapOf() | O | kotlin.collections.HashMap(java.util.HashMap) |
linkedMapOf() | O | kotlin.collections.HashMap(java.util.LinkedHashMap) |
sortedMapOf() | O | kotlin.collections.LinkedHashMap(java.util.SortedMap) |
- 배열의 특정 원소에 접근하는 방법과 동일하게 컬렉션 내 항목에 접근할 수 있다.
1 | val immutableList : List<String> = listOf("a","b") |
- 맵은 숫자 대신 키 값을 넣어 항목에 접근할 수 있다.
1 | val immutableMap : Map<String, Int> = mapOf(Pair("A",65), Pair("B",66)) |
# 클래스 및 인터페이스
클래스 및 인터페이스 선언
- 클래스 및 인터페이스를 선언하는 방식은 자바와 거의 유사하다.
- 접근 제한자를 지정하지 않는 경우 기본은 public이다.
- 선언된 내용이 없으면 클래스와 인터페이스는 몸체만 선언할 수 있다.
- new를 사용하지 않고 인스턴스를 생성한다.
1 | class A{ |
- 추상 클래스는 자바와 동일한 선언 방법이지만, 인스턴스를 생성하는 형태가 다르다.
- 인터페이스를 선언하거나, 인터페이스의 인스턴스를 만드는 방법은 추상 클래스와 매우 유사하다.
- 추상 클래스에서는 인스턴스를 생성 시 생성자를 사용하지만, 생성자가 없는 인터페이스는 인스턴스 이름만 사용한다.
1 | // 추상 클래스의 선언. |
프로퍼티
- 프로퍼티는 자료를 저장할 수 있는 필드와 이에 상응하는 getter/setter 메소드를 함께 제공하며, 자바의 필드와 유사한 형태로 선언한다.
- 클래스의 멤버로 사용하는 프로퍼티는 초기값을 명시적으로 지정해야 한다. 그렇지 않을 경우 컴파일 에러 발생.
- 단, 생성자에서 프로퍼티의 값을 할당한다면 선언 시 값을 할당하지 않아도 된다.
- 프로퍼티 선언 시점이나 생성자 호출 시점에 값을 할당할 수 없는 경우에는 lateinit 키워드를 사용하여 프로퍼티의 값이 나중에 할당될 것임을 명시한다.
- lateinit 키워드는 var 프로퍼티에만 사용 가능하다.
- 반드시 초기화 작업을 해야 한다.
- 프로퍼티에 초기값을 할당하는 시점에서 해당 프로퍼티의 타입을 추론할 수 있다면 타입 선언 생략 가능.
1 | class Person{ |
- lateinit 키워드를 사용했는데 초기화를 하지 않으면 Uninitialized PropertyAccessException 예외가 발생하한다. 컴파일 단계에서는 확인이 불가능하므로
lateinit
키워드를 사용할 경우 반드시 초기화 여부를 확인하는 것이 좋다.
1 | lateinit var name : String |
접근 제한자
- 제한자가 없으면 public으로 간주한다.
- internal 접근 제한자를 제공한다.
- 단순히 같은 패키지에 있으면 접근이 가능했던 자바의 패키지 단위 제한과 달리 internal 접근 제한자는 동일 모듈 내에 있는 클래스들로의 접근을 제한한다.
- 외부 모듈에서는 이 접근 제한자로 선언된 요소에 접근할 수 없다.
- 제한하는 모듈의 범위
- IntelliJ IDEA 모듈
- Maven / Gradle 프로젝트
- 하나의 Ant 태스크 내에서 함께 컴파일 되는 파일들.