[Kotlin] Android 톺아보기 2-6. Kotlin 예외처리.md

이소은·2022년 10월 4일
0

Android 기본기 잡기

목록 보기
7/9

프로그램 코드를 작성하다 보면 해당 코드가 제대로 동작하지 않고 프로그램이 죽어버리는 (...) 아주 안타까운 현상을 많이 마주하게 된다 흑흑흑흑 이에 대처하는 방안을 알아보자



예외처리

대부분의 오류는 코드를 작성하는 도중에 컴파일러가 잡아낼 수 있지만 run-time에서 발생하는 오류는 잡을 수 없기 때문에 예상치 못하게 프로그램이 비정상적으로 종료될 수 있다. 예외를 발생시키는 주요 원인은 다음과 같다.

- 운영체제 문제 (잘못된 시스템 호출)
- 입력값 문제 (존재하지 않는 파일 읽기 혹은 숫자 입력해야 하는데 문자입력 등)
- 받아들일 수 없는 연산 (0으로 나누기 등)
- 메모리 할당 실패 및 부족
- 컴퓨터 기계 자체의 문제 (전원 문제, 망가진 기억 장치 등)

위와 같이 프로그램 실행 중 발생할 수 있는 예외에 대비해야 하는데 이를 예외 처리라고 한다. 예외처리를 하는 방법은 예외가 발생할 수 있는 코드와 이에 대한 처리를 try ~ catch 문으로 감싸놓는 것이다. try 블록에서 예외가 발생 시 catch 블록에서 해당 예외를 처리하는 방식이다.


try{
  예외 발생 가능한 문장
}
catch(e: Exception){
  예외 처리 문장
}
finally{
  try블록의 예외 발생 여부와 상관없이 반드시 실행되어야 하는 문장
}

finally는 try에서 예외 발생 여부와 무관하게 무조건 수행되어야 하는 문장을 작성한 곳이다. 예로 try문에서 "파일 열기"를 작성했다면 finally에서는 "파일 닫기"를 수행해야 한다. 다만 finally 블록은 생략하고 try ~ catch 블록만 작성해도 된다. catch 문장에서 e: Exception에서 Exception은 모든 예외를 가리킨다. 일반적으로는 모든 예외를 가리키는 것 보다 세부적으로 예외를 처리하는 것이 바람직하다.



특정 예외 처리

앞에서 처럼 e: Exception 이렇게 아주 광범위한 예외처리가 아닌, 특정 예외 처리를 해보자. 예로 산술 연산에서 발생할 수 있는 예외를 처리해보자. 이 경우 ArithmeticException을 사용할 수 있다.


try{
  ...
}catch(e: ArithmeticException){
  println(e.message) // 예외 원인을 간단히 출력해 줌 
}


스택 추적하기

e.message를 이용해서 예외가 일어난 원인을 간단히 알 수 있지만, 보다 자세히 알고 싶다면 스택을 추적하면 된다. e의 멤버 메서드인 printStackTrace()를 사용하면 어떤 Exception이 일어난건지 예외 클래스, 오류가 발생한 코드의 줄까지 확인할 수 있다.


try{
  ...
}catch(e: Exception){
  e.printStackTrace()
}


예외 발생시키기

앞에서는 계속 예외를 "처리" 하는데 집중했다면, 이제는 의도적으로 예외를 발생시키는 방법을 알아보자. 이때는 throw 키워드를 사용해 의도적으로 예외를 발생시킬 수 있다.


throw Exception(message: String)

다음 예시에선 잔고가 1000원 이하일 때 예외를 발생시키고 있다.

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("잔고가 1000원 이하입니다.")
  }
}

결과는?! 다음과 같다. checkAmount 함수에서 Exception이 발생되어 e.message가 출력된 것을 확인할 수 있다.

잔고가 1000원 이하입니다.
amount: 500


사용자 정의 예외

Kotlin에서는 IOException, ClassNotFoundException 등 많은 예외 클래스를 이미 제공하고 있으며, 이들은 Throwable 클래스의 자식 클래스이다.


기본적인 Exception 클래스로부터 사용자가 새롭게 예외 클래스를 정의할 수 있다. 아래 코드는 <사용자 예외 클래스 이름>이 Exception 클래스를 상속받아서 새로운 예외 클래스를 만드는 예시 코드이다. 사용자 예외 클래스 이름 뒤에 message를 넘겨서 부모 클래스인 Exception 클래스에 해당 message를 전달하고 있다.


class <사용자 예외 클래스 이름>(message: String) : Exception(message)

한 가지 예시를 보자. 이름을 검사해서 문자 이외에 숫자가 들어 있으면 예외를 발생시키는 코드이다.


class InvalidNameException(message: String): Exception(message) // 사용자 예외 클래스

fun main(){
  var name = "Soeun123"
  
  try{
    validateName(name)
  }catch(e: InvalidNameException){ //사용자가 정의한 예외 처리
    println(e.message)
  }catch(e: Exception){ //기타 예외 처리
    println(e.message)
  }
}

fun validateName(name: String){
  if(name.matches(Regex(".*\\d+.*"))){
    throw InvalidNameException("contains numerals")
  }
}

위의 코드 에서는 InvalidNameException 이라는 사용자 정의 예외 클래스를 생성했다. 이후 Soeun123이라고 예외를 발생시킬 문자열을 try 문에서 처리하고 있다. validateName 함수에서 정규식을 이용해 검사했을 때, 숫자가 포함되므로 InvalidNameException을 throw하고 있다. 이에 catch문이 실행된다. 또한, catch문은 Exception 종류에 따라 예시와 같이 여러개를 선언할 수 있다.


사실 내용 자체는 간단해보이지만... 프로그램의 생명은 예외처리이다. (이미 필자는 최근에 회사에서 수많은 원인 모를 에러를 만나며 어디가 문제인지도 모르는 슬픈 상황에 빠진터라) 배운만큼 써먹어야 하니 예외처리에 공을 들여보자ㅠㅠ



Reference

  • 이것이 안드로이드다 with Kotlin (고돈호 지음, 한빛미디어)
profile
안드로이드 개발자

0개의 댓글