본문 바로가기
c#

[c#] Try Catch 사용법 및 예제

by devjh 2020. 7. 28.
반응형

try catch에 대해 정리합니다.

 

0으로 나누려 했거나, 배열의 인덱스가 벗어났다던가 등등 이러면 예외가 나서

 

try catch에서 잡아야 한다..등등

 

그러나 try catch가 정확히 어디에? 어떤부분이 좋아서 쓰는건지는 잘 와닿지 않습니다.

 

이번게시글에서 try catch의 용도를 확인해보고

 

try catch를 사용해서 예외를 잡는경우와

 

if를 통해 예외를 잡는방법 및 장단점을 확인해보겠습니다.

 

1. 예제

static void Main(string[] args)
{
    int[] myArray = new int[3];
    myArray[0] = 10;
    myArray[1] = 20;
    myArray[2] = 30;

    Console.WriteLine("0~2 사이의 숫자를 입력하세요");
    string a = Console.ReadLine();
    int num = int.Parse(a);
    Console.WriteLine("{0}을 입력하셨습니다.",num);
    Console.WriteLine("{0}번째 배열안에 들어있는 값은 {1}입니다.", num, myArray[num]);

    // 아래의 포문은 무슨일이 있어도 실행시켜야 되는 코드라고 가정하겠습니다.
    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine(i+1);
        Thread.Sleep(100);
    }
}

 

먼저 myArray라는 정수형 배열을 선언해놓고 0,1,2에는 각각 10, 20, 30을 넣겠습니다.

 

그리고 사용자가 입력한 숫자의 배열을 출력하고

 

1부터 10까지 0.1초의 간격으로 출력해준후 프로그램을 종료시키겠습니다.

 

마지막 for문은 꼭 실행되야하는 로직이라고 가정하겠습니다.

 

결과는 잘나옵니다.

 

이제부터 프로그램을 터뜨려보겠습니다.

 

2가지 방식으로 터뜨리고 각각의 예외처리방법과 try catch를 사용한 예외처리방법을 비교해보겠습니다.

 

1. 먼저 0~2 사이의 숫자를 입력하라고했지만 저는 a를 입력해보겠습니다.

 

 

입력 문자열의 형식이 잘못되었습니다 라며 프로그램이 중단됩니다.

 

위치는 21번째줄, int.Parse(a) 구문입니다.

 

문자열을 숫자로 형변환하는데 해당 문자열에 숫자가아닌 a가 들어있으니 프로그램이 터져버렸습니다.

 

아래쪽의 꼭 돌아가야하는 포문도 실행이 안되버립니다.

 

 

 

 

2. 이번에는 0~2사이의 숫자가 아닌 3을 입력해보겠습니다.

 

역시 인덱스가 배열의 범위를 벗어났다고 나오며 터져버리고 꼭 돌아가야하는 포문이 돌아가지 않습니다.

 

 

2. 예외처리하기

static void Main(string[] args)
{
    int[] myArray = new int[3];
    myArray[0] = 10;
    myArray[1] = 20;
    myArray[2] = 30;

    Console.WriteLine("0~2 사이의 숫자를 입력하세요");
    string a = Console.ReadLine();
    int num = -1;

    if (int.TryParse(a,out num))
    {
        Console.WriteLine("{0}을 입력하셨습니다.",num);
        Console.WriteLine("{0}번째 배열안에 들어있는 값은 {1}입니다.", num, myArray[num]);
    }
    else
    {
    	Console.WriteLine("숫자를 입력해주세요");
    }

    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine(i+1);
        Thread.Sleep(100);
    }
}

1. 숫자를 입력하지 않고 문자를 입력한 경우의 예외를 잡아보겠습니다.

 

int.TryParse(string a, out int b)를 사용해서 예외를 잡겠습니다.

 

TryParse는 첫번째 매개변수에 있는값이 숫자라면 형 변환후 두번째 매개변수에 그 값을 저장해주는 기능을 합니다.

 

형변환에 성공하면 True를 실패하면 False를 반환합니다.

 

(out은 c언어의 &와 비슷한 키워드이며 c#의 ref와 기능이 거의 동일합니다만 내부에서 꼭 엑세스해서 값을 지정하겠다는 약속입니다.)

 

이제 문자를 입력해보겠습니다.

이제 숫자를 입력하지 않아도 꼭 타야하는 for문을 타지못하고 프로그램이 죽는경우는 없어졌습니다.

 

 

 

2. 0~2 사이의 숫자를 입력하지 않은 경우의 예외를 잡아보겠습니다.

 

 

static void Main(string[] args)
{
    int[] myArray = new int[3];
    myArray[0] = 10;
    myArray[1] = 20;
    myArray[2] = 30;

    Console.WriteLine("0~2 사이의 숫자를 입력하세요");
    string a = Console.ReadLine();
    int num = -1;

    if (int.TryParse(a,out num))
    {
    	Console.WriteLine("{0}을 입력하셨습니다.",num);
        if (0<=num && num<=2)
        {
            Console.WriteLine("{0}번째 배열안에 들어있는 값은 {1}입니다.", num, myArray[num]);
        }
        else
        {
            Console.WriteLine("배열의 인덱스가 아닌 값을 입력하셨습니다. 0~2사이의 숫자를 입력해주세요");
        }
    }
    else
    {
    	Console.WriteLine("숫자를 입력해주세요");
    }

    for (int i = 0; i < 10; i++)
    {
      Console.WriteLine(i+1);
      Thread.Sleep(100);
    }
}

 

if문으로 0~2 사이의 숫자가 입력됐을때만 해당로직을 타게 하면 됩니다.

 

3을 입력한 결과입니다.

 

 

이제 if문을 통한 예외처리가 완성되었습니다.

 

꼭 타야하는 for문을 타지못하고 프로그램이 죽는경우는 없어졌습니다.

 

즉 예외처리란 예외때문에 프로그램이 터지는걸 막는다고도 볼 수 있습니다.

 

 

static void Main(string[] args)
{
    int[] myArray = new int[3];
    myArray[0] = 10;
    myArray[1] = 20;
    myArray[2] = 30;
    Console.WriteLine("0~2 사이의 숫자를 입력하세요");
    string a = Console.ReadLine();

    try
    {
        int num = int.Parse(a);
        Console.WriteLine("{0}을 입력하셨습니다.",num);
        Console.WriteLine("{0}번째 배열안에 들어있는 값은 {1}입니다.", num, myArray[num]);
    }

    catch
    {

    }

    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine(i+1);
        Thread.Sleep(100);
    }
}

 

맨처음 코드에서 예외로인해 프로그램이 터지는부분을 try블럭 안에 넣었습니다.

 

이제 아까처럼 고의로 예외를 내보겠습니다.

 

 

이제 프로그램이 터지지않고 꼭 실행되야하는 for문이 돌아가는걸 확인할 수 있습니다.

 

catch블럭에 몇가지를 추가하면 무슨예외가 어디서 발생했는지도 확인할 수 있습니다.

 

catch 구문을 아래처럼 바꾸어 보겠습니다.

 

catch(Exception e)
{
    Console.WriteLine(e.Message);
}

 

 

무슨예외가 발생했는지를 알려줍니다.

 

마찬가지로 catch문안에 Console.WriteLine(e.StackTrace); 를 추가해보겠습니다.

 

 

이처럼 catch문 블락에 예약어들을 추가하면

 

무슨예외가 터졌는지 어디서 터졌는지도 확인도 가능합니다.

 

마지막으로 try, catch문 밑에 finally문을 사용하는 경우가 많습니다.

 

finally블럭에서는 try블럭이나 catch문이 모두 실행되고 난 후에 실행되야하는 로직을 넣으시면 됩니다.

 

보통 catch문에서 예외의 원인과 위치를 저장하고 catch문과 finally문에서 더이상 필요없는 메모리를 해제하거나

 

try문에서 사용중이던 자원을 초기화 해서 프로그램이 정상적으로 돌 수 있게 제어 하곤 합니다.

 

 

모든 메서드 내부를 try로 둘러쌓아놓으면 프로그램이 뻗을일이 없어보입니다.

 

당연히 이렇게하면 안됩니다. 불필요한 try catch는 성능저하의 원인입니다.

 

위의 예제처럼 단순한 케이스는 try catch를 사용하지않고 직접 if문을 사용하는게 보편적입니다.

 

그러나 socket, file, sql, stream 등 무슨예외가 어디서 언제 어떻게 터질지 불확실해 처리하기 어려운 경우에는 try catch로 잡고 catch문에서 해당 리소스들을 해제시켜주는 것이 일반적입니다.

반응형

댓글