함수/클래스/객체/인터페이스
Begin Kotlin
코틀린?
타입 추론을 지원하는
정적 타입 지정 언어소스 코드의 정확성과 성능을 보장
소스코드를 간결하게 유지
객체지향과함수형 프로그래밍스타일을 모두 지원일급 시민 함수를 사용해 수준 높은 추상화가 가능
불변 값 지원을 통해 다중 스레드 애플리케이션 개발과 테스트를더 쉽게 가능
서버 애플리케이션 개발에 활용 가능
기존 자바 프레임워크를 완벽하게 지원
HTML 생성기나 영속화등의 일반적인 작업을 위한 새로운 도구를 제공
실용적이며 안전하고, 간결하며 좋은 상호 운용성
NPE 같이 흔히 발생하는 오류를 방지
읽기 쉽고 간결한 코드를 지원
자바와 아무런 제약 없이 통합
코틀린의 컴파일러(Kotlin Compiler)
코틀린 컴파일러는 JVM에서 실행될 수 있는 바이트코드가 포함된 클래스 파일을 생성

코틀린은 자바 컴파일러가 아닌 코틀린 컴파일러에 의해 컴파일되므로 자바를 사용할 때와 다른 부분이 존재
ex. 코틀린에서는 모든 예외를 언체크 예외로 인식
기초
함수 선언 →
fun파라미터 이름 뒤에 타입 →
args: Array<String>함수를 최상위수준에정의 가능클래스 안에 함수를 넣어야 할 필요가 없음
배열도 일반적인 클래스
System.out.println →
println줄 끝에 세미콜론(;) 없이 작성
함수
변수
코틀린에서는 보통 타입 지정을 생략
기본적으로는 모든 변수를 val 키워드를 사용해 불변 변수로 선언하고, 나중에 꼭 필요할 때에만 var로 변경
변경 가능한 변수와 변경 불가능한 변수
val(=value): 변경 불가능한(immutable) 참조를 저장하는 변수 (like. java final)
var(=variable): 변경 가능한(mutable) 참조 (like. java 일반 변수)
문자열 템플릿
문자열 리터럴의 필요한 곳에 변수를 넣되 변수 앞에 $를 추가
$ 문자를 문자열에 넣고 싶으면 println("$x")와 같이 \를 사용해 $를 이스케이프
클래스와 프로퍼티
코틀린의 기본 가시성은 public
코틀린 프로퍼티는 자바의 필드와 접근자 메소드를 완전히 대신
코틀린에서는 클래스 임포트와 함수 임포트에 차이가 없으며, 모든 선언을 import 키워드로 가져올 수 있음
enum & when
when은 자바의 switch를 대치하되 훨씬 더 강력
enum
enum 클래스 안에도 프러퍼티나 메소드 정의 가능
when 으로 enum 다루기
스마트 캐스트: 타입 검사와 타입 캐스트를 조합
코틀린에서는 is를 사용해 변수 타입을 검사 (like. java instanceof)
다중 if → when
Iteration (while & loop)
수에 대한 이터레이션
in으로 컬렉션이나 범위의 원소 검사
in으로 어떤 값이 범위에 속하는지 검사
!in을 사용하면 어떤 값이 범위에 속하지 않는지 검사
예외처리
함수는 정상적으로 종료할 수 있지만 오류가 발생하면 예외를 던질 수 있음
단, 함수가 던질 수 있는 예외를 선언하지 않아도 된다
try 식으로 사용
try 키워드는 if, when 과 마찬가지로 식이다.
따라서 try의 값을 변수에 대입 가능
함수 정의와 호출
컬렉션 만들기
확장 함수와 확장 프로퍼티
메소드를 다른 클래스에 추가
확장 함수
어떤 클래스의 멤버 메소드인 것처럼 호출할 수 있지만 그 클래스의 밖에 선언된 함수
확장 함수를 만들려면 추가하려는 함수 이름 앞에 그 함수가 확장할 클래스의 이름을 덧붙이자
확장 함수는 오버라이드할 수 없음
임포트와 확장함수
확장 함수를 사용하기 위해서는 그 함수를 다른 클래스나 함수와 마찬가지로 임포트 필요
함수를 호출하기 쉽게 만들기
확장 프로퍼티
기존 클래스 객체에 대한 프로퍼티 형식의 구문으로 사용할 수 있는 API를 추가
상태를 저장할 적절한 방법이 없으므로 아무 상태도 가질 수 없음
계산한 값을 담을 장소가 전혀 없으므로 초기화 코드도 사용 불가
가변 인자 함수
메소드를 호출할 때 원하는 개수만큼 값을 인자로 넘기면 자바 컴파일러가 배열에 그 값들을 넣어주는 기능
자바는 타입 뒤에 ...를 붙이지만, 코틀린은 파라미터 앞에
varag변경자를 붙인다.
이미 배열에 들어있는 원소를 가변 길이 인자로 넘길 때
자바에서는 배열을 그냥 넘기면 되지만,
코틀린에서는 배열을 명시적으로 풀어서
배열의 각 원소가 인자로 전달되게 해야 한다.기술적으로는
스프레드(spread) 연산자가 이러한 작업을 수행
값의 쌍 다루기 (중위호출, 구조 분해 선언)
맵을 만들려면
mapOf함수를 사용
중위 호출이라는 특별한 방식으로to라는 일반 메소드를 호출중위 호출 시에는 수신 객체와 유일한 메소드 인자 사이에 메소드 이름을 넣는다
메소드를 중위 호출에 사용하도록 허용하고 싶을 경우 infix 변경자를 메소드 선언 앞에 추가
이러한 기능을 구조 분해 선언이라고 부른다.
Pair 인스턴스 외 다른 객체에도 구조 분해 적용 가능
ex) key, value 두 변수를 맵의 원소를 사용해 초기화
문자열과 정규식
문자열 나누기
split 함수에 전달하는 값의 타입에 따라 정규식이나 일반 텍스트 중 어느 것으로 문자열을 분리하는지 쉽게 알 수 있다.
간단한 경우에는 꼭 정규식을 쓸 필요가 없다.
split 확장 함수를 오버로딩한 버전 중에는 구분 문자열을 하나 이상 인자로 받는 함수가 있다.
3중 따옴표 문자열
역슬래시()를 포함한 어떤 문자도 이스케이프 불필요
로컬 함수와 확장
함수에서 추출한 함수를 원 함수 내부에 중첩시킬 수 있다.
문법적인 부가 비용을 들이지 않고도 깔끔하게 코드를 조직 가능
로컬 함수와 확장으로 코드를 다듬는 과정
클래스, 객체, 인터페이스
코틀린과 자바의 클래스, 인터페이스 개념은 약간 다르다.
인터페이스에 프로퍼티 선언이 들어갈 수 있음
기본적으로 final, public
중첩 클래스는 기본적으로는 내부 클래스가 아니므로 외부 클래스에 대한 참조가 없음
클래스를 data로 선언하면 컴파일러가 일부 표준 메소드를 생성
위임(delegation)을 사용하면 위임을 처리하기 위한 준비 메소드를 직접 작성할 필요가 없음
코틀린 인터페이스
추상 메소드뿐 아니라 구현이 있는 메소드도 정의 가능
클래스 이름 뒤에 콜론(:)을 붙이고 인터페이스와 클래스 이름을 적는 것으로 클래스 확장과 인터페이스 구현을 모두 처리
인터페이스 메소드도 디폴트 구현을 제공
자바에서 메소드 앞에 default를 붙이는 것과 달리, 그냥 메소드 본문을 메소드 시그니처 뒤에 추가
다중 인터페이스 상속 관계에서 동일한 메소드가 구현되어 있을 경우
중복된 상위 메소드는 하위 클래스에서 반드시 구현되어야 한다는 컴파일 오류 발생
open, final, abstract 변경자
코틀린의 클래스와 메소드는 기본적으로
final
특정 클래스의 상속을 허용하려면 클래스 앞에 open 변경자를 붙여야 한다.
오버라이드를 허용하고 싶은 메소드나 프러퍼티의 앞에도 open 변경자를 붙여야 한다.
오버라이드하는 메소드의 구현을 하위 클래스에서 오버라이드하지 못하게 금지하려면 final 명시
final이 없는override메소드나 프로퍼티는 기본적으로 open
자바처럼 코틀린에서도 클래스를 abstract 선언 가능
abstract 선언 추상 클래스는 인스턴스화 불가
따라서 추상 멤버 앞에 open 변경자를 명시할 필요가 없음
인터페이스 멤버의 경우 final, open, abstract를 사용하지 않는다.
인터페이스 멤버는 항상 열려 있으며 final로 변경 불가
인터페이스 멤버에게 본문이 없으면 자동으로 추상 멤버가 되지만,
멤버 선언 앞에 abstract 키워드를 덧붙일 필요가 없음
클래스 내에서 상속 제어 변경자의 의미
final
오버라이드 불가
클래스 멤버에 기본적으로 적용
open
오버라이드 가능
명시적으로 선언 필요
abstract
오버라이드 필수
추상 클래스에서만 사용 가능, 추상 멤버는 구현 불가
override
슈퍼클래스나 인터페이스의 멤버를 오버라이드
오버라이드된 멤버는 final 표시가 없다면 기본적으로 open 상태
가시성 변경자: 기본적으로 공개 (internal)
패키지를 네임스페이스 관리 용도로만 사용하고 가시성 제어에 사용하지 않는다.
패키지 전용 가시성에 대한 대안으로
internal이라는 새로운 가시성 변경자를 도입“모듈 내부에서만 볼 수 있음"이라는 뜻
모듈은 한 번에 컴파일되는 코틀린 파일들을 의미
코틀린에서는 최상위 선언에 대해 private 가시성을 허용
그런 최상위 선언에는 클래스, 함수, 프로퍼티 등이 포함
비공개 가시성인 최상위 선언은 그 선언이 들어있는 파일 내부에서만 사용 가능
이 또한 하위 시스템의 자세한 구현 사항을 외부에 감추고 싶을 때 유용한 방법
public 함수인 giveSpeech 안에서 그보다 가시성이 더 낮은 타입인 internal TalkativeButton을 참조 불가
자바와 다르게 코틀린은 같은 패키지 안에서 protected 멤버에 접근할 수 없음
내부 클래스와 중첩된 클래스: 기본적으로 중첩 클래스 (inner)
자바와의 차이는 코틀린의 중첩 클래스는 명시적으로 요청하지 않는 한 바깥쪽 클래스 인스턴스에 대한 접근 권한이 없다
코틀린 중첩 클래스에 아무런 변경자가 붙지 않으면 자바 static 중첩 클래스와 동일
내부 클래스로 변경해서 바깥쪽 클래스에 대한 참조를 포함하게 만들고 싶다면
inner변경자 선언
코틀린에서 바깥쪽 클래스의 인스턴스를 가르키려면 내부 클래스 Inner 안에서 this@Outer라고 써야 한다.

https://livebook.manning.com/book/kotlin-in-action/chapter-4/83
봉인된 클래스: 클래스 계층 정의 시 계층 확장 제한 (sealed)
when 식에서 하위 클래스를 처리하면 편리하지만 else 분기를 반드시 넣어주어야 한다. 이 문제는
sealed클래스 변경자를 통해 상위 클래스를 상속한 하위 클래스 정의를 제한할 수 있다.
sealed 클래스의 하위 클래스를 정의할 때는 반드시 상위 클래스 안에 중첩시켜야 한다.
하위 클래스를 when 절에서 정의하지 않았을 경우 아래 컴파일 에러 발생
'when' expression must be exhaustive, add necessary 'is Other' branch or 'else' branch instead

https://livebook.manning.com/book/kotlin-in-action/chapter-4/95
클래스 초기화: 주 생성자와 초기화 블록
코틀린은 주(primary) 생성자와 부(secondary) 생성자를 구분
또한 초기화 블록(initializer block)을 통해 초기화 로직 추가 가능
주 생성자의 목적
생성자 파라미터를 지정
생성자 파라미터에 의해 초기화되는 프로퍼티를 정의
부 생성자: 상위 클래스를 다른 방식으로 초기화
일반적으로 코틀린에서는 생성자가 여럿 있는 경우가 자바보다 훨씬 적다.
생성자가 여럿 필요한 경우는
자바 상호운용성
인스턴스를 생성할 때 파라미터 목록이 다른 생성 방법이 여럿 존재하는 경우
인터페이스에 선언된 프로퍼티 구현
인터페이스는 아무 상태도 포함할 수 없으므로 상태를 저장할 필요가 있다면 인터페이스를 구현한
하위 클래스에서 상태 저장을 위한 프로퍼티 등을 만들어야 한다.
인터페이스에는 추상 프로퍼티뿐 아니라 게터와 세터가 있는 프로퍼티를 선언할 수도 있다.
이런 게터와 세터는 뒷받침하는 필드를 참조할 수 없다.
뒷받침하는 필드가 있다면 인터페이스에 상태를 추가하는 의미지만 인터페이스는 상태를 저장할 수 없다
하위 클래스는 추상 프로퍼티인 email을 반드시 오버라이드해야 한다.
반면 nickname은 오버라이드하지 않고 상속할 수 있다.
게터와 세터에서 뒷받침하는 필드에 접근
값을 저장하는 동시에 로직을 실행할 수 있게 하기 위해서는
접근자 안에서 프로퍼티를 뒷받침하는 필드에 접근할 수 있어야 한다.
프로퍼티에 저장된 값의 변경 이력을 로그에 남기려는 경우를 생각해 보면
변경 가능한 프로퍼티를 정의하되
세터에서 프로퍼티 값을 바꿀 때마다 약간의 코드를 추가로 실행해야 한다.
field 식별자를 통해 프로퍼티 접근자(게터와 세터) 안에서 프로퍼티의 데이터를 저장하는 데 쓰이는 뒷받침하는 필드를 참조할 수 있다.
접근자의 가시성 변경
접근자의 가시성은 기본적으로 프로퍼티의 가시성과 같다.
하지만 원할 경우 get이나 set 앞에 가시성 변경자를 추가해서 접근자의 가시성을 변경할 수 있다.
데이터 클래스: 모든 클래스가 정의해야 하는 메소드 자동 생성
data라는 변경자를 클래스 앞에 붙이면 필요한 메소드를 컴파일러가 자동으로 만들어준다.
자바에서 요구하는 모든 메소드(euqals, hashCode, toString)를 포함
데이터 클래스와 불변성: copy() 메소드
데이터 클래스 인스턴스를 불변 객체로 더 쉽게 활용할 수 있게 객체를 복사하면서 일부 프로퍼티를 바꿀 수 있게 해주는 copy 메소드를 제공
복사본은 원본과 다른 생명주기를 가지며, 복사를 하면서 일부 프로퍼티 값을 바꾸거나 복사본을 제거해도 프로그램에서 원본을 참조하는 다른 부분에 전혀 영향을 끼치지 않는다.
클래스 위임: by 키워드 사용
인터페이스를 구현할 때 by 키워드를 통해 그 인터페이스에 대한 구현을 다른 객체에 위임 중이라는 사실을 명시할 수있다.
object 키워드: 클래스 선언과 인스턴스 생성
객체 선언: 싱글턴을 쉽게 만들기
코틀린은 객체 선언 기능을 통해 싱글턴을 언어에서 기본 지원
객체 선언: 클래스 선언과 그 클래스에 속한 단일 인스턴스의 선언을 합친 선언
객체 선언도 클래스나 인터페이스를 상속할 수 있다.
프레임워크를 사용하기 위해 특정 인터페이스를 구현해야 하는데, 그 구현 내부에 다른 상태가 필요하지 않은 경우에 이런 기능이 유용
클래스 안에서 객체를 선언할 수도 있다. 이런 객체도 인스턴스는 단 하나뿐!
동반 객체: 팩토리 메소드와 정적 멤버가 들어갈 장소
코틀린 언어는 자바 static 키워드를 지원하지 않는다.
그 대신 패키지 수준의 최상위 함수와 객체 선언을 활용할 수 있다.
클래스 안에 정의된 객체 중 하나에 companion 라는 특별한 표시를 붙이면 그 클래스의 동반 객체로 만들 수 있다.
동반 객체의 프로퍼티나 메소드에 접근하려면 그 동반 객체가 정의된 클래스 이름을 사용
동반 객체가 private 생성자를 호출하기 좋은 위치
동반 객체는 자신을 둘러싼 클래스의 모든 private 멤버에 접근할 수 있다.
동반 객체를 일반 객체처럼 사용
동반 객체는 클래스 안에 정의된 일반 객체
따라서 동반 객체에 이름을 붙이거나, 동반 객체가 인터페이스를 상속하거나, 동반 객체 안에 확장 함수와 프로퍼티를 정의할 수 있다.
동반 객체에서 인터페이스 구현
다른 객체 선언과 마찬가지로 동반 객체도 인터페이스를 구현할 수 있다.
객체 식: 무명 내부 클래스를 다른 방식으로 작성
무명 객체(anonymous object)를 정의할 때도 object 키워드를 사용
무명 객체는 자바의 무명 내부 클래스를 대신
한 인터페이스만 구현하거나 한 클래스만 확장할 수 있는 자바의 무명 내부 클래스와 달리
코틀린 무명 클래스는 여러 인터페이스를 구현하거나 클래스를 확장하면서 인터페이스를 구현할 수 있다.
자바의 무명 클래스와 같이 객체 식 안의 코드는 그 식이 포함된 함수의 변수에 접근할 수 있다.
하지만 자바와 달리 final이 아닌 변수도 객체 식 안에서 사용할 수 있다.
Last updated