예외(Exception)
컴퓨터에서 일어나는 에러는 2가지가 있다.
첫째는 코드를 작성할 때 발생하는 컴파일 에러(compile error)
둘째는 프로그램 실행 중에 발생하는 런타임 에러(run-time error)
첫째 경우는 코드를 입력하는 사람이 잘못 입력하면 편집기 등에서 문제가 있는 부분을 대부분 알려주므로 어디가 잘못인지 파악하는 것이 어렵지는 않다.
둘째 경우는 프로그램을 실행(run)할 때 생기는 런타임 에러인데 이 경우도 컴퓨터가 예상하지 못한 에러와 프로그램 내에서 예상할 수 있는 에러로 나눌 수 있다.
런타임 중 프로그램 내에서 일어나는 예상할 수 있는 에러를 예외(Exception)이라고 한다.
C#에는 이런 Exception(예외)이 발생하면 프로그램을 멈추고 그것을 처리하는 체계를 가지고 있다.
C#에는 예외에 대해서는 System.Exception 클래스에 정의하고 있는데 다양한 예외들 중 대표적인 것은 다음과 같다.
- 배열에서 인덱스에 없는 것을 참조할 때 발생시키는 IndexOutOfRangeException
- 입출력 에러가 났을 때 발생시키는 IOException
- null객체를 참조하면 발생시키는 NullReferenceException
- 0 으로 나누는 시도가 있을 때 발생시키는 DivideByZeroException
- 메모리가 부족할 때 발생시키는 OutOfMemoryException
- 타입 캐스팅에서 발생하는 에러가 있을 때 발생시키는 InvalidCastException
- 배열 타입이 맞지 않을 때 발생시키는 ArrayTypeMismatchException
- Stack(스택) 영역의 메모리가 지정된 범위를 초과할 때 발생시키는 StackOverflowException
예제1
Exception이 발생하도록 코드를 작성해서 실제로 어떻게 나타나는 지 확인해보자.
위와 같은 스크립트를 만든다.
배열(Array)을 만들고 for반복문으로 배열 값을 모두 더해서 합(sum)을 계산하는 코드이다.
그런데 배열의 요소(element) 수는 3 이고, index(인덱스) 번호는 0, 1, 2 인데 for 반복문 조건에서 인덱스 번호를 0, 1, 2, 3 으로 잘못 설정했다.
유니티로 출력하면 다음과 같은 예외를 발생시킨다.
IndexOutOfRangeException : Index was outside the bounds of the array.
인덱스 범위 초과 예외 : 인덱스는 배열의 경계 바깥에 있었다.
그래서 이런 Exception이 발생했을 때, 어떤 식으로 처리하라는 조치를 미리 만들어 두는 방법들이 있다.
try-catch-finally
*try : 시도하다
*catch : 잡다
*finally : 마지막으로, 최종적으로
위의 코드와 같이 예외가 생길 수 있는 경우에 try, catch, finally 키워드를 사용해서 예외를 처리할 수 있다.
- try는 예외가 발생할 가능성이 있는 코드를 묶는다. (캡슐화)
- catch는 예외가 발생할 경우 그것을 잡는다. 그리고 그것을 어떻게 처리할 것인지 적어놓는다. 여러 가지 예외가 발생할 가능성이 있다면 catch블록을 여러 개 만들어 각 상황별로 다르게 처리하도록 만들 수 있다.
- finally는 예외가 생기든, 안 생기든 상관없이 무조건 실행할 코드를 적는다. 그러므로 이 부분을 생략할 수도 있다.
10번 줄에 예외가 생길 가능성이 있는 for반복문을 try와 함께 중괄호로 묶는다.
17번 줄에 catch 로 예외를 잡아낸다. 괄호에는 System.Exception클래스에 있는 예외 타입과 그것을 저장할 변수를 하나 적는다. 여기서는 exception으로 했다. 이 변수명은 보통 첫글자만 따서 e 로 표시하기도 한다.
19번 줄에 예외가 발생했을 때 처리할 내용을 적는다.
여기서는 IndexOutofRangeException클래스에 있는 Message(메세지) 프라퍼티에 정의된 내용을 출력한다.
21번 줄에 예외 발생과 상관없이 실행할 내용을 작성한다.
여기서는 예외가 발생하든, 안하든 sum 값을 출력한다.
스크립트를 저장한 후 실행하면 다음과 같이 출력될 것이다.
첫째는 예외가 발생했으므로 IndexOutofRangeException클래스에서 전달받은 Message가 출력된다.
둘째는 어쨌든 finally에서 14번 코드를 실행한 결과 sum 값 6을 출력한다.
예제2
예를 하나 더 만들어 본다.
13번 줄에 DivideNumber라는 클래스를 만들었다.
*divide : 나누다
15번 줄에 필드 result 를 만든다.
*result : 결과
17번 줄에 생성자를 만든다. 생성자에서 필드를 0으로 초기화한다.
22번 줄에 Division이라는 메서드를 만든다. 매개변수 2개를 가진다.
이 메서드가 호출되면 첫째 매개변수를 둘째 매개변수로 나누어서 필드result에 저장한다.
*division : 나누기, 분할
7번 줄에 클래스 객체를 만들어서 변수 test에 넣는다.
8번 줄에 Division메서드에 인수를 전달한다.
9번 줄에 result값을 콘솔 창에 출력한다.
실행하면 위와 같이 result값 1이 나올 것이다.
그런데 위 코드에서는 8번 줄에서 Division메서드에 인수를 전달할 때 (5, 0) 처럼 0을 입력해서 전달할 가능성이 있다.
위와 같이 인수를 전달하면 아래와 같이 에러가 발생한다.
DivideByZeroException : Attempted to divide by zero.
( 0으로 나누기 예외 : 0으로 나누려고 시도함 )
연산에서 0으로 나누기(divide by 0)는 정의되어 있지 않기 때문에 이런 상황이 생기면 위와 같이 Exception(예외)을 발생시킨다.
이런 경우는 예외가 일어날 가능성을 미리 예측할 수 있기 때문에 try-catch-finally로 미리 예외 발생 시 어떻게 처리할 것인지 잘 대처하도록 준비해 둘 수 있다.
try-catch-finally를 사용해서 예외 처리를 해보자.
먼저 Exception은 네임스페이스 System에 있기 때문에 예외 클래스를 사용하기 위해 using System;을 추가한다.
만약 using System을 사용하지 않으려면 앞에서 System.IndexOutOfRangeException과 같이 'System.예외타입' 형태를 사용하면 된다. 여기서는 using키워드를 사용한다.
예외가 일어날 가능성이 있는 코드가 27번 줄이므로 try { } 로 감싸준다.
30번 줄에서 catch( )로 '예외 타입'을 적고 예외에서 전달받는 내용을 저장할 변수로 exception을 만든다.
32번 줄에서 해당 예외가 일어나면 변수 exception 내용을 콘솔창에 출력하도록 한다.
34번 줄에서 finally{ } 로 예외가 일어나든, 일어나지 않든 간에 실행할 내용을 적는다.
여기서는 result값을 출력하도록 한다.
위와 같이 예외 처리를 한 후 Division메서드 인수로 5와 0을 입력해서 실행해보자.
예외가 발생하여 DivideByZeroException클래스에서 전달 받은 내용이 출력되고 결과에는 result 초기값 0 이 출력된다.
마지막에 나타나는 0은 Debug.Log(test.result) 값이다.
아래와 같이 예외가 발생하지 않는 경우는 finally에서 작성한 내용만 출력한다.
끝.
Wraven...
'취미로 하는 게임코딩_gameCodingAsHobby > 유니티unity로 게임 만들기' 카테고리의 다른 글
유니티41_C#_26_Event 이벤트 (0) | 2021.03.28 |
---|---|
유니티40_C#_25_Delegate 델리게이트 (0) | 2021.03.28 |
유니티38_C#_23_FileStream 파일스트림 (2) | 2021.03.24 |
유니티37_C#_22_Generic 제네릭 (0) | 2021.03.22 |
유니티36_C#_21_Collection 컬렉션 (0) | 2021.03.22 |