IDE : Intellij
JDK : zulu11
fun main() {
val a = 12
val b = 7
val max = if(a > b){
println("a 선택")
a // 마지막 식인 a가 반환되어 max에 할당
} else {
println("b 선택")
b // 마지막 식인 b가 반환되어 max에 할당
}
println(max)
}
fun main() {
print("Enter the score: ")
val score = readLine()!!.toDouble()
var grade: Char = 'F'
if (score >= 90) grade = 'A'
else if (score in 80.0..89.9) grade = 'B'
else if (score in 70.0..79.9) grade = 'C'
println("Score: $score, Grade: $grade")
}
readLine() : 콘솔로부터 문자열을 입력받는 함수
in 연산자와 범위 연산자(..)
둘 다 같은 표현 if (score in 80.0..89.9) if (score >= 80.0 && score <= 89.9)
fun main() {
print("Enter the score: ")
val score = readLine()!!.toDouble()
var grade: Char = 'F'
when(score){
in 90.0..100.0 -> grade = 'A'
in 80.0..89.9 -> grade = 'B'
in 70.0..79.9 -> grade = 'C'
!in 70.0..100.0 -> grade = 'F'
}
println("Score: $score, Grade: $grade")
}
when문으로 가능한 것
when (x) { 1 -> print("x == 1") 2 -> print("x == 2") else -> { // 블록 사용 가능 print("x는 1, 2가 아닙니다.) } } when (x) { 0, 1 -> print("x == 0 or x == 1") // 일치되는 조건 여러개 표현 가능 else -> print("기타") } when (x) { parseInt(s) -> print("일치함!") // 함수 반환값 사용 가능 else -> print("기타") }
fun main() {
print("Enter the score: ")
val score = readLine()!!.toDouble()
var grade: Char = 'F'
when {
score >= 90.0 -> grade = 'A'
score in 80.0..89.9 -> grade = 'B'
score in 70.0..79.9 -> grade = 'C'
score < 70.0 -> grade = 'F'
}
println("Score: $score, Grade: $grade")
}
score >= 90.0 과 같이 변수와 조건식을 when문에 직접 사용할 수 있다.
fun main() {
cases("Hello")
cases(1)
cases(System.currentTimeMillis())
cases(MyClass())
}
fun cases(obj: Any){
when(obj){
1 -> println("Int: $obj")
"Hello" -> println("String: $obj")
is Long -> println("Long: $obj")
!is String -> println("Not a String")
else -> println("Unknown")
}
}
when문의 인자로 Any를 사용하면 다양한 자료형의 인자를 받을 수 있다.
실행결과
String: Hello Int: 1 Long: 1631946124704 Not a String
fun main() {
var sum = 0
for(x in 1..10) sum += x
println("sum : $sum")
}
Kotlin for문 기본형
1. 하행 반복for (i in 5 downTo 1) print(i) // downTo 키워드 사용
- step 지정
for (i in 5 step 2) print(i) // 2단계씩 증가
fun main() {
print("Enter the lines: ")
val n = readLine()!!.toInt()
for(line in 1..n){
for(space in 1..(n - line)) print(" ")
for(star in 1 until 2 * line) print("*")
println()
}
}
for문 응용. *로 삼각형 그리기
실행 결과Enter the lines: 5 * *** ***** ******* *********
fun main() {
print("Enter the number: ")
var number = readLine()!!.toInt()
var factorial: Long = 1
while(number > 0){
factorial *= number
--number
}
println("Factorial: $factorial")
}
while문 응용. 팩토리얼 계산
fun main() {
do {
print("Enter an integer: ")
val input = readLine()!!.toInt()
for(i in 0 until input){
for(j in 0 until input) print((i + j) % input + 1)
println()
}
} while (input != 0)
}
do-while문 응용. 콘솔로부터 입력받은 숫자를 순서대로 나열하고 한 자리씩 자리를 옮겨 가며 순환한다.
// 1. Unit 명시적 반환
fun hello(name: String): Unit {
println(name)
return Unit
}
// 2. Unit 이름을 생략한 반환
fun hello(name: String): Unit {
println(name)
return
}
// 3. return문 자체를 생략
fun hello(name: String) {
println(name)
}
fun main() {
retFunc()
}
inline fun inlineLambda(a: Int, b: Int, out: (Int, Int)->Unit) = out(a, b)
fun retFunc(){
println("start of retFunc") // 1
inlineLambda(13, 3) {a, b -> // 2
val result = a + b
if(result > 10) return // 3
println("result: $result") // 4
}
println("end of retFunc") // 5
}
inline으로 선언되지 않은 람다식에서는 return@lable 과 같이 라벨 표기와 함께 사용해야 한다.
위 예제의 경우, 3 에서 return문이 실행되며 람다식 바깥의 retFunc()함수까지 종료시킨다. (비지역 반환)
실행 결과start of retFunc
fun main() {
retFunc()
}
fun inlineLambda(a: Int, b: Int, out: (Int, Int)->Unit) = out(a, b) // inline 제거
fun retFunc(){
println("start of retFunc")
inlineLambda(13, 3) lit@{ a, b -> // 1. 람다식 블록 시작 부분에 라벨 지정
val result = a + b
if(result > 10) return@lit // 2. 라벨을 사용한 블록의 끝으로 이동
println("result: $result")
} // 3. 라벨을 사용한 블록의 끝
println("end of retFunc")
}
람다식 함수 이름 라벨 이름@{ return@라벨 이름 }
과 같이 라벨을 정의해 return을 사용하여 비지역 반환을 방지할 수 있다.
실행 결과start of retFunc end of retFunc
fun retFunc(){
println("start of retFunc")
inlineLambda(13, 3) { a, b ->
val result = a + b
if(result > 10) return@inlineLambda
println("result: $result")
}
println("end of retFunc")
}
람다식의 명칭을 그대로 사용하는 것을 암묵적 라벨이라 한다.
fun retFunc(){
println("start of retFunc")
inlineLambda(13, 3, fun(a, b) {
val result = a + b
if(result > 10) return@inlineLambda
println("result: $result")
})
println("end of retFunc")
}
익명 함수는 일반 함수처럼 작동하기 때문에 return도 일반 함수에서 반환되는 것과 같이 사용할 수 있다.
- 람다식 방법
val getMessage = lambda@ { num: Int -> if(num !in 1..100) { return@lambda "Error" // 라벨을 통한 반환 } "Success" // 마지막 식 반환 }
- 익명 함수 방법
val getMessage = fun(num: Int): String { if(num !in 1..100) { return "Error" // 라벨을 통한 반환 } return "Success" // 마지막 식 반환 }
return을 사용하여 명시적으로 반환해야 할 것이 여러 개라면 익명 함수를 쓰는 것이 좋다.
fun greet() = {println("Hello")}
fun main(){
greet() // 아무것도 출력되지 않음
greet()() // Hello 출력
}
할당 연산자에 의해 람다식 {println("Hello")} 자체가 greet() 함수에 할당된 것 뿐이기 때문에 greet()()를 사용해야 greet() 함수가 가진 함수를 사용할 수 있다.
fun greet() = func() {println("Hello")} // 익명 함수를 사용하여
// 함수가 할당됨을 명시적으로 표현
fun greet() = run {println("Hello")}
fun greet() = println("Hello")
fun main() {
for(i in 1..5){
if(i == 3) break
print(i)
}
println()
println("outside")
}
break문을 사용하여 반복문을 빠져나갈 수 있다.
실행 결과
12 outside
fun main() {
for(i in 1..5){
if(i == 3) continue
print(i)
}
println()
println("outside")
}
continue문을 사용하여 for문의 시작 지점으로 돌아갈 수 있다.
실행 결과
1245 outside
fun labelBreak(){
println("labelBreak")
for(i in 1..5) {
second@ for(j in 1..5) {
if(j == 3) break
println("i: $i, j: $j")
}
println("after for j")
}
println("after for i")
}
break문이 가장 가까운 second@ 블록을 탈출한다.
fun labelBreak(){
println("labelBreak")
first@ for(i in 1..5) {
second@ for(j in 1..5) {
if(j == 3) break@first
println("i: $i, j: $j")
}
println("after for j")
}
println("after for i")
}
break문이 first@ 블록을 탈출한다.
fun labelBreak(){
println("labelBreak")
first@ for(i in 1..5) {
second@ for(j in 1..5) {
if(j == 3) continue@first
println("i: $i, j: $j")
}
println("after for j")
}
println("after for i")
}
continue문이 first@ 블록으로 돌아간다.
fun main() {
val a = 6
val b = 0
val c: Int
try {
c = a / b
} catch (e: ArithmeticException) {
println("Exception is handled. ${e.message}")
// e.printStackTrace()
} finally {
println("finally 블록은 반드시 실행됨")
}
}
try 블록에서 예외가 발생하고 catch 블록 구문이 출력된다.
실행 결과
Exception is handled. / by zero finally 블록은 반드시 실행됨
catch 구문을 e.printStacTrace()로 수정하여 스택을 추적할 수 있다.
실행 결과
finally 블록은 반드시 실행됨 java.lang.ArithmeticException: / by zero at ch04.section3.TryCatchKt.main(TryCatch.kt:12) at ch04.section3.TryCatchKt.main(TryCatch.kt)
fun main() {
var amount = 600
try {
amount -= 100
checkAmount(amount)
} catch (e: Exception) {
println(e.message)
}
println("amount: $amount")
}
fun checkAmount(amount: Int){
if(amount < 1000) throw Exception("잔고가 $amount 으로 1000 이하입니다.")
}
throw 키워드로 의도적으로 예외를 발생할 수 있다.
amount가 1,000 이하일 때 throw로 예외를 발생시키고 main() 함수의 catch가 잡아 처리한다.실행 결과
잔고가 500 으로 1000 이하입니다. amount: 500
// 사용자 예외 클래스
class InvalidNameException(message: String): Exception(message)
fun main() {
val name = "Kildong123"
try {
validateName(name)
} catch (e: InvalidNameException) {
println(e.message)
} catch (e: Exception) {
println(e.message)
}
}
fun validateName(name: String){
if(name.matches(Regex(".*\\d+.*"))) // name에 숫자가 포함되어 있을 경우
throw InvalidNameException("Your name : $name : contains numerals.")
}
Exception 클래스의 하위 클래스인 InvalidNameException을 만들어 사용할 수 있다.