상위클래스 Expr 숫자를 표현하는 Num 덧셈 연산을 표현하는 Sum 위 2개의 하위 클래스가 있다. when 식에서 이 모든 하위클래스를 처리하면 편리하다. interface Expr class Num(val value: Int) : Expr class Sum(val left: Expr, val right: Expr) : Expr fun eval(e: Expr) : Int = when (e) { is Num -> e.value is Sum -> eval(e.right) + eval(e.left) else -> // else 분기가 반드시 있어야한다. throw IllegalArgumentException("Unknown expression") } when을 사용해서 Expr 타입의 값을 검사할때 꼭 ..
중첩클래스 자바처럼 코틀린에서도 클래스 안에 다른 클래스를 선언할 수 있다. 클래스 안에 다른 클래스를 선언하면 도우미 클래스를 캡슐화하거나 코드 정의를 그 코드를 사용하는 곳에 둘때 유용하다. 자바와의 차이점 코틀린의 중첩 클래스는 명시적으로 요청하지않는 한 바깥쪽 클래스 인스턴스에 대한 접근 권한이 없다는 점이다. JAVA ButtonJava.java public class ButtonJava implements View { @NotNull @Override public State getCurrentState() { return new ButtonState(); } @Override public void restoreState(@NotNull State state) { } /** * 중첩 클래스 */..
코틀린에서의 final 자바에서는 final 로 명시적으로 상속을 금지하지 않는 모든 클래스를 다른 클래스가 상속할 수 있다. 이렇게 기본적으로 상속이 가능하면 편리한 경우도 많지만 문제가 생기는 경우도 많다. 취약한 기반 클래스(fragile base class) 하위 클래스가 기반 클래스에 대해 가졌던 가정이 기반 클래스를 변경함으로써 깨져버린 경우에 생긴다. 어떤 클래스가 자신을 상속하는 방법에 대해 정확한 규칙을 제공하지 않는다면 그 클래스의 클라이언트는 기반 클래스를 작성한 사람의 의도와 다른 방식으로 메서드를 오버라이드할 위험이 있다. 모든 하위 클래스를 분석하는 것은 불가능 하므로 기반 클래스를 변경하는 경우 하위 클래스의 동작이 예키지않게 바뀔 수도 있다는 면에서 기반 클래스는 취약하다. ..
코틀린 인터페이스 코틀린 인터페이스는 자바8 인터페이스와 비슷하다. 코틀린 인터페이스 안에는 추상 메서드뿐 아니라 구현이 있는 메서드도 정의할 수 있다. 다만 인터페이스에는 아무런 상태(필드)도 들어갈 수 없다. 코틀린에서 클래스는 class로 정의하지만 인터페이스는 interface를 사용한다. 예제 Clickable.kt interface Clickable { fun click() fun showOff() = println("I'm clicked") // default 구현이 있는 메서드 } 인터페이스 메서드도 디폴트 구현을 제공할 수 있다. 자바에서는 default를 메서드 앞에 붙여야하지만, 코틀린에서는 특별히 쓸 필요가 없다. 그냥 메서드 본문을 메서드 시그니처 뒤에 추가하면 된다. 이 인터페이..
로컬함수 확장 예제 : 데이터베이스에 사용자 객체를 저장하기전, 각 필드의 validation 을 검증하는 로직 1단계. 코드 중복을 보여주는 예제 class User(val id: Int, val name: String, val address: String) fun saveUser(user: User) { if (user.name.isEmpty()) { throw IllegalArgumentException ( "Can't save User ${user.id}: empty Name" ) } if (user.address.isEmpty()) { throw IllegalArgumentException ( "Can't save User ${user.id}: empty Address" ) } } fun mai..
코틀린 문자열 (String) 코틀린 문자열은 자바 문자열과 같다. 코틀린 코드가 만들어낸 문자열을 아무 자바 메서드에 넘겨도 되며, 자바 코드에서 받은 문자열을 아무 코틀린 표준 라이브러리 함수에 전달해도 문제가 없다. 문자열 나누기 1) String의 split 메서드 자바에서 split 메서드를 보자. "12.345-6.A".split(".") 위 코드의 결과는 [12, 345-6, A]가 아닌 빈 문자열이다. 자바의 split의 구분 문자열은 실제로 정규식이며, 마침표(.)는 모든 문자를 나타내는 정규식으로 해석된다. 코틀린에서는 split 확장 함수를 제공함으로써 혼동을 야기하는 메서드를 감춘다. fun main() { println("12.345-6.A".split(".")) // [12, 3..
가변 길이 인자 (vararg) 가변 길이 인자는 메서드를 호출할때 원하는 개수만큼 값을 인자로 넘기면 자바 컴파일러가 배열에 그 값들을 넣어주는 기능이다. 코틀린의 가변 길이 인자도 자바와 비슷하다. 타입 뒤에 ...를 붙이는 대신, 코틀린에서는 파라미터 앞에 vararg 변경자를 붙인다. 코틀린은 배열을 명시적으로 풀어서 배열의 각 원소가 인자로 전달되게 해야한다. 스프레드 (spread) 연산자가 그런 작업을 해준다. (배열 앞에 *를 붙인다.) 예제 리스트를 생성하는 함수를 호출할때 원하는 만큼 많이 원소를 전달할 수 있다. fun main() { val list = listOf(2, 3, 5, 7, 11) } listOf 메서드 listOf(vararg elements: T) public fun..
확장함수 기존 자바 API를 재작성하지 않고도 자바 코드를 변환할 수 있어야한다. 어떤 클래스의 멤버 메서드인것처럼 호출할 수 있지만 그 클래스의 밖에 선언된 함수다. 확장함수를 만들려면 추가하려는 함수 이름 앞에 그 함수가 확장할 클래스의 이름을 덧붙이기만 하면 된다. - 객체 타입 : 클래스 이름 - 수신 객체 : 확장 함수가 호출되는 대상이 되는 값 확장 함수가 캡슐화를 깨지는 않는다. 클래스 안에서 정의한 메서드와 달리 확장 함수 안에서는 클래스 내부에서만 사용할 수 있는 비공개(private) 멤버나 보호된(protected) 멤버를 사용할 수 없다. 클래스의 멤버 메서드와 확장 함수를 모두 '메서드'라고 부르자. 클라이언트에게 자신이 호출하려는 메서드가 확장함수인지 멤버 메서드인지의 여부는 중..
코틀린 함수 이름 명시 val list = listOf(1, 2, 3) println(list) // [1, 2, 3] 만약 (1; 2; 3) 처럼 원소 사이를 세미콜론(;)으로 구분하고 괄호로 리스트를 둘러싸고싶다면? (1; 2; 3) 코틀린은 이런 요구 사항을 처리할 수 있는 함수가 표준 라이브러리에 이미 들어있다. 코틀린이 지원하는 기능을 사용하지 않고 직접 구현해보자. 직접 구현하기 /* 이 함수는 어떤 타입의 값을 원소로 하는 컬렉션이든 처리할 수 있다. */ fun joinToString( collection: Collection, separator: String, prefix: String, postfix: String ): String { val result = StringBuilder(p..
코틀린에서의 컬렉션 코틀린은 자신만의 컬렉션 기능을 제공하지 않고, 자바 컬렉션을 활용한다. 코틀린에서는 변경 가능한(mutable) 컬렉션과 변경 불가능한(immutable) 컬렉션으로 구분하여 사용한다. Set 데이터 순서가 없으며, 중복이 불가능하다. 기본적으로 변경 불가능(immutable)하며, mutableSetOf(), hashSetOf(), linkedSetOf(), sortedSetOf()로 변경 가능한 Set 생성이 가능하다. fun main() { val set = hashSetOf(1, 7, 53) // 객체가 어떤 클래스에 속하는지 추측하기 println(set.javaClass) // Java의 getClass() } Map key와 value가 한 쌍의 데이터로 이루어진 컬렉션..
throw 예외처리 코틀린의 예외 처리는 자바나 다른 언어의 예외 처리와 비슷하다. 코틀린에서의 throw 예외처리 특징을 알아보자. new 연산자를 사용하지 않아도 된다. fun main() { val i = 50 if (i !in 0.. 100) { // new 연산자를 사용하지 않아도 된다. throw IllegalArgumentException("exception : $i") } val percentage = exam(50) println(percentage) } throw는 식이다. 다른 식에 포함될 수 있다. fun main() { val percentage = exam(101) println(percentage) } fun exam(i: Int) { val percentage = if (i ..
while, do~while Kotlin에서 while, do~while문 사용은 Java와 동일하다. 새로 추가된 기능도 없다. for루프 코틀린에는 자바의 for에 해당하는 요소가 없다. 이런 루프의 가장 흔한 용례인 초기값, 증가값, 최종값을 사용한 루프를 대신하기 위해 코틀린에서는 범위(range)를 사용한다. 범위는 기본저긍로 두 값으로 이뤄진 구간이다. 보통은 그 두 값은 정수 등의 숫자 타입의 값이며, .. 연산자로 시작 값과 끝 값을 연결해서 범위를 만든다. // 양 끝을 포함하는 구간 : 10까지 포함 val oneToTen = 1..10 어떤 범위에 속한 값을 일정한 순서로 이터레이션하는 경우를 수열(progression)이라고 부른다. 예제 fun fizzBuzz(i: Int) = w..