4. Why What Kotlin
Kotlin의 첫인상
Sealed class Alcohol { . . . (1) (Sealed class)
data class Wine(val grapeType: String, val price: Int): Alcohol()
data class Soju(val city: String? = ‘Seoul’, val proof: Float): Alcohol() . . . (2) (data class, ?, default param)
}
fun main (args: Array<String>) {
val alcohol: Alcohol = Soju(city = “Daejeon’, proof = 12.0f) . . . (3) (val or var, param naming)
val msg = when(alcohol) { . . . (4) (when)
is Alcohol.Wine -> ‘이 와인은 ${alcohol.grapeType}으로 만들어졌으며, 가격은
${alcohol.price}입니다.’ . . . (5) (String formatting)
is Alcohol.Soju -> ‘이 소주는 ${alcohol.city} 소주고, ${alcohol.proof}도 입니다.’
}
println(‘이 술에 대한 소개 : $msg’)
}
5. Why What Kotlin
사용될 수 있는 영역
- Backend
- Android (공식 언어)
- Desktop App (TornadoFX, JavaFX)
- Web app & NodeJS (Javascript to Kotlin Compile)
6. Why What Kotlin
특징 (1) . . 정적 타입
- Kotlin은 정적 타입 지정 언어
- Compile Time에 타입을 알 수 있다.
- 타입 안정성을 갖음
- 문맥으로부터 변수 타입을 자동 유추하여 타입 선언 생략 가능 (타입 추론)
성능 신뢰성
유지
보수성
도구
지원
7. Why What Kotlin
특징 (2) . . FP
간략한 FP의 특징
1. 일급 시민 함수 : 함수를 값처럼 활용
2. 불변성 : 상태를 갖고 있지 않는 불변 객체를 사용
3. Side Effect 없음 : F(x1) = y1, F(x2) = y2, pure function
8. Why What Kotlin
특징 (2) . . FP
그래서 왜 좋은가? (더 자세하게는 다음주 FP 시간에)
1. 명령형(Imperative)에 비해 간결하다
2. 다중 스레드에서 safe하다 (pure function, immutability)
3. 테스트 하기 쉽다(No Side-Effect)
10. Why What Kotlin
실용적인 Kotlin
- 연구를 위한 언어가 아니다
- 여러가지 실제 문제를 해결하기 위해 다른 언어의 성공적인 해법과 기능에 의존
- 특정 Programming 스타일이나 패러다임을 강제하지 않음
- 강력한 IDE의 언어 지원
11. Why What Kotlin
간결한 Kotlin
- 코드가 더 간결할수록 내용 파악이 쉽다
- 개발자는 코드를 작성하는 것보다 기존 코드 읽는 시간이 더 많다
- 부수적인 요소를 줄이기 위한 언어적 차원의 지원
- 더 다양한 함수를 위한 Extension의 지원
12. Why What Kotlin
안전한 Kotlin
- 안전성 <-> 생산성은 Trade Off 관계
- 안전성을 위해서는 더 많은 정보를 추가하여야 한다
- 하지만 코틀린은 2마리 토끼를 모두 잡는데에 집중한다
- JVM의 사용(메모리 안전성)
- Null Safety
- Type 검사 & Auto Casting
13. Why What Kotlin
상호운용적인 Kotlin
- Java를 Inherit하거나 Implement할 수 있다
- 기존 자바 라이브러리에 추가 기능이 필요하면 Extension으로 활용
- 라이브러리 클래스 또한 기존 Java를 활용한다
- Java와는 거의 100% 호환이 된다고 보면 됨
15. Kotlin Basic
Function : 문(Statement) & 식(Expression)
- 식(Expression) : 값을 만들어 내고 다른 식의 하위 요소로 계산에 참여 가능
- 문(Statement) : 자신을 둘러싸고 있는 블록의 최상위 요소, 값을 만들지 않음
- 코틀린은 loop를 제외한 제어 구조가 식이다. 반면, Java는 문이다.
Kotlin
fun max (a: Int, b: Int): Int = if (a > b) a else b
Java
int max(int a, int b) {
if ( a > b)
return a;
else
return b;
}
16. Kotlin Basic
Variable : val & var
- val (Value, 값)
- immutable 참조 : 초기화 후 재대입 불가
- Java : final 변수
- var (Variable, 변수)
- mutable 참조 : 변수 값 바뀔 수 있음
- Java : 일반 변수
17. Kotlin Basic
String Template
- Java Style : “Hello’ + name + ‘!’
- Kotlin : ‘Hello $name!’
- 복잡한 식도 가능(중괄호) : ‘Hello, ${if(a > b) ‘A’ else ‘B’}!”
- 컴파일 후의 코드는 StringBuilder, append( )를 사용하여 바이트 코드 생성
18. Kotlin Basic
Property
- Java Style
- private String name
- Alcohol(String name, int price)
- private String getName( )
Kotlin
class Alcohol (
val name: String,
var price: Int
)
19. Kotlin Basic
Property
- Java to Kotlin
- alcohol.setName(“Soju’) -> alcohol.name = ‘soju’ (Setter)
- String name = alcohol.getName( ) -> val name = alcohol.name (Getter)
20. Kotlin Basic
Enum & When
- Java와 다르게 enum에 프로퍼티나 메소드 정의가 가능하다
Kotlin
enum class Color(val r: Int, val g: Int, val b: Int) {
RED (255, 0, 0),
GREEN (0, 255, 0),
BLUE (0, 0, 255);
fun rgb( ) = (r * 256 + g) * 256 + b // Color.BLUE.rgb( ) -> 255
}
21. Kotlin Basic
Enum & When
- When : Switch문과 비슷하게 사용되는 식(Expression)
- break가 필요 없다
Kotlin
fun colorLowerCase(color: Color) = when(red) {
Color.RED -> “red’
Color.GREEN -> ‘green’
Color.BLUE -> ‘blue’
}
22. Kotlin Basic
Smart Cast
- is를 사용해 변수 타입을 검사한다
- Java에서는 instanceof로 검사 후 직접 캐스팅 해 주어야 되는데 코틀린에서는 컴파일러가
이를 대체 한다.
- 명시적인 캐스트는 as를 사용
23. Kotlin Basic
Smart Cast
Kotlin
Interface Base {
fun base(): String
}
Class Child: Base {
override fun base(): String = “Base’
fun child(): String = ‘Child’
}
Kotlin
fun main() {
val base: Base = Child()
if (base is Child)
println(base.child())
}
24. Kotlin Basic
loop
- 개인적으로 java보단 python과 비슷
- for ( i in 1 . . 100 )
- for ( i in 100 downTo 1 step 2 )
- for ( i in 1 until 100 )
- for ( (key, value) in map)
26. Function
이름 붙인 인자 & Default Parameter
- 초반에 설명한 것 처럼 연구 목적이 아닌 언어로의 성공적인 해법과 기능을 제공한다
- 파이썬에도 있음
- 이름 붙인 인자로 하여금 인자의 이름을 명시적 표기가 가능하다.
27. Function
이름 붙인 인자 & Default Parameter
- Java에는 Default Parameter가 없어서 telescoping constructor pattern을 쓴다
- Effective Java에 나옴 (이를 해결하기 위해 나온게 빌더 패턴)
Java
public Class(String a) // b, c는 기본값 쓰고싶음
public Class(String a, String b) // c는 기본값 쓰고 싶음
public Class(String a, String b, String c) // 기본값 안 쓰고 싶음
// 함수 오버로딩 상황에서도 이런 문제 똑같이 발생한다.
Kotlin
class Class(val a: String = ‘A’, val b: String = ‘B’, val c: String = ‘C’)
28. Function
최상위 함수
- Java에서는 utility function 위해서 private constructor를 갖는 static function
덩어리 클래스를 따로 만들어서 사용 (utils package안에 ..Util.Class 라는 클래스들)
- 예를 들어, Collections 클래스
- 하지만 그냥 Kotlin에서는 .kt안에 최상위 함수를 넣어다 쓰면 그만이다.
- 컴파일 시에는 클래스 안에 static으로 넣어준다.
29. Function
확장 함수
- Kotlin에서는 Java의 라이브러리 클래스들을 주로 사용한다. 근데, 해당 클래스에 필요한
기능을 추가하고 싶다면?
- 확장해야 된다.
- Kotlin에서는 그냥 간단히 확장함수를 선언하여 쓰면 된다.
Kotlin
fun String.lastChar( ) : Char = get(length - 1) // this.get인데 this 생략
println(“ABCDEFG’.lastChar( )) // A 출력
30. Function
가변 인자 함수
- 메소드를 호출 시 원하는 개수만큼 값을 인자로 넘기면 컴파일러가 배열에 그 값을 넣어준다.
- Kotlin에서는 vararg 변경자를 붙임
Kotlin
fun main ( args: Array<String>) {
val list = listOf(*args) // vararg 인자에 넣을때는 배열 앞에 Spread 연산자(*)를 붙여야 됨
}
31. Function
중위 호출, 구조 분해 선언
- Kotlin에서 map에 pair를 넣을때 1 to “one’과 같이 넣는다.
- 사실은 infix fun Any.to(other: Any) = Pair(this, other)
- 중위 호출을 한것 (infix를 붙이지 않은 1.to(“one”)과 같음
- 다시 Pair를 2개의 변수에 한번에 초기화 할 수 있다.
- val (number, name) = 1 to “one’
- 이를 구조 분해 선언이라 한다.
- for ( (index, value) in map) // 이게 구조 분해 선언
33. Class, Instance, Interface
Interface
- Java8과 같이 추상 메소드뿐 아니라 구현이 있는 메소드도 정의 가능하다
- 상속이나 구현이나 모두 : (colon)을 붙여 진행
- java와 달리 override 변경자를 무조건 붙여야 한다.
Kotlin
interface Clickable {
fun click()
fun show() = println(“I am clickable’) // default 메소드
}
class Button: Clickable {
override fun click() = print(‘click)
}
34. Class, Instance, Interface
기본적으로 final
- Java는 기본이 open이여서 default로 클래스 상속이 된다.
- ‘상속을 위한 설계와 문서를 갖추거나, 그럴 수 없다면 상속을 금지하라' (Effective Java)
- 하위 클래스에서 오버라이드 하게끔 의도한 클래스가 아니라면 모두 final로 하라는 말
- Kotlin은 기본이 final이고 상속을 하고 싶으면 open을 붙여야한다.
35. Class, Instance, Interface
가시성 변경자
- Java는 기본이 default다 (패키지 전용)
- 문제는 다른 모듈(외부)에서 패키지만 같다면 전부 사용이 가능하다.
- 그래서 나온게 Kotlin의 internal (같은 모듈 안에서만 가시성 제공)
- Public(기본 가시성), internal, protected, private 4개의 가시성을 제공한다.
36. Class, Instance, Interface
Sealed Class (클래스 계층 확장 제한)
- When절에서 is로 분기 시 반드시 else분기가 필요하다
- Sealed는 하위 클래스 정의를 제한한다.
Kotlin
sealed class Expr {
class Num(val value: Int) : Expr()
class Sum(val left: Expr, val right: Expr) : Expr()
}
when(expr) {
is Expr.Num -> . . .
is Expr.Sum -> . . .
} // Else가 없다.
37. Class, Instance, Interface
data class
- 메소드를 기계적으로 생성하는 작업을 보이지 않는 곳에서 해준다.(손이 덜 아프다)
- toString(), equals(), hashCode()를 전부 자동으로 만들어 준다.
- 데이터 클래스는 불변 클래스(val만 사용)이 되는 것을 권장하며 copy() 메소드 또한
제공한다.
- base 인스턴스의 특정 필드만 복사하여 다른 불변 인스턴스를 만들어 준다.
Kotlin
val ko = Client(‘고세원', 1)
println(ko.copy(name = ‘이원준”)) // Client(name = 이원준, id = 1)
38. Class, Instance, Interface
클래스 위임 : by
- 상속을 허용하지 않는 클래스에 새로운 동작을 추가해야 할 때가 있다.
- 이때 사용하는것이 데코레이터 패턴
- 근데 또 손아프다(준비 코드 다 만들어 줘야 된다)
Kotlin
class DelegatingCollection<T> : Collection<T> {
private val innerList = arrayListOf<T>()
override val size: Int get() = innerList.size
override fun isEmpty(): Boolean = innerList.isEmpty()
override fun contains(element: T): Boolean = innerList.contains(element)
}
39. Class, Instance, Interface
클래스 위임 : by
- 편하게 살자
Kotlin
class DelegatingCollection<T>( innerList: Collection<T> = ArrayList<T>()
: Collection<T> by innerList { // Collection<T>의 모든 기능 구현을 innerList에게 위임(delegate) 한다.
}
// Collection<T>의 일부 함수를 구현하고 싶으면 그냥 override하면 된다.
40. Class, Instance, Interface
object 키워드
- object 키워드는 클래스를 정의 하며 동시에 인스턴스를 생성한다.
- Class에 사용하면 Singleton
Kotlin
object ListUtility{
fun <T> add(list: List<T>, element: T) = …
}
// ListUtility.add(list, 1)
41. Class, Instance, Interface
object 키워드
- Kotlin에는 static 멤버가 불가 따라서 companion object 사용
Kotlin
Class A {
companion object {
fun bar() {
println(“THIS IS COMPANION OBJECT”)
}
}
}
>>> A.bar() // THIS IS COMPANION OBJECT