
소스파일 컴파일 시 -> 컴파일러가 소스코드(*.java)에 대해 잘못된 구문, 자료형 체크
에러 수정 후 컴파일 성공적 완성 -> 클래스 파일(*.class) 생성
컴파일을 에러 없이 수행 -> 실행 시 에러 가 없다는 X
런 타임 오류 종류 -> 1. 에러 2. 예외
에러(Error) : 프로그램 코드에 의해 수습될 수 없는 심각한 오류
(메모리 부족, 스택 오버플로우)
예외(Exception) : 프로그램 코드에 의해 수슬될 수 있는 미약한 오류

모든 예외의 최고 조상은 Exception 클래스이며,
상속계층도를 Exception클래스부터 도식화하면 다음과 같다.

Exception클래스들 : 사용자들의 실수와 같은 외적인 요인에 의해 발생하는 에러
Runtime클래스들 : 프로그래머 실수로 발생하는 에러
프로그램 실행 시 발생할 수 있는 예기치 못한 예외의 발생에 대비한 코드 작성
비 정상적 종료를 막고, 정상적인 실행상태 유지!
try-catch문 사용
try{
// 예외가 발생할 가능성이 있는 문장들을 넣음
} catch(Exception e1){
//Exception1이 발생했을 경우, 이를 처리하기 위한 문장을 적음
} catch(Exception2 e2){
//Exception2이 발생했을 경우, 이를 처리하기 위한 문장을 적음
} catch(ExceptionN eN){
//ExceptionN이 발생했을 경우, 이를 처리하기 위한 문장을 적음
}
발생한 예외 종류와 일치하는 단 한개의 catch블럭만 수행됨!
해당 되는 예외가 없으면 처리되지 않음!
try문 내에서 예외 발생 시 catch블럭을 찾고 수행 후 try-catch 블럭을 빠져나가 다음 문장을 계속 수행하지만
예외 없을 시 try-catch문을 빠져나가 수행 계속
package ch08;
public class Ex8_1 {
public static void main(String[] args) {
System.out.println(1);
try {
System.out.println(0/0); //ArithmeticException 발생 시킴
System.out.println(2); // 실행되지 않음
}catch (ArithmeticException ae) {
System.out.println(3);
}
System.out.println(4);
}
}
1
3
4
catch 매개변수내 Exception e 사용 시 어떤 종류의 예외가 발생하더라도
catch 블럭에서 처리됨
ex) ArithmeticException은 Exception의 자손
catch블럭의 괄호 안 참조변수를 통해 인스턴스 접근 가능
printStackTrace() : 예외 발생 당시의 호출스택에 있었던 메서드 정보와 예외 메세지를 화면에 출력한다.
getMessage() : 발생한 예외 클래스의 인스턴스에 저장된 메세지를 얻을 수 있다.
package ch08;
public class Ex8_1 {
public static void main(String[] args) {
System.out.println(1);
System.out.println(2);
try {
System.out.println(3);
System.out.println(0/0); //예외 발
System.out.println(2); // 실행되지 않음
}catch (ArithmeticException ae) {
ae.printStackTrace();
System.out.println("예외메세지 : " + ae.getMessage());
}
System.out.println(6);
}
}
1
java.lang.ArithmeticException: / by zero
2
3
at ch08.Ex8_1.main(Ex8_1.java:11)
예외메세지 : / by zero
6
멀티 catch 블럭 사용시 연결된 클래스들이 조상과 자손의 관계면 에러
-> 조상 클래스만 쓰는 것과 같기에 자손 제거 해주면 됨
// 멀티 캐치 블럭 내 어떤 오류가 발생했는지는 알 수 없다!
// 따라서 예외클래스들의 공통 분모인 조상 예외클래스에 멤버만 사용 가능!
try{
...
} catch(ExceptionA | ExceptionB e){
e.methodA() ;// 에러, ExceptionA의 메서드 호출 불가
if(e instanceof ExceptionA){
ExceptionA e1 = (ExceptionA)e;
e1.methodA(); // OK, ExceptionA의 메서드 호출 가능
}else{
...
throw 사용
new를 이용하여 발생시키려는 예외클래스 객체 생성 후 throw를 통해 예외 발생
package ch08;
public class Ex8_6 {
public static void main(String[] args) {
try {
// 생성자에 String 넣어주면 이 문자열이 Exception 인스턴스
// 에 저장
Exception e = new Exception("고의로 발생시켰음.");
throw e;
// throw new Exception("고의로 발생시켰음."); 한줄로도 가능하다
}catch ( Exception e) {
System.out.println("에러 메세지 : " + e.getMessage());
e.printStackTrace();
}
System.out.println("프로그램이 정상 종료 되었음. ");
}
}
에러 메세지 : 고의로 발생시켰음.
java.lang.Exception: 고의로 발생시켰음.
프로그램이 정상 종료 되었음.
at ch08.Ex8_6.main(Ex8_6.java:7)
checked 예외 : Exception과 자손들(예외 처리 필수)
unchecked 예외 : RuntimeException과 자손들(예외 처리 선택)
class Ex8_7
{
public static void main(String[] args)
{ // checked 예외라 컴파일 오류 발생
throw new Exception();
}
}
class Ex8_7
{
public static void main(String[] args)
{ // unchecked 예외라 컴파일 오류X, 프로그램 비장성 종료
throw new RuntimeException();
}
}
만약 NullPointerException이나 IndexOutOfBoundsException같은 예외들을 checked 예외로 하였다면 모든 코드에 try catch문이 들어갔어야 했겠지? 생각!
try-catch 외에 예외처리를 하는 방법
throws를 통해 메서드 내에서 발생할 수 있는 예외 적어주면 됨
void method() throws Exception1, Exception2, ... ExceptionN{
// 메서드의 내용
}
void method() throws Exception{
// 모든 종류의 예외가 발생할 가능성이 있다는 뜻
// 자손타입의 예외까지도 발생할 수 있다는 점 주의해야함
}
public class Ex8_9 {
public static void main(String[] args) throws Exception{
method1();
}
static void method1() throws Exception
{
method2();
}
static void method2() throws Exception
{
throw new Exception();
}
}
Exception in thread "main" java.lang.Exception
at ch08.Ex8_9.method2(Ex8_9.java:17)
at ch08.Ex8_9.method1(Ex8_9.java:12)
at ch08.Ex8_9.main(Ex8_9.java:6)
실행 도중 java.lang.Exception이 발생하여 비정상적 종료
예외가 발생하였을 때 3개의 메서드(main,method1,method2)가 호출 스택에 있었으며
예외가 발생한 곳은 제일 위쪽에 있는 method2()
main 메서드가 method1() 호출, method1()은 method2() 호출
main 메서드 조차 예외처리를 해주지 않았기에 main메서드가 종료되어 비정상적 종료
여기선 예외를 처리한 것이 아니라 단순히 전달한 것!!
package ch08;
import java.io.*;
public class Ex8_10 {
public static void main(String[] args)
{
try
{
File f = createFile(""); // 예외 발생 위치
System.out.println(f.getName()+"파일이 성공적으로 생성되었습니다. ");
} catch (Exception e)
{
System.out.println(e.getMessage()+" 다시 입력해 주시길 바랍니다.");
}
}
static File createFile(String fileName) throws Exception
{
if(fileName == null || fileName.equals(""))
{
throw new Exception("파일 이름이 유효하지 않습니다. ");
}
File f = new File(fileName);
f.createNewFile();
return f;
}
}
파일 이름이 유효하지 않습니다. 다시 입력해 주시길 바랍니다.
파일 이름을 입력받아 파일을 생성하는 코드
createFile()에 try-catch를 넣으면 문제 발생 시 createFile()이 예외 처리를 하기에 main은 예외 발생 사실 모름
예외 선언한 것 == 예외처리를 떠넘긴 것
밑은 직접 처리 예시 코드
public class Ex8_10 {
public static void main(String[] args)
{
try
{
File f = createFile("");
System.out.println(f.getName()+"파일이 성공적으로 생성되었습니다. ");
} catch (Exception e)
{
System.out.println(e.getMessage()+" 다시 입력해 주시길 바랍니다.");
}
}
static File createFile(String fileName) throws Exception
{
try {
if(fileName == null || fileName.equals(""))
{
throw new Exception("파일 이름이 유효하지 않습니다. ");
}
}catch (Exception e) {
fileName = "제목없음.txt " ;
}
File f = new File(fileName);
f.createNewFile();
return f;
}
}
핵심 : 어디서 처리할지 판단을 잘하자!
예외 발생 여부와 상관없이 실행되어야 할 코드를 포함
try{
...
} catch (Exception1 e1){
...
}finally{
// finally블럭은 try-catch문 맨 마지막에 위치해야 한다.
}
주로 Exception 클래스 or RuntimeException 클래스로부터 상속받아 만듬
class MyException extends Exception
{ // 에러 코드 저장을 위한 값 추가
private final int ERR_CODE;
MyException(String msg, int errcode){
super(msg); // 조상인 Exception 클래스의 생성자를 호출하여 오류 메세지 저장
ERR_CODE = errCode;
}
MyException(String msg)
{
this(msg,100); // 에러 코드 값 100으로 초기화
}
public int getErrCode(){
return ERR_CODE;
}
}
예외를 처리한 후 인위적으로 다시 발생시켜 예외가 발생한 메서드와 호출한 메서드 양쪽에서 처리할 수 있도록 하는 것
class Ex8_12
{
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메서드에서의 예외가 처리되었습니다"
여러가지 예외를 하나의 큰 분류의 예외로 묶어서 다루기 위함
try{
install();
} catch(SpaceException e){
e.printStackTrace();
} catch(MemoryException e){
e.printStackTrace();
/* 위 두 catch블럭을 catch(InstallException e)로 할수 있다 */
} catch(Exception e){
e.printStackTrace();
}
한 예외가 다른 예외 발생 시킴
예외 A가 예외 B를 발생시켰다면 A는 B의 원인 예외(cause Exception)
//Throwable 은 Error와 exception의 조상
// Throwable initCause(Throwable cause) : 지정한 예외를 원인 예외로 등록
// Throwable getCause() : 원인 예외 반환
void install throws InstallException{
try{
startInstell(); // SpaceException 발생
copyFiles();
}catch (SpaceException e){
// 새로운 예외 생성
InstallException ie = new InstallException("설치중 예외발생");
ie.initCause(e); // Install의 원인 예외로 Space 지정
throw ie;
} catch(MemoryException me){
...
}
}
checked예외를 unchecked예외로 변경할때 사용(필수처리 -> 선택처리)
static void startInstall() throws SpaceException, MemoryException{
// throws에는 Exception의 자손들을 선언하는 것이 일반적
if(!enoughSpace())
throw new SpaceException("설치할 공간이 부족합니다".);
if(!enoughMemory())
throw new MemoryException("메모리가 부족합니다.");
}
class SpaceException extends Exception{
SpaceException(String msg){
super(msg)
}
}
// 선택적 예외로 사용하고 싶다면 여기서 Exception -> RuntimeException
// SpaceException이 따른 곳에서도 많이 사용된다면 밑에 처럼
static void startInstall() throws SpaceException {
if(!enoughSpace())
throw new SpaceException("설치할 공간이 부족합니다".);
if(!enoughMemory())
throw new RuntimeException(new MemoryException("메모리가 부족합니다."));
}
활용 예시
package ch08;
public class Ex8_13 {
public static void main(String[] args) {
try {
install();
} catch(InstallException e) {
e.printStackTrace();
} catch(Exception e) {
e.printStackTrace();
}
}
static void install() throws InstallException{
try {
startInstall();
copyFiles();
} catch(SpaceException2 e) {
InstallException ie = new InstallException("설치 중 예외발생 ");
ie.initCause(e);
throw ie;
} catch(MemoryException2 me) {
InstallException ie = new InstallException("설치 중 예외발생");
ie.initCause(me);
throw ie;
} finally {
deleteTempFiles();
}
}
static void startInstall() throws SpaceException2, MemoryException2{
if(!enoughSpace()) {
throw new SpaceException2("설치할 공간이 부족합니다.");
}
if(!enoughMemory()) {
throw new MemoryException2("메모리가 부족합니다.");
}
}
static void copyFiles() {/* 파일 복사 코드 */}
static void deleteTempFiles() {/* 임시 파일 제거 코드 */}
static boolean enoughSpace() {
// 설치하는데 필요한 공간이 있는지 확인하는 코드
return false;
}
static boolean enoughMemory() {
// 설치하는데 필요한 메모리공간이 있는지 확인하는 코드 적음
return true;
}
}
class InstallException extends Exception{
InstallException(String msg){
super(msg);
}
}
class SpaceException2 extends Exception{
SpaceException2 (String msg){
super(msg);
}
}
class MemoryException2 extends Exception{
MemoryException2 (String msg){
super(msg);
}
}