🟨 목 차 🟨
1. 자바에서 매우 중요한 예외
2. try-catch는 짝이다.
2-1. try-catch를 사용하면서 처음에 적응하기 힘든 변수 선언
2-2. finally야 ~ 넌 무슨 일이 생겨도 반드시 실행해야 돼
2-3. 두 개 이상의 catch
2-4. 예외의 종류는 세가지다.
2-4-1. error
2-4-2. runtime exception(이하 런타임 예외)
2-5. 예외들의 상관관계
3. 모든 예외의 할아버지는 java.lang.Throwable 클래스다
3-1. 난 예외를 던질거니까 throw라고 해^^
3-2. 예외의 throws와 throw 정리
4. 자바 예외 처리 전략
◼️ 1. 자바에서 매우 중요한 예외 ◼️
자바에는 예외(Exception)라는 것이 있다. 매우 중요하며 모르면 자바를 모르는 것과 같다고 해도 된다.
자바 개발을 위해서 없으면 안되는, 예외를 생각하지 않고는 안전한 프로그램 개발이 쉽지 않다.
자바에서 예외는 "우리가 예상한, 혹은 예상치 못한 일이 발생하는 것을 미리 예견하고 안전장치를 하는 것"을 말한다.
자바에서는 예상을 했던든, 예상을 하지 않았건, 예외적인 일이 발생하게 되면 "예외"라는 것을 던진다.
[ 예를 들어 null인 객체에 메소드를 호출한다던지, 5개의 공간을 가지는 배열을 만들었는데 6번째 값을 읽으라고 하던지. 등등 ]
◼️ 2. try-catch는 짝이다. ◼️
예외 처리의 예로 배열 범위 박의 범위 값을 읽으려고 할 때의 예외처리 예시를 한번 보자.
[EX]
package part14;
public class ExceptionSample {
public static void main(String[] args) {
ExceptionSample sample = new ExceptionSample();
sample.arrayOutOfBounds();
}
public void arrayOutOfBounds() {
int[] intArray = new int[5];
System.out.println(intArray[5]);
}
}
==> 위의 코드에서 arrayOutOfBounds() 메소드를 보게 되면 배열의 공간은 5개[0,1,2,3,4]인데 5의 위치를 출력했기 때문에 결과값으로 컴파일 오류가 났다.
이와 같은 예외 메시지가 발생하지 않도록 할 수는 없을까?
==> 당연히 이렇게 예외가 발생하지 않도록 개발하는 것이 우선이다. 하지만, 개발하다 보면 배열의 위츠를 매개 변수로 받아서 동적으로 처리해야 하는 경우도 있기 때문에 완벽하게 처리하기는 어렵다. 그렇기에 예외처리를 이용하여 편리하게 코드를 보자.
[EX]
package part14;
public class ExceptionSample {
public static void main(String[] args) {
ExceptionSample sample = new ExceptionSample();
sample.arrayOutOfBounds();
}
public void arrayOutOfBounds() {
try {
int[] intArray = new int[5];
System.out.println(intArray[5]);
}
catch (Exception e) {
// TODO: handle exception
}
}
}
==> 코드를 보게되면 try-catch 블록을 사용했다.
try 뒤에 줄광호로 예외가 발생하는 문장들을 묶어 주고, catch 괄호 안에는 예외가 발생했을 때 처리를 해준다.
[ 반드시 모든 문장을 묶어 줄 필요는 없고, 예외가 발생하는 부분만 묶어주면 된다. ]
[EX]
public void arrayOutOfBounds() {
int[] intArray = new int[5];
try {
System.out.println(intArray[5]);
}
catch (Exception e) {
// TODO: handle exception
}
}
==> 위의 코드를 실행하게 되면 아무것도 출력 되지 않는다.
즉, try-catch의 try 블록 안에서 예외가 발생되면 그 이하의 문장은 실행되지 않고 바로 catch 블록으로 넘어간다.
[EX]
package part14;
public class ExceptionSample {
public static void main(String[] args) {
ExceptionSample sample = new ExceptionSample();
sample.arrayOutOfBounds();
}
public void arrayOutOfBounds() {
int[] intArray = new int[5];
try {
System.out.println(intArray[5]);
}
catch (Exception e) {
System.err.println("Exception occured.");
}
System.out.println("This code must run.");
}
}
Exception occured.
This code must run.
==> 위의 코드에 catch 문에 System.err.println()이 있는데 에러가 났을때 사용하는 출력문이다.
위에 코드의 결과를 분석해보면,
- try 블록 내에서 예외가 발생하지 않을 경우
try 내에 있는 모든 문장이 실행되고 try-catch 문장 이후의 내용이 실행된다. - try 블록 내에서 예외가 발생하는 경우
try 내에서 예외가 발생한 이후의 문장들은 실행되지 않는다.[예외 발생 전까지는 실행된다.]
catch 내에 있는 문장은 반드시 실행되고, try-catch 문장 이후의 내용이 실행된다.
◼️ 2-1. try-catch를 사용하면서 처음에 적응하기 힘든 변수 선언
try-catch를 사용할 때 가장 하기 쉬운 실수가 있다.
==> 바로 변수의 지정이다.
[EX]
package part14;
public class ExceptionVariable {
public static void main(String[] args) {
ExceptionVariable sample = new ExceptionVariable();
sample.checkVariable();
}
public void checkVariable() {
int[] intArray = new int[5];
try {
System.out.println(intArray[5]);
}
catch (Exception e) {
System.out.println(intArray.length);
}
System.out.println("This code must run.");
}
}
5
This code must run.
==> 위의 코드를 실행하면 정상적으로 컴파일도 되고 정상적인 결과가 나온다.
즉, 예상한 대로 예외가 발생해서 intArray의 길이를 출력하고 try-catch 이후의 출력문이 실행되는 결과이다.
그런데 int[] intArray=new[5];를 try 블록 안에 넣어보자.
[EX]
package part14;
public class ExceptionVariable {
public static void main(String[] args) {
ExceptionVariable sample = new ExceptionVariable();
sample.checkVariable();
}
public void checkVariable() {
try {
int[] intArray = new int[5];
System.out.println(intArray[5]);
}
catch (Exception e) {
System.out.println(intArray.length);
}
System.out.println("This code must run.");
}
}
==> int[] intArray=new[5];를 try 블록안에 넣고 실행을 시켰는데 컴파일 오류가 났다.
그 이유는 intArray가 try 블록 안에서 선언되었기 때문에 catch에서는 intArray가 누군지 모르기 때문이다.
이런 문제를 해결하기 위해서 일반적으로 catch 문장에서 사용할 변수에 대해서는 다음과 같이 try 앞에 미리 선언해 놓아야 한다.
◼️ 2-2. finally야 ~ 넌 무슨 일이 생겨도 반드시 실행해야 돼
try-catch 구문에 추가로 붙을 수 있는 블록이 하나 더 있다. 바로 finally이다.
finally란 "드디어, 마침내"의 의미이다. 자바에서 예외처리 할 때의 finally는 "어떠한 경우에도 넌 반드시 실행해~~"라는 의미이다.
[EX]
package part14;
public class FinallySample {
public static void main(String[] args) {
FinallySample sample = new FinallySample();
sample.finallySample();
}
public void finallySample() {
int[] intArray = new int[5];
try {
System.out.println(intArray[5]);
}
catch (Exception e) {
System.out.println(intArray.length);
}
finally {
System.out.println("Here is finally");
}
System.out.println("This code must run.");
}
}
5
Here is finally
This code must run.
==> 결과는 예외가 발생하여 catch 블록이 실행되고(5출력), finally 블록이 실행된 후 try-catch 이후의 문장이 실행된다.
그렇다면 예외가 발생하지 않도록 배열의 위치를 5가 아닌 4로 바꿔보자.[ System.out.printlin(intArray[4]); ]
0
Here is finally
This code must run.
==> 결과값은 위와 같다. 즉, finally 블록은 예외 발생 여부와 상관없이 실행되는 것을 알 고 있다.
그런데 이 finally를 어디다가 쓸 지 의문이 생길 것이다.
==> finally 블록은 코드의 중복을 피하기 위해서 반드시 필요하다. ( 추후에 알게 된다.)
◼️ 2-3. 두 개 이상의 catch
try-catch문을 쓸 때 catch에 Exception e 라고 아무 생각 없이 썼다. 이 catch 블록이 시작되기 전에 있는 소괄호에는 예외의 종류를 명시힌다.
즉, 항상 반드시 Exception e를 사용하는 것이 아니다.
[EX]
package part14;
public class MultiCatchSample {
public static void main(String[] args) {
MultiCatchSample sample = new MultiCatchSample();
sample.multiCatch();
}
public void multiCatch() {
int[] intArray = new int[5];
try {
System.out.println(intArray[5]);
}
catch (ArrayIndexOutOfBoundsException e) {
System.out.println("ArrayIndexOutOfBoundsException occurred");
}
catch (Exception e) {
System.out.println(intArray.length);
}
}
}
ArrayIndexOutOfBoundsException occurred
==> 코드를 보게되면 catch블록이 2개가 있다. 이처럼 try는 한번만 쓰고, catch 블록을 여러개 만들어도 전혀 문제 없다.
catch 블록의 순서는 매우 중요하다. catch 블록은 순서를 따진다. catch 블록을 서로 순서를 바꿔보자.
그렇게 되면 컴파일 오류가 뜬다. Exception의 비밀에 이유가 있다. 아래의 내용을 이해해보면 이해가 된다.
모든 예외의 부모 클래스는 뭘까?
==> 모든 예외의 부모 클래스는 java.lang.Exception 클래스다. [ Exception 클래스는 java.lang 패키지에 선언되어 있기 때문에 별도로 import 할 필요 없다. ]
예외는 부모 예외 클래스가 이미 catch를 하고, 자식 클래스가 그 아래에서 catch를 하도록 되어 있을 경우에는 자식 클래스가 예외를 처리할 기회가 없다.
즉, Exception 클래스가 모든 클래스의 부모 클래스이고, 배열에서 발생시키는 ArrayIndexOutOfBoundsException은 Exception 클래스의 자식 클래스 이기 때문에 절대로 Exception 클래스로 처리한 catch 블록 이후에 선언한 블록이 처리될 일이 없기 때문에 "왜 필요 없는 것을 만들고 그러냐" 라면서 컴파일러가 에러를 던진 것이다.
그러면 뭣하러 catch를 여러개 쓸 수 있게 하냐는 의문이 들 것이다. 아래의 예시를 보면 쓰는 이유를 이해하자.
package part14;
public class MultiCatchSample {
public static void main(String[] args) {
MultiCatchSample sample = new MultiCatchSample();
sample.multiCatch();
}
public void multiCatch() {
int[] intArray = new int[5];
try {
System.out.println(intArray[5]);
}
catch(NullPointerException e) {
System.out.println("NullPointerException occurred");
}
catch (ArrayIndexOutOfBoundsException e) {
System.out.println("ArrayIndexOutOfBoundsException occurred");
}
catch (Exception e) {
System.out.println(intArray.length);
}
}
}
ArrayIndexOutOfBoundsException occurred
여기서의 예외는 NullPointerException라는 예외가 발생하지 않는 예외이고, ArrayIndexOutOfBoundsException이라는 예외가 발생하는 오류이다.
즉, 예외가 발생한 상태에서 catch 블록이 많다면 해당하는 catch 블록은 건너 뛰고 예외 상황에 맞는 catch문이 실행되는것이다.
NullPointerException occurred
==> 만약 intArray를 null로 만든 후 intArray[5]의 값을 출력해보면 결과 값은 위에 처럼 나온다.
왜 이런 결과가 나오는지 잘 생각을 해봐야 한다.
intArray의 5번째 값을 찾는 작업을 하기 전에 해당 객체가 null인지 확인하는 작업을 먼저 할 지, 아니면 5번째 값을 찾는 작업을 생각해봐야한다.
null인 객체를 갖고 작업하면 안되기 때문에 해당 객체가 Null인지 확인하는 작업은 반드시 먼저 선행되어야만 한다.
그렇기에 두번째에 있는 ArrayIndexOutOfBoundsException이 먼저 발생해 버린것이다. [ 예외가 발생해 버리면 나머지 try 블록에 있는 내용은 모두 무시되므로 ArrayIndexOutOfBoundsException이 발생하지 않는다. ]
그렇기에 catch문을 사용할 때에는 Exception 클래스로 catch하는 것을 가장 아래에 추가할 것을 권장
Exception occurred
==> 만약 intArray를 null로 만든 후 intArray[5]의 값을 출력하는 예외에서 NullPointerException의 catch문을 주석 처리하면 마지막에 있는 Exception catch블록이 실행이 된다. 즉, Exception catch블록이 마지막으로 버티고 있기 때문에 예외가 걸러진 것이다.
만약 마지막에 버티고 있는 Exception catch문을 주석처리하면 어떻게 될까?
==> 컴파일 오류가 뜬다. 그 이유는 예외 처리를 할 수 있는 catch블록이 없기때문이다. 즉 try-catch로 묶은 것이 허사가 되면서 예외 로그를 발생시켰다.
[정리]
- try 다음에 오는 catch 블록은 1개 이상 올 수 있다.
- 먼저 선언한 catch 블록의 예외 클래스가 다음에 선언한 catch 블록의 부모에 속하면, 자식에 속하는 catch 블록은 절대 실행될 일이 없으므로 컴파일이 되지 않는다.
- 하나의 try 블록에서 예외가 발생하면 그 예외와 관련이 있는 catch 블록을 찾아서 실행한다.
- catch 블록 중 발생한 예외와 관련있는 블록이 없으면, 예외가 발생되면서 해당 쓰레드는 끝난다. 따라서, 마지막 catch 블록에는 Exception 클래스로 묶어주는 버릇을 들여 놓아야 안전한 프로그램이 될 수 있다.
◼️ 2-4. 예외의 종류는 세가지다.
지금까지 배운 예외로는 Exception, ArrayIndexOutOfBoundsException, NullPointerException 이렇게 3가지이다.
다른 예외에 대해서 세 종류의 예외가 존재하며, 각 예외는 다음과 같다.
- checked exception
- error
- runtime exception 혹은 unchecked exception
각 예외의 구분은 error와 unchecked(runtime) exception을 제외한 모든 예외는 checked exception 이다.
그렇기에 error와 unchecked exception만 알면 된다.
◼️ 2-4-1. error
에러는 자바 프로그램 밖에서 발생한 예외를 말한다.
예를 들어 서버의 디스크가 고장 났다든지, 메인보드가 맛이 가서 자바의 프로그램이 제대로 동작하지 못하는 경우가 여기에 속한다.
오류의 이름이 Error로 끝나면 에러이고, Exception으로 끝나면 예외다.
Error와 Exception으로 끝나는 오류의 가장 큰 차이는 프로그램 안에서 발생했는지, 밖에서 발생했는지 여부이다.
더 큰 차이는 프로그램이 멈추어 버리느냐, 계속 실행 할 수 있느냐의 차이다.
즉, Error는 프로세스에 영향을 주고, Exception은 쓰레드에만 영향을 준다.
[ 추후 쓰레드에서 자세히 다룸 ]
◼️ 2-4-2. runtime exception(이하 런타임 예외)
런타임 예외는 예외가 발생할 것을 미리 감지하지 못했을 때 발생한다. 이 런타임 예외에 해당하는 모든 예외들은 RuntimeException을 확장한 예들이다.
전에 NullPointerException이 발생하는 예제가 있었다. 이 예외를 묶어주지 않는다고 해서 컴파일 할 때 예외가 발생하지 않는다.
하지만 실행시에는 발생할 가능성이 있다. 이러한 예외들을 런타임 예외라고 한다.
==> 컴파일시에 체크를 하지 않기 때문에 unchecked exception이라고도 부른다.
◼️ 2-5. 예외들의 상관관계
==> 예외들의 상관 관계도를 보게 된다면 Exception을 바로 확장한 클래스들이 Checked 예외이며, RuntimeException 밑에 확장되어 있는 클래스들이 런타임 예외들이다. [ 추후에 자세히 ]
◼️ 3. 모든 예외의 할아버지는 java.lang.Throwable 클래스다. ◼️
Exception과 Error의 공통 부모 클래스는 당연히 Object 클래스다. 그리고 공통 부모 클래스가 또 하나 있는데, 바로 java.lang 패키지에 선언된 Thowable 클래스다.
즉, Exception과 Error 클래스는 Throwable 클래스를 상속받아 처리하도록 되어 있다.( 그래서, Exception과 Error를 처리할 때 Throwable로 처리해도 무관하다 )
Trowable의 생성자
- Trowable()
- Trowable(String message)
- Trowable(String message, Throwable cause)
- Trowable(Trowable cause)
==> 생성자의 매개변수로 String, Throwable 객체로 넘겨줄 수 있다.
Throwalbe 클래스에 선언되어 있고, Exception 클래스에서 많이 사용되는 3가지의 메소드
- getMessage() : 예외 메시지를 String 형태로 제공 받는다. 예외가 출력되었을 때 어떤 예외가 발생되었는지를 확인할 때 매우 유용하다. 우리가 이 메시지를 활용하여 별도의 예외 메시지를 사용자에게 보여주려고 할 때 좋다.
- toString() : 예외 메시지를 String 형태로 제공 받는다. 그런데, getMessage() 메소드보다는 약간 더 자세하게, 예외 클래스 이름도 같이 제공한다.
- printStackTrace() : 가장 첫 줄에는 예외 메시지를 출력하고, 두번 째 줄부터는 예외가 발생하게 된 메소드들의 호출 관계(스택 트레이스)를 출력해준다. [ 이 메소드는 개발 할 때에만 사용하기 바란다. 왜냐하면 엄청나게 많은 양의 로그가 쌓이기 때문이다. 따라서 꼭 필요한 곳에만 이 메소드를 사용 할 것을 권장한다.]
[ getMessage()_EX ]
package part14;
public class ThrowableSample {
public ThrowableSample() {
}
public static void main(String[] args) {
int[] intArray=new int[5];
try {
intArray=null;
System.out.println(intArray[5]);
}
catch (Throwable t) {
System.out.println(t.getMessage());
}
}
}
Cannot load from int array because "intArray" is null
[ toString()_EX ]
package part14;
public class ThrowableSample {
public ThrowableSample() {
}
public static void main(String[] args) {
int[] intArray=new int[5];
try {
intArray=null;
System.out.println(intArray[5]);
}
catch (Throwable t) {
System.out.println(t.toString());
}
}
}
java.lang.NullPointerException: Cannot load from int array because "intArray" is null
[ printStackTrace()_EX ] (null 예외)
package part14;
public class ThrowableSample {
public ThrowableSample() {
}
public static void main(String[] args) {
int[] intArray=new int[5];
try {
intArray=null;
System.out.println(intArray[5]);
}
catch (Throwable t) {
// System.out.println(t.toString());
t.printStackTrace();
}
}
}
java.lang.NullPointerException: Cannot load from int array because "intArray" is null
at part14.ThrowableSample.main(ThrowableSample.java:13)
[ printStackTrace()_EX ] (배열 인덱스 범위 예외)
package part14;
public class ThrowableSample {
public ThrowableSample() {
}
public static void main(String[] args) {
int[] intArray=new int[5];
try {
// intArray=null;
System.out.println(intArray[5]);
}
catch (Throwable t) {
// System.out.println(t.toString());
t.printStackTrace();
}
}
}
java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
at part14.ThrowableSample.main(ThrowableSample.java:13)
◼️ 3-1. 난 예외를 던질거니까 throw라고 해^^
지금까지는 예외를 처리하는 방법을 배웠다. 이제부터는 예외를 발생시키는 방법을 알아보자.
[EX]
package part14;
public class ThrowSample {
public static void main(String[] args) {
ThrowSample sample = new ThrowSample();
sample.throwException(13);
}
public void throwException(int number) {
try {
if(number>12) {
throw new Exception("Number is over than 12");
}
System.out.println("Number is " + number);
}
catch(Exception e){
e.printStackTrace();
}
}
}
위의 코드를 보자.
1년 12달을 처리하는 로직이 필요하다고 생각해보자. 메소드의 매개 변수로 13월이 넘어온다면 정상적인 처리가 불가능 할 것이다.
반드시 예외처리를 할 필요는 없지만, 필요에 의해서 "13월이라는 것은 정의도 불가능하니 예외를 발생시킨다"고 정의할 수도 있다.
==> 이러한 상황에서 try 블록 내에서 throw라고 명시한 후 개발자가 예외 클래스의 객체를 생성하면 된다. 그렇게 되면 다른 예외가 발생한 상황과 동일하게 throw한 문장 이후에 있는 모든 try 블록 내의 문장들은, catch 블록으로 이동한다.
즉, 여기서 number가 12보다 크면 예외를 던지고, 그 밑에 출력 문장은 수행되지 않는다.
catch 블록 중에 throw한 예외와 동일하거나 상속 관계에 있는 예외가 있다면 그 블록에서 예외를 처리할 수 있다.(여기서 throw가 예외 처리를 Exception 객체로 보냈다.)
만약 해당하는 예외가 없다면 발생된 예외는 메소드 밖으로 던져버린다. 즉, 다시말해서 예외가 발생된 메소드를 호출한 메소드로 던진다는 의미다.
try-catch 블록을 이용하지 않고 throws로 메소드를 선언하여 예외 처리가 가능하다.[ 사용방법은 implements와 비슷하고, throws 메소드를 이용하여 뒤에 선언할 수 있는 예외 메소드 객체는 여러개 선언 가능하다.]
==> 하지만 개발이 어려워 진다. 왜냐하면 해당하는(예외처리가 있는 메소드)메소드를 호출할때 try-catch 블록으로 그 메소드를 쓰는 메소드에서 try-catch 블록으로 감싸주어야 하거나, 그 메소드를 쓰는 메소드에서 다시 throws 해줘 해당하는 예외 객체를 선언해야하기 때문이다.
[ 주의할점이 throws 메소드를 선언하고 그 뒤에 선언하는 예외 객체와 실제로 사용하는 예외 객체와 일치 시켜야 한다. ]
◼️ 3-2. 예외의 throws와 throw 정리
- 메소드를 선언할 때 매개 변수 소괄호 뒤에 throws라는 예약어를 적어 준 뒤 예외를 선언하면, 해당 메소드에서 선언한 예오기ㅏ 발생했을 때 호출한 메소드로 예외가 전달된다.
만약 메소드에서 두 가지 이상의 예외를 던질 수 있다면, implemetns처럼 콤마로 구분하여 예외 클래스 이름을 적어주면 된다. - try 블록 내에서 예외를 발생시킬 경우에는 throw라는 예약어를 적어 준 뒤 예외 객체를 생성하거나, 생성되어 있는 객체를 명시해준다.
throw한 예외 클래스가 catch 블록에 선언되어 있지 않거나, throws 선언에 포함되어 있지 않으면 컴파일 에러가 발생한다. - cathch 블록에서 예외를 throw할 경우에도 메소드 선언의 throws 구문에 해당 예외가 정의되어 있어야만 한다.
◼️ 4. 내가 예외를 만들 수도 있다고? ◼️
앞에서 배운 Throwable을 직접 상속 받는 클래스는 Exception과 Error가 있다고 했다.
Error와 관련된 클래스는 개발자가 손댈 필요도, 손대어서도 안된다. 하지만 Exception을 처리하는 예외 클래스는 개발자가 임의로 추가해서 만들 수 있다. 단 한가지 조건이 있다. Throwable이나 그 자식 클래스의 상속을 받아야만 한다는 것이다.
[Throwable 클래스의 상속을 받아도 되지만, Exception을 처리하는 클래스라면 java.lang.Exception 클래스의 상속을 받는 것이 좋다.]
예외 클래스가 되기 위한 조건은 예외 관련 클래스를 확장하면 된다.
[EX]
package part14;
public class MyException extends Exception {
public MyException() {
super();
}
public MyException(String message) {
super(message);
}
}
만든 예외 클래스를 사용해 보자.
[EX]
package part14;
public class CustomException {
public static void main(String[] args) {
CustomException sample = new CustomException();
try {
sample.throwMyException(13);
}
catch (MyException mye) {
mye.printStackTrace();
}
}
public void throwMyException(int number) throws MyException {
try {
if(number>12) {
throw new MyException("Number is over than 12");
}
}
catch (MyException e) {
e.printStackTrace();
}
}
}
위의 코드를 보게 되면 우리가 직접 만든 예외를 던지고, catch 블록에서 사용한다. 이코드를 컴파일 및 실행도 문제 없고 예외 메세지도 정상적으로 발생한다,
[ 참고로 MyException을 throw 한다고 명시해 놓았지만 이것을 catch 소괄호에서 MyException으로 선언할 필요가 없다. MyException의 부모 클래스인 Exception 클래스로 catch 소괄호에 선언을 해주어도 된다. ]
이것이 가능한 이유는 MyException이 Exception을 상속을 받지 않았다면 우리가 만든 예외는 사용이 불가하다.
즉, 우리가 예외 클래스라는 것을 임의로 만들 때에는 반드시 Throwable의 직계 자손 클래스들을 상속받아 (extends하여) 만들어야만 한다.
◼️ 4. 자바 예외 처리 전략 ◼️
자바에 예외를 처리할 때에는 표준을 잡고 진행하는 것이 좋다.
위의 사진을 보며 정리해보자.
Exception을 바로 확장한 오른쪽 있는 예외들이 Checked 예외이고, 왼쪽 하단에 RuntimeException을 확장한 예외들이 런타임 예외(혹은 Unchecked 예외)이다.
앞에서 Exception 클래스를 확장하여 나만의 예외 클래스를 만들었다. 그런데, 이 예외가 항상 발생하지 않고, 실행시에 발생활 확률이 매우 높은 경우에는 런타임 예외로 만드는 것이 나을 수도 있다. 즉, 클래시 선언시 extends Exception 대신에 extends RuntimeException으로 선언하는 것이다.
==> 왜냐하면 해당 예외를 throw 하는 메소드를 사용하더라도 try-catch로 묶지 않아도 컴파일시에 예외가 발생하지 않기 떄문이다.
하지만 예외가 발생할 경우 해당 클래스를 호출하는 다른 클래스에서 try-catch로 묶지 않은 메소드를 try-catch 안에 넣어줘야한다.
[ unchecked exception인 RuntimeException이 발생하는 메소드가 있다면, 그 메소드를 호출하는 메소드는 try-catch로 묶어주지 않더라도 문제가 생기지 않지만, 예외가 발생할 확률은 높으므로 try-catch로 묶어준다. ]
try {
// 예외 발생 가능한 코드
} catch(SomeException e) {
// 여기 아무 코드 없음
}
위의 코드처럼 catch 블록을 처리해주는것을 반드시 피해야한다.
==> 왜냐하면 예외가 발생했을 경우 catch문 내에서 아무런 작업을 하지 않기 때문에 문제가 어디서 발생했는지 전혀 찾을 수가 없다.
따라서, 개발 표준을 잡을 때 catch문 내에서 어떻게 처리할지를 명시적으로 선언해 두어야마나 한다. 다시 말해서 catch문에서 로그에 남기는 등의 작업을 하고 예외를 throw를 이용하여 던져 주어야 문제가 발생한 정확한 원인을 찾아야 한다.
[정리]
- 임의의 예외 클래스를 만들 때에는,
반드시 try-catch로 묶어줄 필요가 있을 경우에만 Exception 클래스를 확장한다.
일반적으로 실행시 예외를 처리할 수 있는 경우에는 RuntimeException 클래스를 확장하는 것을 권장한다. - catch문 내에 아무런 작업 없이 공백을 놔두면 예외 분석이 어려워지므로 꼭 로그 처리와 같은 예외 처리를 해줘야만 한다.
'JAVA > 자바의신 1' 카테고리의 다른 글
16장 클래스 안에 클래스가 들어갈 수도 있구나 (0) | 2022.09.12 |
---|---|
15장 String (0) | 2022.09.10 |
13장 인터페이스와 추상클래스, enum (0) | 2022.09.09 |
12장 모든 클래스의 부모 클래스는 Object에요 (1) | 2022.09.08 |
11장 매번 만들기 귀찮은데 누가 만들어 놓은 거 쓸 수 없나요? (0) | 2022.09.08 |