변수
타입 추론 (Type Inference)
/* 컴파일러가 컴파일 타임에 타입 추론을 통해 타입을 알아낸다 */
val i = 10 // Int
val s = "str" // String
val l1 = 10L
val l2: Long = 10 // 타입을 명시할 수도 있음
변경 가능한 변수 (mutable)
var(variable) 키워드로 선언된 변수는 참조값을 변경할 수 있습니다. 다른 데이터 타입으로의 변경은 불가능합니다.
var x = 10
x = 20 // ok
// 같은 데이터 타입 값만 세팅이 가능하다
x = "test" // (x) compile error
변경 불가능한 변수( immutable )
val(value) 키워드로 선언된 변수에는 단 한 번만 참조값을 세팅할 수 있습니다. (초기값 세팅만 가능)
자바의 final 키워드로 선언한 것과 동일합니다.
val x = 10
x = 20 // (x) compile error
// 선언과 동시에 세팅하라는 의미가 아니다
val isUpper: Boolean // 초기화를 하지 않고 선언하는 경우, type 명시 필수!!
if(x > 0) {
isUpper = true // ok
} else {
isUpper = false // ok
}
isUpper = false // (x) compile error
변수에 세팅된 참조값을 변경할 수 없는 것이기 때문에, 참조가 가르키는 객체의 내용은 변경할 수 있습니다.
val list = arrayListOf(1, 2)
list += 3 // list would be [1, 2, 3]
함수
Standard library functions
코틀린에서는 println
함수와 같이 별도의 import 없이 제공하는 API들이 있습니다.
이는 kotlin-stdlib와 default import를 지원하기 때문에 가능한 것입니다.
// println은 kotlin-stdlib::kotlin.io 패키지 하위에 존재
println("Hello, world!")
Default Import
Kotlin 파일에는 기본적으로 임포트되는 패키지들이 존재합니다.
- kotlin.*
- kotlin.collections.*
- kotlin.io.*
Packages and imports | Kotlin
kotlinlang.org
kotlin-stdlib 라이브러리는 코틀린 프로젝트 설정에서 확인할 수 있습니다.
Kotlin stdlib API documentation
다음 페이지에서 상세 API 목록과 정의를 찾을 수 있습니다.
kotlin-stdlib - Kotlin Programming Language
kotlin-stdlib - Kotlin Programming Language
kotlinlang.org
Statement vs Expression
코틀린은 statement <-> expression 을 구분하는 관점에서 자바와는 다른 점이 많습니다.
코틀린에서 if 키워드는 식으로 처리됩니다. 다른 언어에서는 보통 if 문이라 부르는 것과 차별이 있는 것인데요. 어떤 차이가 있을까요?
val isZero = if(number == 0) true else false
/* if-else block 가장 아랫 라인이 result에 세팅됨 */
val result =
if(condition) {
/* ... */
"if end" // result = "if end"
} else {
/* ... */
"else end" // result = "else end"
}
// 대입(=) 키워드는 반대로 expression -> statement로 처리된다
fun isZero(a: Int, b: Int): Int = if(number == 0) true else false
Statement
- statement는 블록의 상위 요소( 보통 블록을 포함 )
- 아무런 값을 만들어내지 않음
Expression
- 다른 expression의 하위 요소로 포함될 수 있습니다.
- expression의 결과는 값을 생성합니다.
Class와 Property
자바에서의 프로퍼티는 Field와 Access Method를 묶어놓은 개념입니다.
코틀린에서는 이를 컴파일러를 통해 언어 기본 기능으로 제공합니다.
- val 필드 → getter 제공
- var 필드 → getter/setter 제공
또한 클래스 인스턴스 생성시, 메모리 할당 연산자 new
를 사용하지 않아도 됩니다.
/* Kotlin */
class Human(
val name: String, // read-only
var age: Int // read + write
)
val human = Human("name", 30) // new operator 생략
println("${human.name}: ${human.age}") // public 변수인 것처럼 사용
var value = 1 // Int 타입도 getter/setter를 내부적으로 제공
/* 같은 내용의 Java 코드, 편의상 어노테이션 처리 */
class Human {
@Getter
private String name;
@Getter @Setter
private int age;
}
커스텀 접근자( Custom Accessor )
커스텀 게터/세터를 만들고 싶은 경우 다음과 같이 사용 할 수 있습니다.
class Rectangle(
val width: Int,
val height: Int
) {
val area: Int
get() = this.width * this.height
}
enum
고전적으로 enum의 경우, switch-case 구문과 사용하기 좋습니다. (코틀린에서는 when)
enum class Direction {
NORTH, SOUTH, WEST, EAST
}
printDirection(d: Direction) = when(d) {
Direction.NORTH -> println("north")
Direction.SOUTH -> println("south")
Direction.WEST -> println("west")
Direction.EAST -> println("east")
}
Enum 또한 클래스이기 때문에 별도의 필드와 메소드를 가질 수 있습니다.
만약 별도의 필드를 정의한 경우, 마지막 항목 뒤에는 세미콜론(;)을 붙여 구분해주어야 합니다.
enum class Snack(
val snackName: String,
val price: Int
) {
POTATO_CHIP("포테이토칩", 1000),
SWING_CHIP("스윙칩", 1200),
CHOCO_CHIP("초코칩", 2500);
fun calcPrice(count: Int) = this.price * count
}
fun main(args: Array<String>) {
val price = Snack.POTATO_CHIP.calcPrice(3)
println(price)
}
when
when 키워드는 Java의 switch statement와 동일한 역할을 합니다.
하지만 if와 마찬가지로 statement가 아닌 expression이므로 값을 반환한다는 차이점이 있습니다.
fun describe(obj: Any): String = when (obj) {
1 -> "One"
"Hello" -> "World"
is Long -> "Long"
!is String -> "Not a String"
else -> "Unknown"
}
println(describe(1L)) // "Long" will be printed
/* when문에 파라미터를 세팅하지 않으면, if-else와 같이 사용할 수 있다 */
val items = arrayListOf("banana", "apple")
when {
("banana" in items && "apple" in items) -> print("banana")
"avocado" in items -> print("avocado")
else -> print("no fruit")
}
Smart Casts
개발자가 코드에 type casting을 명시하지 않더라도, 코틀린 컴파일러가 스마트하게 캐스팅을 진행해주는 경우가 있습니다.
is
keyword를 통해 객체가 특정 클래스의 인스턴스임을 확인하면, 컴파일러가 자동으로 type casting을 진행하여 컴파일을 진행합니다.
/* Java */
void function(Object obj) {
if(obj instanceof String) {
String str = (String)obj;
System.out.println(str.length() + " : " + str)
}
}
/* Kotlin */
fun function(x: Any) {
if(str is String) {
print("${str.length} : $str")
}
}
Loop
while, do-while 루프
코틀린은 while
, do-while
루프를 지원하며, Java와 사용법이 같습니다.
while(condition) {
/* ... */
}
do {
/* ... */
} while(condition)
For 루프
코틀린은 range(iterable한 객체)를 통한 이터레이션을 지원합니다.
- 초기값, 증가값을 의미하는 변수와 조건식이 존재하지 않음
조건에 사용할 수 있는 키워드는 다음과 같습니다.
in
,until
,downTo
,step
for(i in 1..10) {
// 1 <= i <= 10
}
for(ch in 'a'..'z') {
// 'a' <= ch <= 'z'
}
for(i in 1..10 step 3) {
// 1, 4, 7, 10
}
/* until은 끝자리 숫자를 제외함을 유의 */
for(i in 1 until 5) { // step 사용 가능
// 1 <= i < 5
}
for(i in 5 downTo 1) { // step 사용 가능
// 5, 4, 3, 2, 1
}
/* iterable 객체를 통한 iteration */
val numbers = listOf(1, 2, 3, 4)
for (number in numbers) {
// 1, 2, 3, 4
}
Range 클래스( x..y ) 분석
x..y
도 역시 kotlin-stdlib가 제공하는 하나의 Range 클래스이며, 다양한 종류를 지원하고 있습니다.
- IntRange, CharRange, ClosedRange, ...
kotlin.ranges - Kotlin Programming Language
kotlin.ranges - Kotlin Programming Language
kotlinlang.org
Range의 구현체 중 IntRange 클래스는 아래와 같이 구성되어 있습니다.
val range = 1..10
/* 아래는 디버깅으로 확인한 클래스 정보 */
range = {IntRange@491} 1..10
first = 1
last = 10
step = 1
endInclusive = {Integer@527} 10
isEmpty = false
/* 다음 코드를 실행하면, range 변수는 IntRange가 아닌 IntProgression의 객체가 된다
* 이 내용은 생략 */
val range = 1..10 step 2
try, catch, finally
Java와 표현식과 구동 방식이 굉장히 비슷합니다.
fun doThings() {
try {
/* ... */
} catch (e: NumberFormatException) { // 예외 타입을 ':' 오른쪽에 써준다
/* ... */
} catch (e: Exception) {
/* ... */
} finally {
// finally는 Java와 동일하게 동작
}
}
/* 함수가 던지는 예외를 명시하지 않아도 된다 */
fun throwException() {
/* throws가 아닌 throw를 사용한다 */
throw IllegalArgumentException("errmsg")
}
try-catch
키워드도 statement가 아닌 expression입니다.
그렇기에 if-else
와 동일하게 블럭의 마지막 라인은 결과값으로 반환됩니다.
단, finally 문은 그대로 statement를 유지
/* 아래 try 구문 정상 구동
* value -> "Succeed"
* Exception 발생시
* value -> "Fail"
*/
val value =
try {
/* do things... */
"Succeed"
} catch(e: Exception) {
/* do things... */
"Fail"
} finally {
// finally는 statement이므로 결과값에 영향을 주지 않음
}
☕️ Networking
기술 직군의 기술적인 교류, 커리어 이야기, 직군 무관 네트워킹 모두 환영합니다!
위클리 아카데미 오픈 채팅방(비밀번호: 9323)
kakaotalk: https://open.kakao.com/o/gyvuT5Yd