![[C#] 예외처리 Try - Catch / Throw & Finally](https://img1.daumcdn.net/thumb/R750x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLHo1s%2FbtrMmgCyDyG%2FJBsHkExdBYAXtKNeEVnkRk%2Fimg.png)
일들이 계획한대로 흘러가지않아 다른 계획들을 실행하지 못했다.
하지만 그래도 공부는 꾸준히 해줘야 하기에 오랜만에 예외처리에 대해 공부를 해봤다.
포트폴리오를 만들면서 try - catch를 쓴적은 없지만 다이렉트x를 살짝 배울때 C++에서 사용했었다.
오류가 나더라도 프로그램이 멈추지 않고 실행하게끔 만든다던지,
상황에 맞게 설정해둔 오류들을 로그로 찍어 어떤 문제가 있는지 파악해서 해결한다던지 쓰일 부분은 정말 많아보였다.
Try - Catch
너무 쉬운 영어 단어지만 얘기해보자면 시도하다 - 잡다 라는 뜻을 가지고 있다.
시도를 해서 예외를 던지면 그 예외를 잡아서 처리하는 단순한? 방식이라고 생각이 든다.
사용할때는 아래와 같이 써주면 된다.
try
{
//실행 하려는 코드
}
catch(예외)
{
//예외가 발생했을때 실행 할 코드
}
static void Main(string[] args)
{
int[] test = { 3, 5, 6 };
try
{
for(int i=0;i<test.Length+1;i++)
{
Console.WriteLine(test[i]);
}
}
catch(IndexOutOfRangeException e)
{
Console.WriteLine(e.Message);
}
}
간단한 코드를 만들어봤다.
test라는 3개의 요소가있는 배열을 선언하고,
try절의 코드 블록 안에는 for문을 길이보다 한번 더 돌게 끔 만들었다.
그리고 catch에서 잘못된 인덱스를 통해 배열의 요소에 접근할 때 일어나는 IndexOutOfRangeException예외를 받게끔 처리했다.
실행을 해보면 3번째 요소까지 출력을하고 예외를 던지고 종료가 된다.
만약 try-catch가 없다면 예외가 처리되지 않았다는 오류가 나타난다.
System.Exception
C#에서 Exception 클래스는 모든 예외의 조상 클래스이다.
우리가 사용했던 IndexOutOfRangeException을 파고 들어가본다면SystemException을 상속받고 있으며
SystemException은 Exception을 상속받고 있는것을 볼 수 있다.
그렇기 때문에 위에서 사용한 IndexOutOfRangeException 을 대신해서 조상 클래스인 Exception을 사용해도 똑같은 결과가 나온다.
class MainApp
{
static void Main(string[] args)
{
int[] test = { 3, 5, 6 };
try
{
for(int i=0;i<test.Length+1;i++)
{
Console.WriteLine(test[i]);
}
}
catch(Exception e) // Exception으로 변경!
{
Console.WriteLine(e.Message);
}
}
}
그렇다면 catch에서 Exception클래스 하나만 사용해도 될까?
하나하나 예외를 정하지 않고 Exception 클래스로 예외를 받는다면 너무나도 편하다.
하지만 우리가 예상하지 못한 예외들까지 전부 받기때문에 , 작업에 있어서 조심할 필요가 있다.
내가 공부한 책에는 ' 그 예외가 현재 코드가 아닌 상위 코드에서 처리해야 할 예외라면, 이코드는 예외를 처리하는 대신 버그를 만들고 있는 셈이 됩니다.' 라고 얘기를 하고 있는데, 예외처리를 많이 해보지 않아서 아직 확 와닿지는 않는다.
Exception 클래스 (System) | Microsoft Learn
마소 도큐먼트에는 여러가지의 예외들을 설명한 자료가 있으니 섬세한 작업을 위해 살펴두면 좋을 것 같다.
Throw
예외를 던지고 잡는다는 표현을 한다.
말 그대로 Throw는 예외를 던지는 일이다.
받는 숫자가 짝수여야만 잘 작동하는 프로그램이 있다고 가정을 하고 코드를 만들어봤다.
static void Main(string[] args)
{
int[] test = { 2, 4, 7 };
try
{
for(int i=0;i<test.Length;i++)
{
if(test[i] % 2 == 0)
{
Console.WriteLine("정상입니다.");
}
else
{
throw new Exception("짝수가 아니므로 오류입니다.");
}
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
짝수라면 정상이라는 메세지를 찍어 주었고,
아니라면 throw를 이용해 예외를 던져주었다.
Exception 클래스를 살펴보면 여러가지 생성자가 있는데,
어떤 오류인지 메세지를 담을 수 있는 생성자를 사용해 예외를 던졌다.
7은 짝수가 아니기 때문에 예외 메세지를 찍고 프로그램이 정상 종료되었다.
Finally
Finally는 예외이건 예외가 아니던간에 코드를 무조건 실행시켜주는 역할을 담당한다.
try
{
//실행 할 코드
}
catch(예외)
{
//예외가 발생했을때 실행 할 코드
}
finally
{
//무조건 실행 할 코드
}
난 어떤 상황일때 써야할지 아직 감이 잡히지는 않지만,
내가 공부한 책에 설명에는 데이터베이스 연결을 해제하는 예시를 들었다.
데이터베이스 연결 해제는 try에서 코드 실행에 성공을 할때도 필요하고, 예외가 발생돼서 catch절 안의 코드블록이 실행되더라도 실행이 되어야 하는 코드이다.
중복 코드로 try , catch의 모든 예외들에 전부 데이터베이스를 해제하는 코드들을 넣어줄것이 아니라 finally 안에 넣어주면 끝나는 일이다.
throw를 테스트 해볼때와 비슷한 메서드를 만들어 보았다.
정상적으로 실행되거나 예외가 발생하고 나서 마지막에는 "프로그램 종료" 라는 문구를 찍게 만들었다.
public static void Test(int[] a)
{
try
{
for(int i = 0; i < a.Length; i++)
if (a[i] % 2 == 0) //짝수라면 정상이라는 문구 찍기
{
Console.WriteLine("정상입니다.");
}
else //짝수가 아니면 오류 던지기
{
throw new Exception("짝수가 아니므로 오류입니다.");
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally //마지막에 실행 할 코드
{
Console.WriteLine("프로그램 종료");
}
}
마지막에 "프로그램 종료" 라는 메세지를 잘 찍어내는 것을 볼 수 있다.
fianlly는 리턴을 하더라도 무조건 실행된다.
예시 코드를 만들기 위해 위 함수의 반환 타입을 bool 타입으로 바꿔서 작성해봤다.
public static bool Test(int[] a)
{
try
{
for(int i = 0; i < a.Length; i++)
if (a[i] % 2 == 0)
{
Console.WriteLine("정상입니다.");
}
else
{
throw new Exception("짝수가 아니므로 오류입니다.");
}
return true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return false;
}
finally
{
Console.WriteLine("프로그램 종료");
}
}
try , catch 의 어떤 코드가 실행되더라도 리턴이 되는데 과연 finally안의 코드는 어떻게 작동할까?
리턴에 상관없이 finally안의 코드가 잘 작동되는것을 볼 수 있다.
만약 finally 안에서 예외가 일어난다면?
- 따로 예외 처리를 해두지 않았다면 당연히 처리되지 않은 예외가 된다.
finally안에도 try-catch를 통해 예외처리가 가능하다.
When으로 예외 필터하기
switch 문에서 when으로 조건을 한번 더 걸었던것처럼 catch에서도 when을 통해 예외 필터가 가능하다.
static void Main(string[] args)
{
int[] test = { 2, 4, 7 };
try
{
for (int i = 0; i < test.Length; i++)
if (test[i] % 2 == 0)
{
Console.WriteLine("정상입니다.");
}
else
{
throw new Exception("짝수가 아니므로 오류입니다.");
}
}
catch (Exception e) when (test.Length > 10) // 필터 걸기
{
Console.WriteLine(e.Message);
}
}
위와 비슷한 코드에 catch 절에서 배열의 길이가 10 이상일때만 예외를 받게끔 코드를 작성했다.
현재 test의 배열 길이는 3이기 때문에 조건에 부합하지 않는다.
실행을 시켜보면 예외를 던졌지만 catch에서 받지 못하는 것을 볼 수 있다.
Throw 식
throw 는 보통 문(statement)로 사용하지만, C# 7.0 부터는 식(expression)으로도 사용 가능하다.
전에 포스팅한 스위치 문과 식의 차이와 비슷하다.
static void Main(string[] args)
{
string a = null;
try
{
string b = a ?? throw new Exception("널 오류");
Console.WriteLine(b);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
Null 병합 연산자 ?? 를 통해 throw 식을 만들었다.
a가 널이 아니라면 a를 그대로string b에 넣고, 널이라면 ?? 뒤의 코드를 실행하거나 넣는다.
a는 널이기 때문에 예외를 던지는 것을 볼 수 있다.
예외처리를 위한 try-catch를 간단하게 공부해봤다.
개인적으로는 서버쪽에 많이 쓰일거같은 느낌이긴 하지만 , 알아두면 좋을 내용 같다.
'프로그래밍 공부 > C# 프로그래밍' 카테고리의 다른 글
델리게이트와 이벤트(Delegate & Event) (1) | 2023.03.21 |
---|---|
[C#] re-throw? 그리고 throw vs throw EX (2) | 2022.09.18 |
[C#] 프로퍼티란? & 자동구현 프로퍼티와 public 변수와의 차이 찾아보기 (0) | 2022.08.24 |
[C#] 메소드 오버로딩,가변 개수의 인수, 명명된 인수, this() 생성자 (0) | 2022.08.24 |
[C#] ref 와 out 매개변수 한정자 (0) | 2022.08.24 |
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!