F.R.I.D.A.Y.

Kotlin: 13 예외 처리 본문

DEV/Kotlin

Kotlin: 13 예외 처리

F.R.I.D.A.Y. 2020. 4. 5. 22:26
반응형

 우리가 살면서 목돈을 마련하는 이유는 무엇일까요? 미래를 예측할 수 없기 때문에. 즉, 만일의 상황이 발생했을 때 이를 대비하기 위해 목돈을 마련해둡니다.

 프로그램에서도 이렇게 목돈과 같은 문법이 존재합니다. 이번 시간에는 프로그램에서 갑작스럽게 발생할 수 있는 오류를 대비하는 예외 처리를 배워봅니다.


문제 이해하기

0으로 나누기

 사용자로부터 두 수 A와 B를 받아서 A/B의 결과를 출력하는 프로그램을 만든다고 생각해보겠습니다.

fun main(args:Array<String>){
	var a:Int
	var b:Int
	
	print("A 값 입력: ")
	a = readLine()!!.toInt()
	print("B 값 입력: ")
	b = readLine()!!.toInt()
	
	println("A / B = ${a/b}")
}

A에 2, B에 4를 입력한 모습. Int 타입이기 때문에 결과는 내림 처리되어 0으로 출력되었다.

 나누기에서 생각해볼 수 있는 문제가 divde for zero. 0으로 나누는 문제입니다. 분모는 0이 될 수 없습니다. 따라서 만일 B의 값으로 0을 입력한다면 오류가 출력됩니다.

B의 값으로 0을 입력한 경우. 0으로 나눌 수 없어 오류가 출력되었다.

 어떤 오류가 났는지 디버거가 알려주는군요.[# by zero] 그러나 문제는 이후에 발생합니다. 이렇게 오류[# 이런 식으로 프로그램이 실행 도중에 오류가 난 것을 런타임 에러(혹은 오류)라고 부릅니다.]가 일어나게 되면 프로그램을 하던 일을 멈추고 비정상 종료를 하게 됩니다. 따라서 이후에 어떤 코드를 썼던 작동하지 않습니다.

출력 값 뒤에 안내 문자열이 출력되지 않음

 그래서 예외처리 구문이 필요한 것입니다.

if 문을 이용한 예외 처리

 이렇게 0으로 나누는 문제는 사전에 알 수 있으니 예외 처리를 할 수 있습니다.

if(b != 0) println("A / B = ${a/b}")
else println("0으로 나눌 수 없습니다.")

 if 구문을 이용해 처리할 수도 있겠군요. 이렇게 사전에 예측할 수 있는 문제들은 다른 문법들을 이용해 예외 처리를 한다지만, 만일 사전에 예측할 수 없는 문제들이 있습니다. 이 문제들은 어떻게 예외 처리를 해야 할까요?


try-catch

 그래서 있는 것이 try-catch 문법입니다.

네이버 사전에 등재된 try, catch의 의미

 구조

try {
	// commands
} catch(parameter) {
	// commands
} [finally {
	// commands
}]
 try {}

 실제 수행할 코드를 작성하는 부분입니다. 이곳의 코드가 문제가 일어나게 되면 catch {} 구문으로 이동해 오류를 잡게 됩니다.

catch(parameter){}

 try {} 구문에서 오류가 발생했을 때, 해당 명령어에서 바로 catch 구문으로 넘어오게 됩니다. try와 연결된 중괄호 내부 명령어에서 오류가 발생했을 때만 넘어오므로, 만일 오류가 발생하지 않았다면 이곳의 코드는 실행되지 않습니다.

[finally {}]

 try 영역에서 오류가 발생하지 않았다면 catch 내부의 코드는 실행되지 않습니다. 혹은, try에서 오류가 발생했다면 이후 명령이 남았더라도 이후 명령은 실행하지 않고 바로 catch 구문으로 이동해 catch와 연결된 명령어가 실행됩니다. 그러나 finally 구문의 명령어는 어떠한 경우에도 실행되도록 설계되었습니다.

 

 위 설명을 토대로 그림을 그려보면 다음과 같습니다.

적용하기

 이렇게 배운 try-catch 구문을 나눗셈을 하는 위 코드에 적용시켜보겠습니다.

fun main(args:Array<String>){
	var a:Int
	var b:Int
	
	print("A 값 입력: ")
	a = readLine()!!.toInt()
	print("B 값 입력: ")
	b = readLine()!!.toInt()
	
	println("A / B = ${a/b}")
}

 에러가 발생했던 곳은 마지막 ${a/b}가 들어있는 출력 구문입니다. 이 부분을 try-catch로 감싸 보겠습니다.

fun main(args:Array<String>){
	var a:Int
	var b:Int
	
	print("A 값 입력: ")
	a = readLine()!!.toInt()
	print("B 값 입력: ")
	b = readLine()!!.toInt()

	try{
		println("A / B = ${a/b}")
	}catch(e:Exception){
		println("오류 발생: ${e.message}")
	}
	
	println("런타임 오류가 발생했다면 이 글은 출력되지 않습니다. " +
		"예외처리를 했다면 다르겠지만요!")
}

 확인을 위해 아래에 출력문을 하나 추가했습니다. 만일 이 출력문이 정상 실행된다면 예외처리가 잘 되었겠네요.

맨 밑에 출력이 이뤄진 모습

 잘 되었군요.

better use

 이렇게 문제가 발생할 수 있는 부분이라면 예외 처리를 통해 정보를 수집하고 그 정보를 통해 다시 문제를 해결해나갈 수 있습니다. 그럼 모든 부분에 예외 처리를 위한 try-catch를 사용해도 될까요? 아닙니다. 예외 처리를 위한 과정은 의외로 많은 자원을 잡아먹습니다. 빠른 속도를 보장해야 한다면 예외 처리 구문을 모든 곳에 사용해선 안됩니다. 또 한 가지, 여기저기서 에러가 날 수 있어 예외 처리를 해야 한다면 차라리 새로 만드는 것이 좋습니다. 프로그램은 이젠 우리 일상 깊숙이 들어섰습니다. 경우에 따라서는 내가 만든 프로그램이 오류 때문에 다른 사람을 해칠 수도 있겠죠.[# 혹은 전 세계를 멸망으로 이끌 수도 있겠죠.][# 물론 이 글을 읽고 있을 대부분은 배우는 상황일 테니 겁먹지 않아도 됩니다.] 그런 프로그램은 이리저리 장치를 붙여가며 수명을 연장시키는 것보다 새로 만드는 것이 나을 것입니다. 결국, 예외 처리는 "사용이 불가피하다!"라고 판단되는 곳에서만 사용하는 것이 좋습니다.


throw

 try-catch 구문과 함께 사용하는 throw라는 키워드가 존재합니다. '던지다'라는 의미를 가진 throw는 단어 의미 그대로 오류를 "던집니다." 아래 코드를 보겠습니다.

fun main(args:Array<String>){
	var a:Int
	var b:Int
	
	print("A 값 입력: ")
	a = readLine()!!.toInt()
	print("B 값 입력: ")
	b = readLine()!!.toInt()

	try{
		if(b == 0) throw Exception("0으로 나눌 수 없습니다.")
		println("A / B = ${a/b}")
	}catch(e:Exception){
		println("오류 발생: ${e.message}")
	}
	
	println("런타임 오류가 발생했다면 이 글은 출력되지 않습니다. " +
		"예외처리를 했다면 다르겠지만요!")
}

 여기 코드에서 0으로 나누는지 확인하는 코드가 있습니다. 그리고 만일 0으로 나누게 되는 연산이라면 throw 키워드를 동작시킵니다.

예외 처리 문자열이 전달된 모습

 이렇게 throw는 강제로 오류를 일으켜서 catch 구문에서 잡을 수 있게 해줍니다. 이렇게 하면 어떤 오류가 났는지 더 확실히 알 수 있겠죠.


Next.

 

Kotlin: 14 인라인 함수와 익명 함수

함수 파트에서 떨어트리고 지금 나온 인라인&익명 함수입니다. 두 문법은 사실 함수 파트를 다룰 때 이어서 함께 작성해도 되지 않았을까 싶은 생각이 듭니다. 이미 지나가버린 걸 어떻게 하겠어요? 시작합니다...

pang2h.tistory.com

# index

728x90
반응형

'DEV > Kotlin' 카테고리의 다른 글

Kotlin: 15 함수형 프로그래밍  (1) 2020.06.06
Kotlin: 14 인라인 함수와 익명 함수  (0) 2020.04.06
Kotlin: 12 흐름 제어하기  (0) 2020.04.04
Kotlin: 11 반복문-while, do-while  (0) 2020.04.03
Kotlin: 10 반복문-for  (0) 2020.04.03
Comments