[11]JAVA Nam GungSung Class(02 18) chapter 8 예외처리 - Jo-Jun-Yeong/NamGungSung-class GitHub Wiki
ch8-1 프로그램 오류
-
컴파일 에러(compile-time error) : 컴파일 할 때 발생하는 에러
-
런타임 에러(runtime error) : 실행할 때 발생하는 에러
-
논리적 에러(logical error) : 작성 의도와 다르게 동작
-
java 의 런타임 에러
- 에러(error) : 프로그램 코드에의해서 수습될 수 없는 심각한 오류 (OOME...)
- 예외(exception) : 프로그램. 코드에 의해서 수습될 수 있는 다소 미약한 오류
예외처리(exception handling)
(1) 정의 : 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는 것
(2) 목적 : 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것
ch8-3 Exception과. RuntimeException
- Exception 클래스들 : 사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외
- RuntimeException : 프로그래머의 실수로 발생하는 예외
-
IOException : 입출력 예외(In / Out)
-
Class Not Found Exception : 클래스 인식 불가
-
...
-
Run Time Exception
-
ArithmeticException : 산술계산 예외
-
ClassCast : 형변환 예외
-
NullPoint : Null 값 객체의 메소드를 호출 예외
-
... *IndexOutOfBoundsException : 배열. 범위를 벗어난 예외
ch8-4 예외 처리하기, try-catch문의 흐름
예외처리(exception handling)의
- 정의 : 프로그램 실행 시 발생할 수 있는 예외의 발생에 대비한 코드를 작성하는것
- 목적 : 프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는것
ch8-5 try - catch문에서의 흐름
- try블럭 내에서 예외가 발생한 경우.
- 발생한. 예외와 일치하는 catch블럭이 있는지 확인한다
- 일치하는 catch블럭을 찾게 되면, 그 catch블럭 내의 문장들을 수행하고 전체try-catch문을 빠져나가서 그 다음 문장을 계속해서 수행한다. 만일 일치하는 catch블럭을 찾기 못하면, 처리되지 못한다.
catch블럭을 찾지 못해서 예외처리가 되지 못하면 프로그램 비정상종료가된다
- try블럭 내에서 예외가 발생하지 않은 경우.
- catch블럭을 거치지 않고 전체 try - catch문을 빠져나가서 수행을 계속한다.
//예외가 발생하지 않았을 경우
System.out.println(1);
try {
System.out.println(2);
System.out.println();
} catch (Exception e) {
System.out.println(4);
}
//try - catch의 끝
System.out.println(5);
//예외가 발생했을 경우
System.out.println(1);
try {
System.out.println(0/0); //1. 예외발생!!
System.out.println(2); //2. 예외가 발생한 이후의 문장은 실행이 안된다.
} catch (ArithmeticException ae) { // 3.catch문을 수행 후.
System.out.println(3);
}//try - catch의 끝 // 4. try- catch 문 전체를 빠져나간다
System.out.println(4);
ch8-6 예외의 발생과 catch블럭 (예제)
- 예외가 발생하면, 이를 처리할 catch블럭을 찾아 내려감
- 일치하는 catch블럭이 없으면, 예외는 처리 안됨
- Exception이 선언된 catch블럭은 모든 예외 처리(마지막 catch블럭)
System.out.println(1);
System.out.println(2);
try {
System.out.println(3);
System.out.println(0/0); //0으로 나눠서 ArithmeticException을 고의로 발생
System.out.println(4);
} catch (ArithmeticException ae) {
if(ae instanceof ArithmeticException)
System.out.println("true");
System.out.println("ArithmeticException");
} catch (Exception e){ //ArithmeticException을 제외한 모든 예외가 처리된다
// Exception -> 모든 예외의 최고조상 -> 모든 예외 처리 가능
System.out.println("Exception");
} //try - catch 의 끝
System.out.println(6);
ch8-7 PrintStackTrace() 와 getMessage()
- printStackTrace() : 예외발생 당시의 호출스택(Call Stack)에 있었던 메서드의 정보와 예외 메시지를 화면에 출력한다.
- getMessage() : 발생한 예외클래스의 인스턴스에 저장된 메시지를 얻을 수 있다.
//예제
System.out.println(1);
System.out.println(2);
try {
System.out.println(3);
System.out.println(0/0); // 예외 발생
System.out.println(4); // 실행되지 않음
} catch (ArithmeticException ae) {
ae.printStackTrace();
System.out.println("예외 메시지 : "+ ae.getMessage());
} //try - catch 의 끝
System.out.println(6);
} //main메서드
//출력
1
2
3
java.lang.ArithmeticException: / by zero // <- getmessage가 반환된 부분
at Exception_Test.main(Exception_Test.java:10)
예외 메시지 : / by zero
6
ch8-8 멀티 catch 블럭
- 내용이 같은 catch블럭을 하나로 합친 것(JDK1.7부터)
//ex
//같은 catch블럭을 따로
try {
}
catch(ExceptionA e) {
e.printStackTrace();
}
catch(ExceptionB e2) {
e2.printStackTrace();
} //위처럼 같은 제외의 chatch블럭을 하나로합치면
// 같은 catch블럭을 하나로 합친 경우
try {
} catch (ExceptionA | ExceptionB e) {
e.printStackTrace();
}
##주의할 점
- (parentException | childException e)과 같이 부모자식 관계를 묶으면 안된다.
부모타입의 예외면 자식을 굳이 쓸 필요가 없다.
- (ExceptionA | ExceptionB e) 일경우 ExceptionA의 메소드만 호출해서는 안된다.즉 공통된 맴버만 사용 가능하다.
사용하고자하면 if 문을 사용하여 (ExceptionA)e 와 같이 형변환을 해줘야 한다. -> 아예 따로사용할 지언정 굳이 이렇게 사용하지 않는다.
ch8-9 예외 발생시키기
- 연산자 new를 이용해서 발생기키려는 예외 클래스의 객체를 만든다음
Exception e = new Exception("고의로 발생기켰음");
- 키워트 throw를 이용해서 예외를 발생시킨다
throw e;
try {
Exception e = new Exception("고의로 발생시켰음"); // 1. Exception이라는 예외에대한 정보가 담겨있는 객체를 만들고
throw e; // 2. throw를 통해 예외를 발생 시킴
//throw new Exception("고의로 발생시켰음")을 통해 한문장으로 가능
} catch (Exception e) { // 3. 발생한 예외와 catch블럭에 선언된 예외의 와 같으므로 참조변수에 해당 객체의 주소가 담겨짐
System.out.println("dpfjaptlwl : "+ e.getMessage());
e.printStackTrace();
}
System.out.println("프로그램 정상 종료");
} //main메서드
ch8-10 checked예외, unchecked예외
- checked예외 : 컴파일러가 예외 처리 여부를 체크(예외 처리 필수) (Exception과 그 자손)
- unchecked예외 : 컴파일러가 예외 처리 여부를 체크 안함(예외 처리 선택) (RuntimeException과 그의 자손들)
public static void main(String[] args) {
try {
throw new Exception(); // Exception과 그 자손은 컴파일러가 확인을 함으로 try-catch를 써야 에러가 나지 않는다
} catch(Exception e) {}
public static void main(String[] args) {
throw new RuntimeException(); // throw new RuntimeException을 고의로 발생시킨다
//예외처리(try-catch) 가 선택이기떄문에 예외처리를 하지 않아도 컴파일은 된다(오류가 안나는건 아님)
}
오류
- 컴파일 에러
- 런타임에러
Error : 심각
Exception : 덜 심각
ㄴException과 자손 : 체크드 체외(필수)(try-catch)
ㄴRuntimeException과 자손 : 언체크드예외(선택)
- 논리적 에러
ch8-11 메서드에 예외 선언하기 finally블럭
- 메서드가 호출시 발생가능성이있는 예외를 호출하는 쪽에 알리는 것
- 예외를 처리하는 방법
- try-catch
- 예외 선언하기 (떠넘기기)
- 직접처리
- 예외 떠넘기기
- 은폐(덮기) (try-catch블럭에 빈공간으로 넣기 방대한 데이터를 처리할때 영양없는 데이터를 버려야할때)
- 예외 선언하는 방법
void method() throws Exception1, exception2,args ExceptionN{ //예외할 예외 선언, ','로 구분한다.
//메서드 내용
}
// method()에서 exception과 그자손 예외 발생 가능
void method() throws Exception{ //Exception은 모든 Exception의 조상이므로 이 한개가 모든 자손 선언의 갯수보다 많다.
// 메서드 내용
}
//ex
static void startINstall() throws SpaceException, MemoryException { //예외시킬 예외들
if(!enoughSpace())
thorw new SpaceException("설치할 공간이 부족합니다.");
if(!enoughMenory())
throw new MemoryException("메모리가 부족합니다.");
} //startINstall메서드의 끝
//ex
public class Exception_Test {
public static void main(String[] args) throws Exception{
//최종적인 main메서드에도 try-catch문이 없어서 자바 버츄얼머신(JVM)에게 넘어간다.
method1(); //같은 클래스 내의 static맴버이므로 객체생성없이 직접호출 가능.
//ex
} //main
static void method1() throws Exception{
method2();
} //method1의 끝
static void method2() throws Exception{
throw new Exception();
} //method2의 끝
} //public class
//출력
//자바 버츄얼머신의 예외처리기가 출력한 결과
Exception in thread "main" java.lang.Exception //JVM에의해 예외됨
at Exception_Test.method2(Exception_Test.java:15) //예외를 선언했지만 try-catch가 없어서 떠넘겨짐
at Exception_Test.method1(Exception_Test.java:11) //예외를 선언했지만 try-catch가 없어서 떠넘겨짐
at Exception_Test.main(Exception_Test.java:6) //예외를 선언했지만 try-catch가 없어서 떠넘겨짐
따라서 main에서도 예외처리되지않아서 비정상종료가 된다
즉 직접 처리하냐(수행하는 method에서 try-catch적용) 떠넘기냐(호출한 메서드에서 try-catch)를 적용하냐)의 차이이고 이를 생각하고 적용해야한다.
ch8-14 finaly블럭
- 예외 발생여부와 관계업싱 수행되어야 하는 코드를 넣는다.
- 작업의 성공 여부없이 실행될수있는 기능
public static void main(String [] args) {
try {
// 예외가 발생할 가능성이 있는 문장들을 넣는다.
} catch (Exception1 e1) {
// 예외처리를 위한 문장을 적는다.
} finally {
// 예외의 발생여부에 관계없이 항상 수행되어야하는 문장들을 넣는다.
// finally블럭은 try-catch문의 맨 마지막에 위치해야 한다.
}
// ** try블럭 안에 return문이 있어서 try블럭을 벗어나갈 때도 finally블럭이 실행된다. **
} //public class
ch8-15 사용자 정의 예외 만들기
- 우리가 직접 예외 클래스를 정의할 수 있다.
- 조상은 Exception(필수 try-catch)과 RuntimeException(선택 try-catch)중에서 선택
가능하면 RuntimeException, 필요할떄 exception
public class Exception_Test extends Exception {
Exception_Test extends Exception{
Exception_Test(String msg){ //꼭 문자열을 매개변수로받는 생성자를 만들어야
super(msg); //그리고 또 그안에는 조상생성자를 넣어줘야 한다.
}
} //main
} //public class
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); // ERR_CODE를 100(기본값)으로 초기화 한다.
}
public int getErrCode() { // 에러 코드를 얻을 수 있는 메서드도 추가했다.
return ERR_CODE; // 이 메서드는 주로 getMessage()와 함께 사용될 것이다.
}
}
1. Exception과 RuntimeException중 무엇을 조상으로할지 선택하는 것이 중요
2. 메소드의 매개변수로 String을 넣어준다
3. 그 안에 조상(Exception)의 생성자를 호출한다.
ch8-17 예외 되던지기(exception re-throwing)
- 예외를 처리한 후에 다시 예외를 발생기키는 것
- 호출한 메서드와 호출된 메서드 양쪽 모두세어 예외처리하는 것
public static void main (String [] args) {
try {
method1(); // 1. 예외 발생 3. 다시예외 발생
} catch (Exception e) { // 4. 예외 처리
System.out.println("main 메서드에서 예외가 처리되었습니다.");
}
} //main
static void method1() throws Exception {
try {
throw new Exception();
} catch (Exception e) { // 2. 예외 처리
System.out.println("method1 메서드에서 예외가 처리되었습니다."); //
throw e; // 3. 다시 예외 발생
}
} //method1 끝
왜하는건지 모르겠네
ch8-18 연결된 예외(chained exception)
- 한 예외가 다른 예외를 발생시킬 수 있다.
- 예외 A가 예외 B를 발생시키면 A는B의 원인예외(cause exception)
- Throwable initCause(Throwable 예외A) : 지정한 예외를 원인 예외로 등록
- Throwable getcause() : 원인 예외를 반환
void install() throws InstallException{
try {
startInstall(); // 여기서 SpaceException 발생
copyFiles();
} catch (SpaceException e) {
InstallException ie = new InstallException("설치중 예외 발생"); //예외 생성
ie.initCause(e); // InstallException의 원인 예외를 SpaceException으로 지정
// intitCause()를 사용해서 e를 InstallException에 포함시킨다
throw ie; // InstallException을 발생시킨다.
} catcg (MemoryException me) {
}
}
왜 연결된 예외(chained exception)을 사용하는가?
[이유1] 여러 예외를 하나로 묶어서 다루기 위해서
-> 많아지는 catch블럭을 줄이기 위함
[이유2] checked 예외를 unchecked예외로 변경하려 할 때
checked(Exception의 자손-필수처리)
unchecked(RuntimeException의 자손 - 선택처리)
필수처리일 경우 try-catch를 꼭 써야하기때문에 불필요한 코드들이 많아지므로
연결된 예외(chained Exception)를 시용하여 checked -> unchecked로 변경한다.
- 세부적 예외를 포괄적 예외로 감쌀때 사용
- checked를 unchecked예외로 변경할때 사용한다.