throw와 throw new Exception ()의 차이점


164

차이점은 무엇입니까

try { ... }
catch{ throw } 

try{ ... }
catch(Exception e) {throw new Exception(e.message) } 

두 번째 메시지에 상관없이?


51
두 번째 스 니펫은 내가 본 것 중 가장 악의적이지만 무해한 코드 라인 중 하나입니다.
Saks

답변:


259

throw; 원래 예외를 다시 발생시키고 원래 스택 추적을 유지합니다.

throw ex;원래 예외를 throw하지만 스택 추적을 재설정하여 catch블록 까지 모든 스택 추적 정보를 삭제합니다 .


절대 쓰지 마throw ex;


throw new Exception(ex.Message);더 나빠요 Exception예외의 원래 스택 추적과 유형을 잃어 버린 새로운 인스턴스를 만듭니다 . (예 :) IOException.
또한 일부 예외에는 추가 정보 (예 :)가 ArgumentException.ParamName있습니다.
throw new Exception(ex.Message); 이 정보도 파괴됩니다.

경우에 따라 예외가 발생했을 때 코드가 수행 한 작업에 대한 추가 정보를 제공 할 수 있도록 모든 예외를 사용자 정의 예외 오브젝트로 랩핑 할 수 있습니다.

이렇게하려면 상속을하는 새로운 클래스를 정의 Exception, 네 예외 생성자를 추가 및 소요 선택적으로 추가 생성자 InnerException추가 정보뿐만 아니라,하고, 새로운 예외 클래스를 던져 통과 ex는 AS InnerException매개 변수 . original를 전달하면 InnerException스택 추적을 포함하여 모든 원래 예외 속성이 유지됩니다.


24
"새로운 예외를 던진다 (ex); 더 나쁘다.": 나는 이것에 동의하지 않는다. 때로는 예외 유형을 변경하고 원래 예외를 내부 예외로 유지하는 것이 최선의 방법 일 수 있습니다. 하지만 그것은해야 throw new MyCustomException(myMessage, ex);물론.
Dirk Vollmar

9
동일한 0xA3 @ : 나는 의미 ex.Message하는 것입니다 악화.
Saks

6
표준 생성자를 구현하는 것 외에도 사용자 지정 예외를 만들어야 [Serializable()]합니다.
Dirk Vollmar

21
Yo dawg, 우리는 예외를 좋아하므로 예외를 예외로 처리하여 잡는 동안 잡을 수 있습니다.
다스 대륙

2
@SLaks : throw;예외가 발생한 실제 줄 번호가 줄 번호로 바뀝니다 throw;. 어떻게 처리 할 것을 제안합니까? stackoverflow.com/questions/2493779/…
Eric J.

34

첫 번째는 원래 스택 추적을 유지합니다.

try { ... }
catch
{
    // Do something.
    throw;
}

두 번째는 예외 유형 및 / 또는 메시지 및 기타 데이터를 변경할 수 있습니다.

try { ... } catch (Exception e)
{
    throw new BarException("Something broke!");
}

내부 예외를 전달하는 세 번째 방법도 있습니다.

try { ... }
catch (FooException e) {
    throw new BarException("foo", e);
} 

다음을 사용하는 것이 좋습니다.

  • 첫 번째는 정보를 파괴하거나 오류에 대한 정보를 추가하지 않고 오류 상황에서 일부 정리를 수행하려는 경우입니다.
  • 세 번째는 오류에 대한 추가 정보를 추가하려는 경우입니다.
  • 두 번째는 신뢰할 수없는 사용자로부터 정보를 숨기려는 경우입니다.

6

다른 사람이 보지 못한 한 가지 다른 점은 다음과 같습니다.

catch {} 블록에서 아무 것도하지 않으면 try ... catch를 갖는 것은 의미가 없습니다. 나는 항상 이것을 본다 :

try 
{
  //Code here
}
catch
{
    throw;
}

또는 더 나쁜 :

try 
{
  //Code here
}
catch(Exception ex)
{
    throw ex;
}

최악의 경우 :

try 
{
  //Code here
}
catch(Exception ex)
{
    throw new System.Exception(ex.Message);
}

finally 절이 없으면 동의합니다.
토니 로스 만

1
@ToniRossmann이 경우에는 throw 이외의 다른 작업을 수행하지 않는 한 try..final을 catch없이 사용합니다.
JLWarlow

4

throw발견 된 예외 throw new Exception의 세부 사항 중 일부 를 잃으면 서 스택 추적을 유지하면서 발견 된 예외를 다시 발생시킵니다.

일반적으로 throw그 시점에서 예외를 완전히 처리하지 않고 자체적으로 예외를 기록합니다.

BlackWasp에는 C #에서 Throwing Exceptions 라는 제목의 기사가 있습니다.


4

새로운 예외를 던지면 현재 스택 추적이 사라집니다.

throw;원래 스택 추적을 유지하며 거의 항상 더 유용합니다. 해당 규칙의 예외는 사용자 정의 예외에서 예외를 래핑하려는 경우입니다. 그런 다음 수행해야합니다.

catch(Exception e)
{
    throw new CustomException(customMessage, e);
}

3

throw발견 된 예외를 다시 발생시키기위한 것입니다. 이는 호출 체인을 전달하기 전에 예외로 무언가를 수행하려는 경우 유용 할 수 있습니다.

throw인수없이 사용하면 디버깅 목적으로 호출 스택이 유지됩니다.


0

원하는 경우 원래 예외를 내부 예외로 설정하여 새 예외를 throw 할 수 있습니다.


0

두 번째 예는 예외의 스택 추적을 재설정합니다. 첫 번째는 예외의 기원을 가장 정확하게 유지합니다. 또한 실제로 잘못 된 것을 아는 데 핵심적인 원래 유형의 포장을 풀었습니다 ... 기능에 두 번째가 필요한 경우-예를 들어 확장 정보를 추가하거나 사용자 정의 'HandleableException'과 같은 특수 유형으로 다시 줄 바꿈하려면 InnerException 속성도 설정되어 있는지 확인하십시오!


네, 이것은 당신이 빨리 써야하는 질문 중 하나입니다. ;)
Robert Harvey

0

가장 중요한 차이점은 두 번째 표현식이 예외 유형을 지우는 것입니다. 예외 유형은 예외를 포착하는 데 중요한 역할을합니다.

public void MyMethod ()
{
    // both can throw IOException
    try { foo(); } catch { throw; }
    try { bar(); } catch(E) {throw new Exception(E.message); }
}

(...)

try {
    MyMethod ();
} catch (IOException ex) {
    Console.WriteLine ("Error with I/O"); // [1]
} catch (Exception ex) {
    Console.WriteLine ("Other error");    // [2]
}

경우 foo()가 발생 IOException, [1]catch 블록은 예외를 잡을 것입니다. 그러나 bar()던질 때 캐치 블록에 잡히지 않는 IOException일반 Exception개미 로 변환됩니다 [1].


0

던지기 또는 던지기 ex는 단순히 오류 정보를 기록하고 호출자에게 정보를 다시 보내지 않으려는 경우 예외를 던지거나 다시 던지는 데 사용됩니다. 그러나 throw 또는 throw ex를 사용하는 호출자에게 예외에 대한 의미있는 정보를 보내려는 경우를 대비하십시오. 이제 throw와 throw ex의 차이점은 throw는 스택 추적과 다른 정보를 유지하지만 throw ex는 새로운 예외 객체를 생성하여 원래 스택 추적이 손실된다는 것입니다. 따라서 throw and throw e를 사용해야하는 경우에도 여전히 호출 스택 정보를 재설정하는 것과 같은 예외를 다시 발생시켜야하는 상황이 몇 가지 있습니다. 예를 들어, 메소드가 라이브러리에 있고 호출 코드에서 라이브러리의 세부 사항을 숨기려면 호출 스택에 라이브러리 내의 개인용 메소드에 대한 정보를 포함시키지 않아도됩니다. 이 경우 라이브러리의 공개 메소드에서 예외를 포착 한 다음 다시 호출하여 호출 스택이 해당 공개 메소드에서 시작되도록 할 수 있습니다.


0

던지다; 원래 예외를 다시 발생시키고 예외 유형을 유지하십시오.

새로운 예외를 던지십시오 (); 원래 예외 유형을 다시 발생시키고 예외 스택 추적을 재설정하십시오.

전 던져; 예외 스택 추적을 재설정하고 예외 유형을 재설정하십시오.


-1

여기에 어떤 대답도 차이를 보여주지 않으므로 차이를 이해하는 데 어려움을 겪는 사람들에게 도움이 될 수 있습니다. 이 샘플 코드를 고려하십시오.

using System;
using System.Collections.Generic;

namespace ExceptionDemo
{
   class Program
   {
      static void Main(string[] args)
      {
         void fail()
         {
            (null as string).Trim();
         }

         void bareThrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw;
            }
         }

         void rethrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw e;
            }
         }

         void innerThrow()
         {
            try
            {
               fail();
            }
            catch (Exception e)
            {
               throw new Exception("outer", e);
            }
         }

         var cases = new Dictionary<string, Action>()
         {
            { "Bare Throw:", bareThrow },
            { "Rethrow", rethrow },
            { "Inner Throw", innerThrow }
         };

         foreach (var c in cases)
         {
            Console.WriteLine(c.Key);
            Console.WriteLine(new string('-', 40));
            try
            {
               c.Value();
            } catch (Exception e)
            {
               Console.WriteLine(e.ToString());
            }
         }
      }
   }
}

다음과 같은 출력이 생성됩니다.

Bare Throw:
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
   at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
   at ExceptionDemo.Program.<>c.<Main>g__bareThrow|0_1() in C:\...\ExceptionDemo\Program.cs:line 19
   at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64

Rethrow
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
   at ExceptionDemo.Program.<>c.<Main>g__rethrow|0_2() in C:\...\ExceptionDemo\Program.cs:line 35
   at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64

Inner Throw
----------------------------------------
System.Exception: outer ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
   at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 43
   --- End of inner exception stack trace ---
   at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 47
   at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64

이전 답변에서 알 수 있듯이 베어 스로우는 실패한 원래 코드 줄 (12 행)과 예외가 발생했을 때 호출 스택에서 활성화 된 다른 두 지점 (행 19 및 64)을 명확하게 보여줍니다.

다시 던지기 사례의 결과는 왜 문제인지 보여줍니다. 이와 같이 예외가 다시 발생하면 예외에는 원래 스택 정보가 포함되지 않습니다. 만 유의 throw e(라인 35) 및 최 호출 스택 포인트 (라인 64)가 포함된다. 이런 식으로 예외를 throw하면 fail () 메서드를 문제의 원인으로 추적하기가 어려울 수 있습니다.

마지막 경우 (innerThrow)는 가장 정교하며 위의 것보다 많은 정보를 포함합니다. 새 예외를 인스턴스화하고 있으므로 컨텍스트 정보 ( "외부"메시지를 추가 할 수 있지만 새 예외의 .Data 사전에 추가 할 수 있음)를 추가하고 원본의 모든 정보를 보존 할 수 있습니다. 예외 (도움말 링크, 데이터 사전 등 포함).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.