fun main(args: Array<String>){
println("Hello, World!")
}
코틀린은 함수를 최상위 수준에 정의할 수 있다
⇒ 자바 처럼 class안에 함수를 넣어야 할 필요가 없다는 뜻
파라미터의 이름 뒤에 파라미터의 타입을 쓴

코틀린에서의 if는 문장이 아니라 결과를 만들어 내는 식이다.
fun max(a: Int, b: Int) : Int = if (a > b) a else b
코틀린에서는, 식이 본문인 함수가 많이 쓰인다.
또한, 앞서 말했던 코틀린의 ‘타입 추론’기능에 의해 반환 타입을 생략하여 아래와 같이 적을 수 있다
fun max(a: Int, b: Int) = if (a > b) a else b
그러나 이는, ‘식이 본문인 함수’의 반환 타입만 생략 가능하다.
블록이 본문인 함수가 값을 반환한다면, 반드시 반환 타입을 지정해야된다.
타입을 지정을 생략하는 경우 (대부분의 경우)
val a = "나는 코틀린 스터디 중"
val b = 23
타입을 추가하고 싶다면?
val b: Int = 23
초기화 식을 사용하지 않고 변수를 선언하고 싶다면? (*반드시 타입 지정을 하자)
val c: Int
c = 23
변경 불가능한 참조를 저장하는 변수, 재대입이 불가능하다
변경 가능한 참조, 변수의 값은 바뀔 수 있다
** 기본적으로 val로 선언하고, 나중에 꼭 필요할 때만 var로 선언하는 것을 권장
(1) 어떤 블록이 실행될 때, 오직 한 초기화 문장만 실행됨을 컴파일러가 확인할 수 있다면 조건에 따라 val값을 다른 여러 값으로 초기화 할 수 있다.
val message: String
if (canPerf○rmOperati○n()) {
message='Success"
//...연산을수행한다
l
else {
messaqe=''Failed"
)
(2) val 참조 자체는 불변일지라도 그 참조가 가리키는 객체의 내부 값은 변경될 수 있다.
val lang = arrayListOf("Java") //불변 참조를 선언
lang.add("Kotlin") //참조가 가리키는 객체 내부를 변경
(1)var을 이용하여 변수의 값을 변경할 수는 있지만, 타입은 유지된다.
var ans = 42
ans = "코틀린 공부 중" //변수 타입이 달라 컴파일 오류 발생
fun main(args: Array<strlng>) {
val name = if(args.slze>0) args[0] else''Kotlin'
Println(''Hello,$name")
}
println("\$x")
// \이스케이프기호를 이용해라//자바의 경우
public Class Person {
prlvate final String name;
public Person(String name) {
this.name=name;
}
public Strinq getName () {
return name
}
}
위와 같은 내용을 코틀린으로 변경하면
class Person (val name: String)
값 객체 : 위와 같이 코드 없이 데이터만 저장하는 클래스
** 코틀린의 기본 가시성은 public이므로 public 가시성 변경자는 생략됨
클래스 안에서 변경 가능한 프로퍼티 선언하기
class Person(
val name: String // 읽기 전용 프로퍼티
var isMarried: Boolean // 쓰기 전용 프로퍼티
)
val 프로퍼티 : 게터만 선언
var 프로퍼티 : 게터와 세터 모두 선언
코틀린에서 Person 클래스 사용하기
- 게터와 세터의 이름을 정하는 규칙의 예외
게터
이름이 is로 시작하는 프로퍼티의 게터 ⇒ get이 붙지 않고 이름 그대로 사용 됨
(is로 시작하지 않는 그냥 프로퍼티를 사용해도 코틀린이 자동으로 케터를 호출해줌)
세터
이름이 is로 시작하는 프로퍼티의 세터 ⇒ is를 set으로 바꾸기
예시
```kotlin
class Love(
var isLove: Boolean = true
)
Love.setLove = false
```
new 키워드를 사용하지 않고, 생성자를 호출할 수 있다
val person = Person("hyoeun", false)
println(person.name) //hyoeun 출력
println(person.isMarried) // false출력
class Rectangle(val height: Int, val width: Int) {
0 val isSquare: Boolean
get() {
return heigth == width
}
}
이 프로퍼티에는 자체 구현을 제공하는 getter만 존재한다.
property에 접근할 때마다 getter가 property 값을 매번 다시 계산한다.
자바의 경우

위와 같이 패키지의 구조와 일치하는 디렉터리 계층 구조를 만들고, 클래스의 소스코드를 그 클래스가 속한 패키지와 같은 디렉터리에 위치시켜야 한다
코틀린의 경우는 다음과 같다.

별도의 디렉터리를 만들지 않고, geometry라는 폴더 안에 shape.kt를 넣어도 되나, 자바와 같이 패키지별로 디렉터리를 구성하는 것을 지향한다.
왜 그럴까?
자바와 코틀린을 함께 사용하는 프로젝트에서는 자바의 방식을 따르지 않으면, 자바 클래스를 코틀린 클래스로 *마이그레이션할 때 문제가 생길 수도 있다.
마이그레이션 이란?
데이터나 시스템이 한 환경에서 다른 환경으로 옮겨지는 과정.
파일을 A에서 B로 옮기는 단순한 과정이 아닌 데이터의 변환, 적용, 새로운 환경에서의 통합 과정도 모두 포함된 복잡한 과정이다.
enum 클래스는 다음과 같이 정의한다
enum class Color {
RED, ORANGE, YELLOW, GREEN
}
enum class Color (
val r: Int, val g: Int, val b: Int // 상수의 프로퍼티 '정의'
) {
RED(255, 0, 0), ORANGE(255, 165, 0).. **;**
// 각 상수를 생성할 때 그에 대한 프로퍼티 '값을 지정'
***// enum 상수 목록과 메소드 정의 사이에 세미콜론 필수***
fun rgb() =( r*256 + g )*256 + b
// enum 클래스 안에서 메소드를 정의한다
}
fun getMnemonic( color: Color) = */**/ when도 값을 만들어 내는 식이다
// 식이ㅣ 본문인 함수에 바로 when을 쓸 수 있다***
when (color) {
Color.RED -> "R"
Color.ORANGE -> "O"
.
.
.
}
+) 한 when 분기 안에 여러 값을 사용할 때는, 콤마로 구분해 주면 된다.
fun getMnemonic( color: Color) =
******when (color) {
Color.RED, Color.BLUE, Color.YELLOW -> "R"
Color.ORANGE -> "O"
.
.
}
+) when 분기 조건에 여러 다른 객체 사용하기
fun mix(c1: Color, c2: Color) =
when **(setOf(c1, c2)**) {
***// when 식의 인자로 아무 객체나 사용할 수 있다***
setOf(RED, YELLOW) -> ORANGE
.
.
else -> throw Exception("Dirty Color")
}
if (e is Sum) {
return eval(e.right) + eval(e.left)
}
is를 이용하여 Sum 타입인지 검사한 다음에는 e.right와 e.left를 사용할 수 있다.
val n = e as Num
if문으로 만든 eval 함수
fun eval(e: Expr) : Int =
if (e is Num) {
e.value
} else if (e is Sum) {
eval(e.right) + eval(e.left)
}
else {
throw IllegalArgumentException("Unknown expression")
}
⇒ if 중첩 대신 when을 사용한다면?
fun eval(e: Expr) : Int =
when(e) {
is Num -> **// 인자 타입을 검사하는 when 분기**
e.value
is Sum ->
eval(e.right) + eval(e.left)
else ->
throw IllegalArgumentException("Unknown expression")
}
while (조건) {
/*내용*/
}
조건이 참인 동안 본문을 반복 실행한다
do {
/*내용*/
} while (조건)
맨 처음 본문을 한 번 실행한 다음
조건이 참인 동안 본문을 반복 실행
.. < 연산자로 시작 값과 끝 값을 연결해서 범위를 만든다.
val oneToTen = 1..10 (1~10의 범위에서)
for (i in 100 downTo 1 step 2)
// downTo : 역방향 수열
// step 2 : 증가 값 2
출력 >> 100 98 96 ..
in 연산자를 사용해 어떤 값이 범위에 속하는지 검사할 수 있다.
fun isLetter(c: Char) = c in 'a'..'z' || c in 'A'..'Z'
println(isLetter('q')) // true 출력
+) when에서 in 연산자 사용하기
fun recognize(c: Char) = when (c) {
in '0'..'9' -> "It's a digit!"
in 'a'..'z', in 'A'..'Z' -> "It's a letter!"
else -> "I don't know.."
}
in 연산자 범위는 문자에만 국한되지 않는다, 비교가 가능한 클래스라면 그 클래스의 인스턴스 객체를 사용해 범위를 만들 수 있다
함수는 정상적으로 종료할 수 있지만 오류가 발생하면 예외를 던질 수 있다(throw).
코틀린의 throw는 식이므로 다른 식에 포함될 수 있다
val percentage =
if(number in 0..100)
number
else
throw IllegalArgumentException(
"A percentage value must be between 0 and 100 : $number")
예외를 처리하기 위해 try, catch, finally 절을 함께 사용한다
fun readNumber(read: BufferedReader) {
val number =try {
Integer.parseInt(reader.readLine())
} catch (e: NumberFormatException) {
return
}
println(number)
}
코틀린의 try 키워드는 if나 when과 마찬가지로 식으로 쓰인다.
fun readNumber(reader: BufferedReader) {
val number = try {
Integer.parseInt(reader.readLine())
} catch(e: NumberFormatException) {
null
}
println(number)
}