일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- ToString
- StringBuffer클래스
- 다형성
- 예외처리
- 람다식
- 객체
- array
- DB
- 상속
- 객체지향
- 커넥션 풀
- Connection
- 에러
- 메서드
- StringBuffer
- File입출력
- for문
- 예외
- 인터페이스
- 입출력
- JSP
- 제어자
- 배열
- Interface
- I/O
- try-catch
- 내장 객체 영역
- java
- 접근제어자
- 변수
- Today
- Total
ksouth9
예외처리(exception handling)(3) 본문
자동 자원 반환 try-with-resources문
try에 리소스(자원)을 선언하고, try 블럭이 끝나면(리소스를 다 사용하고 나면) 자동으로 반납(close)(리소스를 종료)해주는 기능이다.
try(...)문에서 선언된 객체들에 대해서 try가 종료될 때 자동으로 자원을 해제해주는 기능.
주로 입출력에 사용되는 클래스 중에서 사용한 후에 꼭 닫아 줘야 하는 것들이 있다. 그래야 사용했던 리소스가 반환되기 때문이다.
//괄호()안에 두 문장 이상 넣을 경우 ';'로 구분한다.
try (FileInputStream fis = new FileInputStream("score.dat");
DataInputStream dis = new DataInputStream(fis)) {
while (true) {
score = dis.readInt();
System.out.println(scroe);
sum += score;
}
} catch (EOFEXception e) {
System.out.println("점수의 총합은 " + sum +"입니다.");
} catch (IOException ie) {
ie.printStackTrace();
}
try-with-resources문의 괄호()안에 객체를 생성하는 문장을 넣으면, 이 객체는 따로 close()를 호출하지 않아도 try블럭을 벗어나는 순간 자동적으로 close()가 호출된다. 그 다음에 catch블럭 또는 finally블럭이 수행된다.
※try블럭의 괄호()안에 변수를 선언하는 것도 가능하며, 선언된 변수는 try블럭 내에서만 사용할 수 있다.
AutoCloseable은 try에 선언된 객체가 AutoCloseable을 구현했더라면 Java는 try 구문이 종료될 때 객체의 close() 메서드를 호출해준다. AutoCloseable을 구현한 객체만 close()가 호출된다.
public interface AutoCloseable {
void close() throws Exception;
}
AutoCloseable 예시
public class AutoCloseableExample {
public static void main(String[] args) {
try (CustomResource customResource = new CustomResource();){
customResource.doSomething();
} catch (Exception e){
e.printStackTrace();
}
}
}
class CustomResource implements AutoCloseable {
public void doSomething(){
System.out.println("Do something ...");
}
@Override
public void close() throws Exception {
System.out.println("CustomResource Closed!");
}
}//실행결과
Do something ...
CustomResource Closed!
사용자정의 예외 만들기
기존의 정의된 예외 클래스 외에 필요에 따라 프로그래머가 새로운 예외 클래스를 정의하여 사용할 수 있다. 직접 정의하여 사용하는 예외
보통 Exception클래스 또는 RuntimeExcpetion클래스로부터 상속받아 클래스를 만들지만, 필요에 따라서 알맞은 예외 클래스를 선택할 수 있다.
일반 예외로 선언할 경우 - Exception
실행 예외로 선언할 경우 - RuntimeException
class MyException extends Exception {
MyException(String msg) { //문자열을 매개변수로 받는 생성자
super(msg); //조상인 Exception클래스의 생성자를 호출한다.
}
}
Exception클래스로부터 상속받아서 MyException클래스를 만들었다. 필요하다면, 멤버변수나 메서드를 추가할 수 있다. Exception클래스는 생성 시에 String값을 받아서 메시지로 저장할 수 있다. 사용자정의 예외 클래스에도 메시지를 저장하려면, String을 매개변수로 받는 생성자를 추가해주어야 한다.
public class MyException extends Exception {
//에러 코드 값을 저장하기 위한 필드를 추가.
private final int ERR_CODE; //생성자를 통해 초기화 한다.
MyException(String msg,int errCode){ //생성자
super(msg);
ERR_CODE = errCode;
}
MyException (String msg){ //생성자
this(msg,100);
}
public int getErrCode() { //에러 코드를 얻을 수 있는 메서드 추가
return ERR_CODE; //이 메서드는 주로 getMessage()와 함께 사용될 것이다.
}
메시지만 저장하는 것이 아니라 에러코드 값도 저장할 수 있도록 ERR_CODE와 getErrCode()를 MyException클래스의 멤버로 추가했다. 이렇게 함으로써 MyException이 발생했을 때, catch블럭에서 getMessage()와 getErrCode()를 사용해서 에러코드와 메시지를 모두 얻을 수 있을 것이다.
예외던지기(exception re-throwing)
예외를 처리한 후에 인위적으로 다시 발생시키는 방법 '예외 되던지기(exception re-throwing)'
한 메서드에서 발생할 수 있는 예외가 여러개인 경우, 몇 개는 try-catch문을 통해서 메서드 내에서 자체적으로 처리하고, 그 나머지는 선언부에 지정하여 호출한 메서드에서 처리하도록 함으로써, 양쪽에서 나눠서 처리되도록 할 수 있다.
그리고 심지어는 단 하나의 예외에 대해서도 예외가 발생한 메서드와 호출한 메서드, 양쪽에서 처리하도록 할 수 있다.
먼저 예외가 발생할 가능성이 있는 메서드에서 try-catch문을 사용해서 예외를 처리해주고 catch문에서 필요한 작업을 행한 후에 throw문을 사용해서 예외를 다시 발생시킨다. 다시 발생한 예외는 이 메서드를 호출한 메서드에게 전달되고 호출한 메서드의 try-catch문에서 예외를 또다시 처리한다. 이 방법은 하나의 예외에 대해서 예외가 발생한 메서드와 이를 호출한 메서드 양쪽 모두에서 처리해주어야 할 작업이 있을 때 사용된다.
주의할 점은 예외가 발생할 메서드에서는 try-catch문을 사용해서 예외처리를 해줌과 동시에 메서드의 선언부에 발생할 예외를 'throws'에 지정해줘야 한다.
public class ExceptionEx17 {
public static void main(String[] args) {
try {
method1();
} catch( Exception e) {
System.out.println("main메서드에서 예외가 처리되었습니다.");
}
}
static void method1() throws Exception {
try {
throw new Exception();
} catch(Exception e) {
System.out.println("method1메서드에서 예외가 처리되었습니다.");
throw e; //다시 예외를 발생시킨다.
}
}
}
method1()과 main메서드 양쪽의 catch블럭이 모두 수행되었다. method1()의 catch블럭에서 예외를 처리하고도 throw문을 통해 다시 예외를 발생 시켰다. 그리고 이 예외를 main메서드에서 한 번 더 처리하였다.
반환값이 있는 return문의 경우, catch블럭에도 return문이 있어야 한다. 예외가 발생했을 경우에도 값을 반환해야하기 때문이다.
static int method1() {
try {
System.out.println("method1()이 호출되었습니다.");
return 0; //현재 실행 중인 메서드를 종료한다.
} catch (Exception e) {
e.printStackTrace();
return 1; //catch블럭 내에도 return문이 필요하다.
} finally {
System.out.println("method1()의 finally블럭이 실행되었습니다.");
}
}
또는 catch블럭에서 예외 던지기를 해서 호출한 메서드로 예외를 전달하면, return문이 없어도 된다.
static int method1() throws Exception {
try {
System.out.println("method1()이 호출되었습니다.");
return 0;
} catch(Exception e) {
e.printStackTrace();
// return 1; //catch블럭 내에도 return문이 필요하다.
throw new Exception(); //return문 대신 예외를 호출한 메서드로 전달.
} finally {
System.out.println("method1()의 finally블럭이 실행되었습니다.");
}
}
연결된 예외(chained exception)
한 예외가 다른 예외를 발생시킬 수도 있다. 예외 A가 예외 B를 발생시켰다면, A를 B의 '원인 예외(cause exception)라고 한다. 두 가지 예외를 연결하는 것을 연결된 예외라고 부른다.
try {
startInstall(); //SpaceException 발생
copyFiles();
} catch (SpaceException e) {
InstallException ie = new InstallException("설치중 예외발생") //예외생성
ie.initCause(e); //InstallException의 원인 예외를 SpaceException으로 지정
throw ie; //InstallException을 발생시킨다.
} catch (MemoryException me) {
...
먼저 InstallException을 생성한 후에, initCause()로 SpaceException을 InstallException의 원인 예외로 등록한다. 그리고 'throw'로 이 예외를 던진다.
initCause()는 Exception클래스의 조상인 Throwable클래스에 정의되어 있기 때문에 모든 예외에서 사용가능하다.
initCause (Throwable cause) - 지정한 예외를 원인 예외로 등록(두 예외를 연결)
getCause() - 원인 예외를 반환
원인 예외 사용 이유
- 발생한 예외를 원인 예외로 등록해서 다시 예외를 발생시키는 이유는 여러가지 예외를 하나의 큰 분류의 예외로 묶어서 다루기 위함이다.
- checked예외를 unchecked예외로 바꿀 때 사용한다.
'Java' 카테고리의 다른 글
java.lang 패키지(2) (0) | 2022.03.27 |
---|---|
java.lang 패키지(1) (0) | 2022.03.20 |
예외처리(exception handling)(2) (0) | 2022.03.18 |
예외처리(exception handling)(1) (0) | 2022.03.17 |
추상클래스와 인터페이스 차이점 (0) | 2022.03.17 |