
Expression
값을 만들어 내며 다른 Expression의 하위 요소로 계산에 참여할 수 있다.
Statement
자신을 둘러싸고 있는 가장 안쪽 블록의 최상위 요소로 존재하며, 아무런 값을 만들어내지 않는다.
| 문법 요소 | Java | Kotlin | 
|---|---|---|
| if | if문, Statement | Expression Kotlin에서는 if가 값을 만들어 내기 때문에, 3항 연산자가 필요 없다. | 
| 대입 = | 대입식, Expression | Statement 대입식과 비교식을 잘못 바꿔 쓰는 버그 방지 | 
| 제어 구조 | Statement | Expression Loop를 제외한 모든 제어구조 | 
| when | Java에는 없음. | Expression 다른 변수에 대입할 수 있다. | 
| throw | Statement | Expression 다른 식에 포함될 수 있다. | 
| try, catch | Statement | Expression try, catch의 값을 변수에 대입할 수 있다. | 
fun max(a: Int, b: Int): Int {
	return if (a > b) a else b
}Type Inference 타입 추론을 통해 컴파일러가 자동으로 함수 반환 타입을 정해준다. fun max(a: Int, a: Int) = if (a > b) a else bvalImmutable 참조를 저장하는 변수final varMutable 참조val answer = 1
val answer2: Int  // 초기화 하지 않는다면 타입 추론이 불가능하기 때문에 반드시 타입 지정 해야한다.
// ...
answer2 = 2
val message: String
// ...
if (canPerformOperation()) {
	message = "Success"
}
else {
	message = "Failed"
}
val answer3 = 3
// ...
answer3 = -1   // Compile Error (Val cannot be reassigned)
val answer4 = 4
// ...
answer4 = "no answer"  // Compile Error (Val cannot be reassigned, Type mismatch)
val languages = arrayListOf("Java", "Python", "Go", "C", "Javascript")
languages.add("Kotlin")   // OK, val means just immutable referenceval language = "Kotlin"
println("Hello, ${language}!")language = "Python"
print(f"Hello, {language}!")publicclass Person(val name: String)public class Person {
	private final String name;
	public Person(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
}val : getter 만 제공var : getter, setter 모두 제공class Person(val name: String, val isMarried: Boolean)$ kotlinc
Welcome to Kotlin version 1.7.10 (JRE 17.0.4.1+1-LTS-2)
Type :help for help, :quit for quit
>>> class Person(val name: String, val isMarried: Boolean)
>>> val person = Person("rolroralra", true)
>>> println(person.name)
rolroralra
>>> println(person.isMarried)
trueclass Rectangle(val height: Int, val width: Int) {
	val isSquare: Boolean
		get() {
			return height == width
		}
}class Rectangle(val height: Int, val width: Int) {
	val isSquare: Boolean
		get() = height == width
}NOTE
1개의 kt 확장자 파일에 여러 개의 클래스를 넣으면, 해당 파일명이 패키지 마지막 이름이 되어서, 한 개의 kt파일 자체가 패키지 디렉토리를 의미하게 된다.
클래스 각각이 아주 작은 경우, 주로 사용.
enum 은 soft keyword, enum이라는 이름 사용 가능.enum class Color {
	RED, ORANGE, YELLOW, GRREN, BLUE, INDIGO, VIOLET
}enum class Color(
	val r: Int, val g: Int, val b: Int
) {
	RED(255, 0, 0), 
	ORANGE(255, 165, 0), 
	YELLOW(255, 255, 0), 
	GREEN(0, 255, 0), 
	BLUE(0, 0, 255), 
	INDIGO(75, 0, 130), 
	VIOLET(238, 130, 238);   // 여기는 반드시 세미콜론을 사용해야 한다.
	fun rgb() = (r * 256 + g) * 256 + b	   
}whenswitch 대체break,when (val response = executeRequest())import geometry.colors.Color
fun getMnemonic(color: Color) =  
    when (color) {  
        Color.RED -> "Richard"  
        Color.ORANGE -> "Of"  
        Color.YELLOW -> "York"  
        Color.GREEN -> "Gave"  
        Color.BLUE -> "Battle"  
        Color.INDIGO -> "In"  
        Color.VIOLET -> "Vain"  
    }import geometry.colors.Color
import geometry.colors.Color.*
fun getWarmth(color: Color) = when (color) {  
    RED, ORANGE, YELLOW -> "warm"  
    GREEN -> "neutral"  
    BLUE, VIOLET -> "cold"  
    else -> "not supported"  
}fun mix(c1: Color, c2: Color) =  
    when (setOf(c1, c2)) {  
        setOf(RED, YELLOW) -> ORANGE  
        setOf(YELLOW, BLUE) -> GREEN  
        setOf(BLUE, VIOLET) -> INDIGO  
        else -> throw Exception("Not Supported")  
    }fun Request.getBody() =
	when (val response = executeRequest()) {
		is Success -> response.body
		is HttpError -> throw HttpException(response.status)
	}whenwhen 에 인자가 없을 경우, 분기 조건이 Boolean 결과를 계산하는 식이어야 한다.fun mixOptimized(c1: Color, c2: Color) =  
    when {  
        (c1 == RED && c2 == YELLOW) || (c1 == YELLOW && c2 == RED) -> ORANGE  
        (c1 == YELLOW && c2 == BLUE) || (c1 == BLUE && c2 == YELLOW) -> GREEN  
        (c1 == BLUE && c2 == VIOLET) || (c1 == VIOLET && c2 == BLUE) -> INDIGO  
        else -> throw Exception("Not Supported")  
    }타입 검사와 타입 캐스트를 조합
is로 변수에 든 값의 타입을 검사한 다음에 그 값이 바뀔 수 없는 경우에만 작동한다.
타입 검사  is
- java의 타입 검사 instanceof
명시적 타입 캐스트 as
fun eval(expr: Expr): Int {  
    if (expr is Num) {  
        val n = expr as Num     // 명시적 타입 캐스트. 불필요한 코드 (No cast needed)
        return n.value  
    } else if (expr is Sum) {  
        return eval(expr.left) + eval(expr.right)   // Smart Cast  
    } else {  
        throw Exception("Not Supported")  
    }  
}// smart cast
fun eval(expr: Expr): Int {  
    if (expr is Num)  
        return expr.value  
    else if (expr is Sum)  
        return eval(expr.left) + eval(expr.right)  
    else  
        throw Exception("Not Supported")  
}// when 활용, smart cast
fun eval(expr: Expr): Int =  
    when (expr) {  
        is Num -> expr.value  
        is Sum -> eval(expr.left) + eval(expr.right)  
        else -> throw Exception("Not Supported")  
}fun evalWithLogging(expr: Expr): Int =  
    when (expr) {  
        is Num -> {  
            println("nums: ${expr.value}")  
            expr.value  // 블록의 마지막 식이므로, expr.value가 return 된다.
        }  
        is Sum -> {  
            val left = evalWithLogging(expr.left)  
            val right = evalWithLogging(expr.right)  
  
            println("sums: $left + $right")  
            left + right  
        }  
        else -> throw Exception("Not Supported")  
    }whilewhile (isValid) {
	/* ... */
}
do {
	/* ... */
} while (isValid)for0..10  : [0, 10] 폐구간0 until 10  : [0, 10) 개구간100 downTo 1  : 100,99,98,......,1  (included)100 downTo 1 step 2  : 100, 98, 96, ......, 2'A'..'Z'fun fizzBuzz(i: Int) = when {  
    i % 15 == 0 -> "FizzBuzz"  
    i % 3 == 0 -> "Fizz"  
    i % 5 == 0 -> "Buzz"  
    else -> "$i"  
}
fun main() {
	for (i in 1..100) {  
	    print("${fizzBuzz(i)} ")
	}
	
	println()
}for ((key, value) in map)val binaryReps = ('A'..'Z').groupBy ({ it }, { Integer.toBinaryString(it.code)})  
  
for ((alphabet, binary) in binaryReps) {  
    println("$alphabet = $binary")  
}for (value in list)for (index in list.indices)for ((index, value) in list.withIndex())val list = arrayListOf("10", "11", "1001")  
  
for (element in list) {  
    println(element)  
}  
  
for (i in list.indices) {  
    println("index = $i, element = ${list[i]}")  
}  
  
for ((index, element) in list.withIndex()) {  
    println("list[$index] = $element")  
}for (value in set)for (index in set.indices) ,  set.elementAt(index)for ((index, element) in set.withIndex())val set = setOf("10", "11", "1001")  
  
for (element in set) {  
    println(element)  
}  
  
for (i in set.indices) {  
    println("index = $i, element = ${set.elementAt(i)}")  
}  
  
for ((index, element) in set.withIndex()) {  
    println("set.elementAt($index) = $element")  
}inin 연산자를 사용해 어떤 값이 범위/컬렉션에 속하는지 검사할 수 있다.!inComparable 을 구현한 클래스의 경우, 범위를 만들 수 있다.fun recognize(c: Char) = when (c) {  
    in '0'..'9' -> "Digit"  
    in 'a'..'z', in 'A'..'Z' -> "Alphabet"  
    in " \t\n\r" -> "LineAndSpace"  
    in "!@#$%^&*()[]{}()<>~\\|;:'\",./?" -> "Special"  
    else -> throw Exception("Not Supported")  
}  
  
println(recognize('8'))  
println(recognize('d'))  
println(recognize(' '))  
println(recognize('@'))println("Kotlin" in "A".."K")   // false  = "Kotlin" >= "A" && "Kotlin" <= "K"
println("Kotlin" in "A".."L")   // true   = "Kotlin" >= "A" && "Kotlin" <= "L"
println("Kotlin" in setOf("Java", "Python", "Go", "Scala"))  // falsethrownew 를 붙일 필요가 없다.throw 는 식(Expression)이므로 다른 식에 포함될 수 있다.fun percentage(value: Int, totalValue: Int = 100) =  
    if (value in 0..totalValue) {  
        value.toDouble() * 100 / totalValue  
    } else {  
        throw IllegalArgumentException("Value must be between 0 and $totalValue: $value")  
    }
println("${percentage(47, 250)}%")  // 18.8%try catchchecked exception , unchecked exception 을 구별하지 않는다.NOTE
Java의 경우, checked/unchecked exception을 구분하며, checked exception의 경우는 모두 catch로 처리하거나 throws 절에 명시해야 한다.
fun readNumber(reader: BufferedReader): Int? {  
    return try {  
        Integer.parseInt(reader.readLine())  
    } catch (e: NumberFormatException) {  
        null  
    }  
}
val br = BufferedReader(InputStreamReader(System.`in`))  
println(readNumber(br))