코틀린이 어떻게 변경 가능한 데이터보다 변경할 수 없는 불변 데이터 사용을 장려하는지?
fun main(args: Array<String>){
println("Hello, world!")
}
fun
;
을 붙이지 않아도 좋다.코틀린 if는 값을 만들어내지 못하는 문장이 아니고 결과를 만드는 식이라는 점이 흥미롭다.
<함수 표현>
fun max (a: Int, b: Int) : Int {
return if (a > b) a else b
}
fun max (a: Int, b: Int) = if (a > b) a else b
코틀린에서는 식이 본문인 함수가 자주 쓰인다. 코틀린은 타입 추론이 가능하므로 모든 식의 타입을 지정하지 않아도 된다. 블록이 본문인 함수가 값을 반환한다면 반드시 반환 타입을 지정하고 return문을 사용해 반환 값을 명시해야 한다.
코틀린에서는 키워드로 변수 선언을 시작하는 대신 변수 이름 뒤에 타입을 명시하거나 생략하게 허용한다. → 타입으로 변수 선언을 시작하면 타입을 생략할 경우 식과 변수 선언을 구별할 수 없기 때문에이다.
val answer : Int
answer = 42
초기화 식을 사용하지 않고 변수를 선언하려면 변수 타입을 반드시 명시해야한다.
<변수 표현>
#조건에 따른 초기화
val message : String
if(canPerformOperation()){
message = "Success"
}
else{
message = "Failed"
}
#참조는 불변, 객체의 내부 값은 변경 가능
val languages = arrayListOf("Java")
languages.add("Kotlin")
fun main(arg: Array<String>){
val name = if (args.size > 0) args[0] esle"Kotlin"
println("Hello, $name!") //문자열 템플릿
}
코틀린에서 변수를 문자열 안에 사용하려면, 문자열 리터럴의 필요한 곳에 변수를 너호디 변수 앞에 $를 추가하면 된다. 컴파일러는 각 식을 정적으로(컴파일 시점에) 검사하기 때문에 존재하지 않는 변수를 문자열 템플릿 안에서 사용하면 컴파일 시점에 오류가 발생한다. $ 문자를 문자열에 넣고 싶으면 \를 사용해 $를 이스케이프 시킨다. 복잡한 식도 {}로 둘러싸서 문자열 템플릿 안에 넣을 수 있다.
class Person(val name : String)
코드가 없이 데이터만 저장하는 클래스를 값 객체라 부른다. 코틀린 기본 가시성은 public이므로 생략이 가능하다.
class Person{
val name : String, //비공개 필드와 게터를 생성
var isMarried : Boolean //비공개 필드, 게터, 세터 생성
}
#자바와 비교
System.out.println(person.getName());
println(person.name)
/*지나가는 지식*/
자바에서는 is로 시작하는 프로퍼티의 게터에는 get을 붙이지 않고 세터에는 is대신 set을 쓴다.
클래스라는 개념의 목적은 데이터를 캡슐화학 캡슐화한 데이터를 다루는 코드를 한 주체 아래 가두는 것이다. 자바는 프로퍼티(필드, 접근자)라는 개념을 활용하는 프레임워크가 많지만 코틀린은 프로퍼티를 언어 기본 기능으로 제공한다. 클래스에서 프로퍼티를 선언하는 방식은 변수 선언하는 방식과 동일하다. val은 읽기 전용 프로퍼티이며, var은 변경 가능한 프로퍼티이다.
class Rectangle(val height : Int, val width:Int){
val isSquare : Boolean
get() = height == width
}
pachage geometry.example //패키지
import geomtry.shapes.createRandomRectangle //임포트
같은 패키지에 속해 있다면 다른 파일에서 정의한 선언일지라도 직접 사용할 수 있다. 반면 다른 패키지에 정의한 선언을 사용하려면 임포트를 통해 선언을 불러와야 한다. 패키지 이름 뒤에 .*을 추가하면 패키지 않의 모든 선언을 임포트할 수 있다. (최상위에 정의된 함수나 프로퍼티까지 모두 불러오니 유의하기!)
자바에서는 패키지의 구조와 일치하는 디렉터리 계층 구조를 만들고 클래스의 소스코드를 그 클래스가 속한 패키지와 같은 디렉터리에 위치시켜야한다. 코틀린에서는 여러 클래스를 한 파일에 넣을 수 있고, 파일의 이름도 마음대로 정할 수 있다.
enum class Color(
val r : Int, val g: Int
){
RED(255,0,0),iNDIGO(75,0,130);
fun rgb() = r*g
}
enum은 소프트 키워드라 부르는 존재다. enum은 class 앞에 있을 때는 특별한 의미를 지니지만 다른 곳에서는 이름에 사용할 수 있다. 각 enum 상수를 정의할 때는 그 상수에 해당하는 프로퍼티 값을 지정해야만 한다. enum 클래스 안에 메소드를 정의하는 경우 반드시 enum 상수 목록과 메소드 정의 사이에 세미콜론을 넣어야 한다.
fun getMnemonic(color: Color) =
when(color){
Color.RED -> "Richard"
Color.ORANGE -> "Of"
Color.GREEN -> "Gave"
}
color로 전달된 값과 같은 분기를 찾는다. 자바와 달리 각 분기의 끝에 break를 넣지 않아도 된다.
코틀린 when의 분기 조건은 임의의 객체를 허용한다. when의 분기 조건 부분에 식을 넣을 수 있기 때문에 많은 경우 코드를 더 간결하고 아름답게 작성할 수 있다.
fun mixOptimized(cl: Color, c2: Color) =
when{
(cl == RED && c2 == YELLOW) || (cl == YELLOW && c2 == RED) -> ORANGE
else -> throw Exception("Dirty color")
}
//when(setOf(c1,c2)) 인자가 사라짐
setOf()는 호출될 때마다 함수 인자로 주어진 두 색이 when의 분기 조건에 있는 다른 두 색과 같은지 비교하기 위해 여러 Set 인스턴스를 생성한다. 보통은 이런 비효율성이 크게 문제가 되지 않는다. 하지만 이 함수가 아주 자주 호출된다면 불필요한 가비지 객체가 늘어나는 것을 방지하기 위해 인자가 없는 when 식을 사용한다.
코틀린에서는 범위(폐구간)를 사용한다. 보통은 구간의 두 값은 정수 등의 숫자 타입의 값이고, ..
연산자로 시작 값과 끝 값을 연결해서 범위를 만든다. 끝 값을 포함하지 않는 반만 닫힌 범위를 만들고 싶다면 until
함수를 사용하면 된다.
fun isLetter(c: Char) = c in 'a'..'z' || c in'A'..'Z'
fun isNotDigit(c: Char) = c !in '0'..'9'
in 연산자를 사용해 어떤 값이 범위에 속하는지 검사할 수 있다. 반대로 !in을 사용하면 어떤 값이 범위에 속하지 않는지 검사할 수 있다.
fun readNumber(reader: BufferedReader) : Int?{
try{
val line = reader.readline()
return Integer.parseInt(line)
}
catch (e: NumberFormatException){ //예외 타입을 :의 오른쪽에 쓴다.
return null
}
finally{
reader.close()
}
}
try 키워드는 식이다. 따라서 try의 값을 변수에 대입할 수 있다. if와 달리 try의 본문을 반드시 중괄호 { }로 둘러싸야 한다.