0. 오리엔테이션 1. 코틀린의 기본의 기본을 읽혀요! - 코틀린이란 무엇일까? - 변수와 자료형, 연산자 2. 함수형 프로그래밍 이란? - 마법의 요술상자, 함수의 기본 - 요술상자, 함수 가지고 놀기 3. 프로그램 흐름의 제어 - 프로그램의 흐름을 제어해보자! 4. 코틀린의 표준함수 활용하기 - 코틀린과 표준함수 5. 강좌 마무리 프로젝트 |
▶ 깃허브 코드 : github.com/0525hhgus/Kotlin-study
[ 프로그램 흐름 제어]
1. 조건문을 통한 분기
1) if문과 if~else문
▶ if문
if (조건식) {
수행할 문장 // 조건식이 참인 경우에만 수행
...
}
// if 문
var max = 0
if (a < b)
max = b // 수행할 문장이 한 줄이면 중괄호를 생략할 수 있음
▶ if~else문
if (조건식) {
수행할 문장 // 조건식이 참인 경우에만 수행
} else {
수행할 문장 // 조건식이 거짓인 경우에 수행
}
▶ if~else문의 간략화
var max: Int
if (a > b)
max = a
else
max = b
val max = if (a > b) a else b
▶ 블록과 함께 사용하는 경우
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)
}
- 반환된다고 해서 return을 사용하는 것은 아님
▶ 실습: if~else문 사용해보기
package chap05.section1
fun main(){
val a = 17
val b = 7
val max = if (a > b) {
println("a $a")
a
} else {
println("a $b")
b
}
println("max $max")
}
2) else if 다중 조건
▶ else if는 필요한 만큼 조합할 수 있음
- 마지막은 else로 구성
val number = 0
val result = if (number > 0)
"양수 값"
else if (number < 0)
"음수 값"
else
"0"
▶ 실습: else if 성적 등급 출력하기
package chap05.section1
fun main() {
print("Enter the score: ")
val score = readLine()!!.toDouble()
var grade: Char = 'F'
if (score >= 90.0) {
grade = 'A'
} else if (score >= 80 && score <= 89.9) {
grade = 'B'
} else if (score >= 70 && score <= 79.9) {
grade = 'C'
}
println("score: $score, grade: $grade")
}
3) in 연산자와 범위 연산자
▶ 비교 연산자와 논리 연산자의 복합
- ...} else if (score >= 80.0 && score <= 89.9) {...
- 비교 연산자(>=, <=)와 논리곱 연산자(&&)가 사용
▶ 범위(range) 연산자
- 변수명 in 시작값..마지막값
- score in 80..89이면 score 범위에 80부터 89까지 포함
▶ 실습: in 연산자와 범위 연산자 적용하기
package chap05.section1
fun main() {
print("Enter the score: ")
val score = readLine()!!.toDouble()
var grade: Char = 'F'
if (score >= 90.0) {
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")
}
4) when문을 사용한 다양한 조건 처리
▶ 인자를 사용하는 when문
when (인자) {
인자에 일치하는 값 혹은 표현식 -> 수행할 문장
인자에 일치하는 범위 -> 수행할 문장
...
else -> 문장
}
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("기타")
}
5) when과 일치되는 여러 조건과 함수 사용
package chap04.section1
fun main() {
val nestedLambda: ()->()->Unit = { { println("nestedLambda") } }
}
6) when과 in, is 연산자 사용
▶ in 연산자와 범위 지정자 사용
when(x) {
in 1..10 -> print("x는 1 이상 10 이하입니다.")
!in 10..20 -> print("x는 10 이상 20 이하의 범위에 포함되지 않습니다.")
else -> print("x는 어떤 범위에도 없습니다.")
}
▶ is 키워드 함께 사용하기
val str = "안녕하세요."
val result = when(str) {
is String -> "문자열입니다."
else -> false
}
▶ 실습: when 구문을 사용한 등급
package chap05.section1
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..80.9 -> grade = 'B'
in 70.0..70.9 -> grade = 'C'
}
// ctrl + shift + / -> /* */ 주석 처리
/* if (score >= 90.0) {
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")
}
7) 인자가 없는 when
▶ 특정 인자에 제한하지 않고 다양한 조건을 구성
when {
조건[혹은 표현식] -> 실행문
...
}
▶ 인자가 없는 when의 예
fun main() {
print("Enter the score:")
var score = readLine()!!.toDouble()
var grade: Char = 'F'
// 인수 없는 when의 사용
when {
score >= 90.0 -> grade = 'A' // 인자 있는 when과 다르게 조건식을 구성할 수 있음
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")
}
🤔 생각해보세요.
when구문의 조건에는 함수, 콤마로 구분한 여러개의 값 등 여러가지가 사용될 수 있습니다. 다양한 조건을 필요로 하는 문제를 하나 생각해서 when구문으로 구성해보세요.
Q. 다양한 조건을 필요로 하는 문제를 하나 생각해서 when구문으로 구성
A. 물품별로 할인된 가격을 출력하는 프로그램
- 입력 : 물품 이름
- 조건 : 가격이 '100 이상 200 이하'이면 10% 할인된 가격으로
- 출력 : 할인된 가격
package chap05.section1
fun main() {
print("Enter the item:")
val item = readLine()
var price: Double = 0.0
if (item.equals("apple")) {
price = 100.0
} else if (item.equals("orange")) {
price = 120.0
} else if (item.equals("melon")) {
price = 50.0
}
when (price) {
in 100.0..200.0 -> price *= 1.1
}
println("item: $item, price: $price")
}
2. 반복문
1) for문
▶ for문의 선언
for (요소 변수 in 컬렉션 혹은 범위) {
반복할 본문
}
for (x in 1..5) { // 코틀린의 in과 범위 지정을 활용한 루프
println(x) // 본문
}
for (x in 1..5) println(x) // 한줄에 표현하는 경우
- 코틀린에서는 자바와 같은 세미콜론 표현식을 사용하지 않음
▶ for문 예제
- for문을 사용해 1부터 10까지 더하기
fun main() {
var sum = 0
for (x in 1..10) sum += x
println("sum: $sum")
}
▶ 하행 반복 - downTo
- 5, 4, 3, 2, 1
for (i in 5 downTo 1) print(i)
for (i in 5..1) print(i) // 잘못된 사용! 아무것도 출력되지 않는다
▶ 필요한 단계 증가 - step
- 1, 3, 5
for (i in 1..5 step 2) print(i)
▶ 혼합 사용
- 5, 3, 1
for (i in 5 downTo 1 step 2) print(i)
▶ 실습: for문의 예
package chap05.section2
fun main() {
var sum = 0
for (num in 1..100 step 2) { // 홀수합
sum += num
}
println("sum: $sum")
}
package chap05.section2
fun main() {
var sum = 0
for (num in 0..99 step 2) { // 짝수합
sum += num
}
println("sum: $sum")
}
2) while문
▶ while문 선언
while (조건식) { // 조건식이 true인 동안 본문의 무한 반복
본문
....
}
var i = 1
while (i <= 5) {
println("$i")
++i // 계속 반복하다 보면 조건식이 5 이상으로 넘어갈 때 false가 되어 탈출
}
- 데몬 프로그램의 사용 예
while (true) {
temp = 온도 검사
if (temp > 한계 온도) { 경고 발생 }
...
}
▶ while문 예제
- while문을 활용한 팩토리얼 예
fun man() {
print("Enter the number: ")
var number = readLine()!!.toInt()
var factorial: Long = 1
while (number > 0) { // n x ... x 4 x 3 x 2 x 1
factorial *= number
--number
}
println("Factorial: $factorial")
}
3) do~while문
▶ do~while문 선언
do {
본문
} while (조건식)
▶ 실습: do~while문을 활용한 순환문자열
package chap05.section2
// 목표 : 5 -> 12345, 23451, 34512 ...
fun main() {
do {
print("Enter the number: ")
val input = readLine()!!.toInt()
for (i in 0 until input) { // == for (i in 0..(input - 1))
for (j in 0 until input) {
print((i + j) % input + 1)
}
println()
}
} while(input != 0)
}
🤔 생각해보세요.
반복문에 사용하는 for, while, do~while등을 조합하면 다양한 코드의 흐름을 구성할 수 있게 됩니다. 그렇다면 for문을 이용해 입력받은 줄 수만큼 *기호로 삼각형을 만들어내기 위해서는 어떻게 하면 될까요?
다음은 출력의 예 입니다.
Enter the lines: 5
*
***
*****
*******
*********
Q. for문을 이용해 입력받은 줄 수만큼 *기호로 삼각형을 만드는 프로그램
A. Hint
n: 줄 수 입력
반복 (line: 1 → n만큼) {
반복 (space: 1 → (n-line)만큼) { 공백 출력 }
반복 (star: 1 → (2*line-1)만큼) { 별표 출력 }
개행
}
package chap05.section2
fun main() {
print("Enter the line:")
val n = readLine()!!.toInt()
for ( line in 1..n ) {
for ( space in 1..(n - line) )
print(" ")
for ( star in 1 until 2 * line ) // == for ( star in 1..(2 * line - 1) )
print("*")
println()
}
}
3. 흐름의 중단과 반환
1) 흐름 제어 관련 요약
▶ 흐름 제어문
- return: 함수에서 결괏값을 반환하거나 지정된 라벨로 이동
- break: for이나 while의 조건식에 상관없이 반복문을 끝냄
- continue: for이나 while의 반복문의 본문을 모두 수행하지 않고 다시 조건으로 넘어감
▶ 예외 처리문
- try { ... } catch { ... }: try 블록의 본문을 수행하는 도중 예외가 발생하면 catch 블록의 본문을 실행
- try { ... } catch { ... } finally { ... }: 예외가 발생해도 finally 블록 본문은 항상 실행
2) return
▶ return으로 값 반환하기
fun add(a: Int, b: Int): Int P
return a + b
println("이 코드는 실행되지 않습니다.") // 여기까지 도달하지 않음
}
▶ return으로 Unit 반환하기
// 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): Unit {
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") // ①
inlineLambda(13, 3) { a, b -> // ②
val result = a + b
if(result > 10) return // ③ 10보다 크면 이 함수를 빠져 나감, 비지역 반환
println("result: $result") // ④ 10보다 크면 이 문장에 도달하지 못함
}
println("end of retFunc")
}
3) 라벨을 사용한 return
▶ 람다식에서 라벨 사용
람다식 함수명 라벨이름@ {
...
return@라벨이름
}
fun inlineLambda(a: Int, b: Int, out: (Int, Int) -> Unit) { // inline이 제거됨
out(a, b)
}
fun retFunc() {
println("start of retFunc")
inlineLambda(13, 3) lit@{ a, b -> // ① 람다식 블록의 시작 부분에 라벨을 지정함
val result = a + b
if(result > 10) return@lit // ② 라벨을 사용한 블록의 끝부분으로 반환
println("result: $result")
} // ③ 이 부분으로 빠져나간다
println("end of retFunc") // ④ 이 부분이 실행됨
}
▶ 실습: 람다식 리턴과 라벨 사용 예
package chap05.section3
fun main() {
retFunc()
}
inline fun inlineLambda(a: Int, b: Int, out: (Int, Int) -> Unit) {
out(a, b)
}
fun retFunc() {
println("Start of Func")
inlineLambda(12,3) lit@{ a, b ->
val result = a + b
if (result > 10) return@lit
println("result: $result")
}
println("end of Func")
}
▶ 암묵적 라벨
...
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
println("result: $result")
} // inlineLambda() 함수의 끝
println("end of retFunc")
}
4) 람다식 방법과 익명 함수 비교
▶ 람다식 방법
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"
}
...
val result = getMessage(99)
5) break와 continue
▶ break와 continue의 사용
- for이나 while, do...while문 루프를 빠져 나옴
▶ break와 continue의 예
package chap04.section3
fun main() {
for(i in 1..5) {
if (i==3) break
print(i)
}
println() // 개행 문자
println("outside")
}
6) break와 라벨
▶ 라벨 없는 break와 라벨을 사용한 break
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")
}
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")
}
- continue를 사용할 때도 생각해보자
🤔 생각해보세요.
마지막 예제에 있었던 break 비교 예제에 continue를 사용했을 때는 어떻게 되는지 모두 함께 생각해 봅시다.
Q. break 비교 예제에 continue를 사용했을 때
A.
- 라벨 없는 continue
package chap05.section3
fun main() {
labelContinue()
}
fun labelContinue() {
println("labelContinue")
for(i in 1..5) {
second@ for (j in 1..5) {
if (j == 3) continue
println("i:$i, j:$j")
}
println("after for j")
}
println("after for i")
}
- 라벨 있는 continue
package chap05.section3
fun main() {
labelContinue()
}
fun labelContinue() {
println("labelContinue")
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")
}
4. 예외 처리
1) 예외(exception)
▶ 실행 도중의 잠재적인 오류까지 검사할 수 없기 때문에 정상적으로 실행이 되다가 비정상적으로 프로그램이 종료되는 경우
- 운영체제의 문제 (잘못된 시스템 호출의 문제)
- 입력값의 문제 (존재하지 않는 파일 혹은, 숫자 입력란에 문자 입력 등)
- 받아들일 수 없는 연산 (0으로 나누기 등)
- 메모리의 할당 실패 및 부족
- 컴퓨터 기계 자체의 문제 (전원 문제, 망가진 기억 장치 등)
2) 예외 구문
▶ 예외를 대비하기 위한 구문
try {
예외 발생 가능성 있는 문장
} catch (e: 예외처리 클래스명) {
예외를 처리하기 위한 문장
} finally {
반드시 실행되어야 하는 문장
}
- 반드시 실행해야할 작업이 없다면 finally 블록은 생략하고 try~catch 블록만으로 코드를 구성할 수 있음
▶ 실습: 예외 구문 작성하기
package chap05.section4
fun main() {
val a = 6
val b = 0
val c: Int
try {
c = a / b
println("After")
} catch (e: Exception) {
println("Exception")
} finally {
println("Finally")
}
}
3) 특정 예외 처리
▶ 산술 연산에 대한 예외를 따로 특정해서 잡을 때
''
} catch (e: ArithmeticException) {
println("Exception is handled. $(e.message)")
}
- 스택의 추적
...
} catch (e : Exception){
e.printStackTrace()
}
...
4) 예외 발생시키기
▶특정 조건에 따른 예외 발생
throw Exception(message: String)
▶ throw를 사용한 예외 발생 예제
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 이하입니다.")
}
🤔 생각해보세요.
프로그램은 정해진대로만 흘러간다면 아무 문제가 없겠죠. 하지만 다양한 예외 상황을 만날 수 있습니다. 이러한 예외 상황을 생각해보고 어떤것들이 있는지 댓글로 남겨 봅시다. 또한 어떻게 처리할 수 있을까요?
Q. 프로그램의 예외 상황과 처리 방법
A. 제 경험에 빗대어 웹크롤링 프로그램을 생각해본다면, 크게 1) 웹 사이트 주소가 존재하지 않거나 2) Null 데이터를 가져오는 등의 예외 상황이 발생할 수 있습니다.
해당 경우 모두 try-catch문을 사용하여
1)의 경우, 존재하지 않은 웹 사이트 주소를 알리고 다른 웹 사이트 주소가 남았다면 마저 실행되도록 하였습니다.
2)의 경우, Null 데이터를 가져온 웹 사이트 주소를 알리고 다른 웹 사이트 주소가 남았다면 마저 실행되도록 하였습니다.
감사합니다!
'대외활동 > Naver Boostcourse' 카테고리의 다른 글
[부스트코스] 코틀린 프로그래밍 기본 1/2(함수편) - 미니 프로젝트 (0) | 2021.02.14 |
---|---|
[부스트코스] 코틀린 프로그래밍 기본 1/2(함수편) - 코틀린과 표준함수 (0) | 2021.02.12 |
[부스트코스] 코틀린 프로그래밍 기본 1/2(함수편) - 람다식과 고차 함수 (0) | 2021.02.01 |
[부스트코스] 코틀린 프로그래밍 기본 1/2(함수편) - 함수의 기본, 함수형 프로그래밍 (0) | 2021.01.26 |
[부스트코스] 코틀린 프로그래밍 기본 1/2(함수편) - 널과 연산자 (0) | 2021.01.16 |