반응형

출처 : 이것이 자바다

예외처리

10.1 예외와 예외 클래스

v  오류의 종류

에러(Error)

      하드웨어의 잘못된 동작 또는 고장으로 인한 오류

      에러가 발생되면 프로그램 종료

      정상 실행 상태로 돌아갈 수 없음

예외(Exception)

      사용자의 잘못된 조작 또는 개발자의 잘못된 코딩으로 인한 오류

      예외가 발생되면 프로그램 종료

      예외 처리 추가하면 정상 실행 상태로 돌아갈 수 있음

v  예외의 종류

일반(컴파일 체크) 예외(Exception)

      예외 처리 코드 없으면 컴파일 오류 발생

      Exception을 상속 받지만 RuntimeException을 상속받지 않는 클래스들

실행 예외(RuntimeException)

      예외 처리 코드를 생략하더라도 컴파일이 되는 예외

      경험 따라 예외 처리 코드 작성 필요

      RuntimeException을 상속받은 클래스들이다.

v  예외 클래스

 

 

10.2 실행 예외(RuntimeException)

실행 예외는 자바 컴파일러가 체크를 하지 않기 때문에 오로지 개발자의 경험에 의해서 예외 처리 코드를 삽입해야 한다.

처리하지 않을 경우 예외가 발생하면 프로그램은 곧바로 종료된다.

10.2.1 NullPointerException

객체 참조가 없는 상태

null 값 갖는 참조변수로 객체 접근 연산자인 도트(.) 사용했을 때 발생

 

 

객체가 없는 상태에서 객체를 사용하려 했으니 예외가 발생하는 것이다.

 

NullPointerException이 발생하는 경우

public class NullPointerExceptionExample {

           public static void main(String[] args) {

                       String data = null;

                       System.out.println(data.toString());

           }

}

 

10.2.2 ArrayIndexOutOfBoundsException

배열에서 인덱스 범위 초과하여 사용할 경우 발생

 

 

 

 

 

 

 

 

ArrayIndexOutOfBoundsExceptionExample

public class ArrayIndexOutOfBoundsExceptionExample {

           public static void main(String[] args) {

                       String data1 = args[0];

                       String data2 = args[1];

 

                       System.out.println("args[0]: " + data1);

                       System.out.println("args[1]: " + data2);

           }

}

 

args를 선언하지 않았기 때문에 예외가 발생한다.

이 문제를 해결할려면 [Run] ->[Run Configurations] ->[Arguments] ->[Program arguments]

두 개의 매개값을 입력하고 실행하면 예외가 발생하지 않는다.

 

배열값을 읽기 전에 배열의 길이를 먼저 조사하는 것이  좋다.

ArrayIndexOutOfBoundsExceptionExample

public class ArrayIndexOutOfBoundsExceptionExample {

           public static void main(String[] args) {

                       if(args.length ==2) {

            String data1 = args[0];

            String data2 = args[1];

            System.out.println("args[0]: " + data1);

            System.out.println("args[1]: " + data2);

        } else {

            System.out.println("[실행 방법]");

            System.out.println("java ArrayIndexOutOfBoundsExceptionExample");

            System.out.println("1 2");

        }

           }

}

 

10.2.3 NumberFormatException

 

Integer Double은 포장(Wrapper) 클래스라고 하는데, 이 클래스의 정적 메소드인 parseXXX() 메소드를 이용하면 문자열을 숫자로 변환할 수 있다.

 

이 메소드들은 매개값인 문자열이 숫자로 변환될 수 있다면 숫자를 리턴하지만, 숫자로 변환될 수 없는 문자가 포함되어 있다면 java.lang.NumberFormatException을 발생시킨다.

NumberFormatException이 발생하는 경우

public class NumberFormatExceptionExample {

           public static void main(String[] args) {

        String data1 = "100";

        String data2 = "a100";

       

        int value1 = Integer.parseInt(data1);

        int value2 = Integer.parseInt(data2);    //NumberFormatException 발생

       

        int result = value1 + value2;

        System.out.println(data1 + "+" + data2 + "=" + result);

    }

}

 

10.2.4 ClassCastException

타입 변환이 되지 않을 경우 발생

 

 

 

 

 

 

 

정상 코드

 

 

예외코드

 

 

instanceof연산의 결과가 true일 경우 처리하는 것이좋다.

Animal animal = new Dog();

if(animal instanceof Dog){

  Dog dog = (Dog) animal;

}else if(animal instanceof Cat){

  Cat cat = (Cat) animal;

}

Remocon rc = new Audio();

if(rc instanceof Television){

  Television tv = (Television)rc;

}else if( rc instanceof Audio){

  Audio audio = (Audio)rc;

}

 

ClassCastException

public class ClassCastException {

           public static void main(String[] args) {

                       Dog dog = new Dog();

                       changeDog(dog);

                      

                       Cat cat = new Cat();

                       changeDog(cat);

           }

 

           private static void changeDog(Animal animal) {

                       Dog dog = (Dog) animal;//ClassCastException 발생 가능

           }

          

}

class Animal{}

class Dog extends Animal{}

class Cat extends Animal{}

 

수정후

public class ClassCastException {

           public static void main(String[] args) {

                       Dog dog = new Dog();

                       changeDog(dog);

                      

                       Cat cat = new Cat();

                       changeDog(cat);

           }

 

           private static void changeDog(Animal animal) {

                       if(animal instanceof Dog) {

                                  Dog dog = (Dog) animal;//ClassCastException 발생 가능

                       }

                      

           }

          

}

class Animal{}

class Dog extends Animal{}

class Cat extends Animal{}

 

10.3 예외 처리 코드

    • 예외 발생시 프로그램 종료 막고, 정상 실행 유지할 수 있도록 처리

      일반 예외: 반드시 작성해야 컴파일 가능

      실행 예외: 컴파일러가 체크해주지 않으며 개발자 경험 의해 작성

    • try catch finally 블록 이용해 예외 처리 코드 작성

 

 

 

 

 

일반 예외 처리

public class TryCatchFinallyExample {

           public static void main(String[] args) {

                       try {

                                  Class clazz = Class.forName("java.lang.String2");

                       } catch (ClassNotFoundException e) {

                                  System.out.println("클래스가 존재하지 않습니다.");

                       }

    }

}

 

 

 10.4 예외 종류에 따른 처리 코드

10.4.1 다중 catch

try{}

catch(){}

catch(){}

public class CatchByExceptionKindExample {
    public static void main(String[] args) {
        try {
            String data1 = args[0];
            String data2 = args[1];
            int value1 = Integer.parseInt(data1);
            int value2 = Integer.parseInt(data2);
            int result = value1 + value2;
            System.out.println(data1 + "+" + data2 + "=" + result);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("실행 매개값의 수가 부족합니다.");
            System.out.println("[실행 방법]");
            System.out.println("java CatchByExceptionKindExample num1 num2");
        } catch (NumberFormatException e) {
            System.out.println("숫자로 변환할 수 없습니다.");
        } finally {
            System.out.println("다시 실행하세요.");
        }
    }
}

실행 매개값의 수가 부족합니다.

[실행 방법]

java CatchByExceptionKindExample num1 num2

다시 실행하세요.

 

10.4.2 catch 순서

상위 예외 클래스가 하위 예외 클래스보다 아래쪽에 위치해야 한다.

차례대로  검색된다. 

public class CatchOrderExample {
 
    public static void main(String[] args) {
        try {
            String data1 = args[0];
            String data2 = args[1];
            int value1 = Integer.parseInt(data1);
            int value2 = Integer.parseInt(data2);
            int result = value1 + value2;
            System.out.println(data1 + "+" + data2 + "=" + result);
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("실행 매개값의 수가 부족합니다.");
        } catch (Exception e) {
            System.out.println("실행에 문제가 있습니다.");
        } finally {
            System.out.println("다시 실행하세요.");
        }
    }
 
}
 

실행 매개값의 수가 부족합니다.

다시 실행하세요.

 

10.4.3 멀티 catch

 | 로 연결하면 된다.

public class MultiCatchExample {
 
    public static void main(String[] args) {
        try {
            String data1 = args[0];
            String data2 = args[1];
            int value1 = Integer.parseInt(data1);
            int value2 = Integer.parseInt(data2);
            int result = value1 + value2;
            System.out.println(data1 + "+" + data2 + "=" + result);
        } catch (ArrayIndexOutOfBoundsException|NumberFormatException e) {
            System.out.println("실행 매개값의 수가 부족하거나 숫자로 변환할 수 없습니다.");
        } catch (Exception e) {
            System.out.println("알수 없는 예외 발생");
        } finally {
            System.out.println("다시 실행하세요.");
        }
    }
}
 

실행 매개값의 수가 부족하거나 숫자로 변환할 수 없습니다.

다시 실행하세요.

 

10.5 자동 리소스 닫기

 자바 7에서 새로 추가된 try-with-resources를 사용하면 예외 발생 여부와 상관없이 사용했던 리소스 객체(각종 입출력 스트림,서버소켓,소켓,각종 채널)의 close() 메소드를 호출해서 안전하게 리소스를 닫아준다.

 

리소스란 여러 가지 의미가 있겠지만 여기서는 데이터를 읽고 쓰는 객체라고 생각한다. 

 

try-with-resources를 사용하기 위해서는 조건이 있다

 

리소스 객체는 java.lang.AutoCloseable 인터페이스를 구현하고 있어야 한다.

 

public class FileInputStream implements AutoCloseable{
    private String file;
    
    public FileInputStream(String file) {
        this.file =file;
    }
    
    public void read() {
        System.out.println(file + "을 읽습니다.");
    }
 
    @Override
    public void close() throws Exception {
        System.out.println(file + "을 닫습니다.");
    }
}
public class TryWithResourceExample {
 
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("file.txt")) {
            fis.read();
            throw new Exception(); // 강제적으로 예외 발생
        } catch (Exception e) {
            System.out.println("예외 처리 코드가 실행되었습니다.");
        }
    }
 
}

file.txt을 읽습니다.

file.txt을 닫습니다.

예외 처리 코드가 실행되었습니다.

 

10.6 예외 떠넘기기

메소드 내부에서 예외가 발생할 수 있는 코드를 작성할 때 try-catch 블록으로 예외를 처리하는 것이 기본이지만, 경우에 따라서는 메소드를 호출한 곳으로 예외를 떠넘길 수도 있다. 이때 사용 하는 키워드가 throws이다.

throws 키워드는 메소드 선언부 끝에 작성되어 메소드에서 처리하지 않은 예외를 호출한 곳으로 떠넘기는 역할을 한다.

다음 예제에서 Class.forName() 메소드를 사용하는 findClass() 메소드는 예외를 떠넘겼고, findClass()를 호출하는 main() 메소드에서 try-catch 블록을 사용해서 예외 처리를 했다.

public class ThrowsExample {
 
    public static void main(String[] args) {
        try {
            findClass();
        } catch (ClassNotFoundException e) {
            System.out.println("클래스가 존재하지 않습니다.");
        }
    }
 
    public static void findClass() throws ClassNotFoundException {
        Class clazz = Class.forName("java.lang.String2");
    }
}

클래스가 존재하지 않습니다.

 

10.7 사용자 정의 예외와 예외 발생

10.7.1 사용자 정의 예외 클래스 선언

일반 예외로 선언시 Exception을 상속하면 되고 , 실행 예외로 선언시 RuntimeException을 상속하면 된다.

public class BalanceInsufficientException extends Exception{
    public BalanceInsufficientException() { }
    public BalanceInsufficientException(String message) {
        super(message);
    }
}

10.7.2 예외 발생시키기

다음 예제는 은행 계좌 (Account) 클래스를 작성한 것이다. 출금(withdraw) 메소드에서 잔고(balance) 필드와 출금액을 비교해서 잔고가 부족하면 BalanceInsufficientException을 발생 시키도록 했다.

public class Account {
    private long balance;
    
    public Account() { }
    
    public long getBalance() {
        return balance;
    }
    
    public void deposit(int money) {
        balance += money;
    }
    
    public void withdraw(int money) throws BalanceInsufficientException {    //사용자 예외 떠넘기기
        if(balance < money) {
            throw new BalanceInsufficientException("잔고부족:"+(money-balance)+" 모자람");    //사용자 정의 예외 발생
        }
        balance -= money;
    }
}
 

 

10.8 예외 정보 얻기

public class AccountExample {
 
    public static void main(String[] args) {
        Account account = new Account();
        //예금하기
        account.deposit(10000);
        System.out.println("예금액: " + account.getBalance());
        //출금하기
        try {
            account.withdraw(30000);
        } catch (BalanceInsufficientException e) {    //예외 메시지 얻기
            String message = e.getMessage();
            System.out.println(message);
            System.out.println();                    //예외 추적 후 출력
            e.printStackTrace();
        }
    }
 
}

예금액: 10000

잔고부족:20000 모자람

 

sec10_7.BalanceInsufficientException: 잔고부족:20000 모자람

    at sec10_7.Account.withdraw(Account.java:18)

    at sec10_7.AccountExample.main(AccountExample.java:12)

 

getMessage() 메소드의 리턴값을 출력한 것이다.

 

연습문제

1. 예외에 대한 설명 중 틀린 것은 무엇입니까? (4)

 

1.예외는 사용자의 잘못된 조작, 개발자의 잘못된 코딩으로 인한 프로그램 오류를 말한다.

2.RuntimeException의 하위 예외는 컴파일러가 예외 처리 코드를 체크하지 않는다.

3.예외는 try-catch 블록을 사용해서 처리된다.

4.자바 표준 예외만 프로그램에서 처리할 수 있다.

 

2. try-catch-finally 블록에 대한 설명 중 틀린 것은 무엇입니까? (3)

 

1.try { } 블록에는 예외가 발생할 수 있는 코드를 작성한다.

2.catch { } 블록은 try { } 블록에서 발생한 예외를 처리하는 블록이다.

3.try { } 블록에서 return문을 사용하면 finally { } 블록은 실행되지 않는다.

4.catch { } 블록은 예외의 종류별로 여러 개를 작성할 수 있다.

 

3. throws에 대한 설명으로 틀린 것은 무엇입니까? (4)

 

1.생성자나 메소드의 선언 끝 부분에 사용되어 내부에서 발생된 예외를 떠넘긴다.

2.throws 뒤에는 떠넘겨야 할 예외를 쉼표(,)로 구분해서 기술한다.

3.모든 예외를 떠넘기기 위해 간단하게 throws Exception으로 작성할 수 있다.

4.새로운 예외를 발생시키기 위해 사용된다.

 

4. throw에 대한 설명으로 틀린 것은 무엇입니까? (2)

 

1.예외를 최초로 발생시키는 코드이다.

2.예외를 호출한 곳으로 떠넘기기 위해 메소드 선언부에 작성된다.

3.throw로 발생된 예외는 일반적으로 생성자나 메소드 선언부에 throws로 떠넘겨진다.

4.throw 키워드 뒤에는 예외 객체 생성 코드가 온다.

 

 

5. 다음과 같은 메소드가 있을 때 예외를 잘못 처리한 것은 무엇입니까? (3)

 

public void method1() throws NumberFormatException, ClassNotFoundException { ...}

 

1.try { method1();} catch(Exception e) { }

2.void method2() throws Exception {method1();}

3.try {method3();} catch (Exception e) { } catch (ClassNotFoundException e) { }

4.try {method1();} catch (ClassNotFoundException e) { } catch (NumberFormatException e) { }

 

 

 

6. 다음 코드가 실행되었을 때 출력 결과는 무엇입니까?

package sec10_7;

 

public class TryCatchFinallyExample {

 

    public static void main(String[] args) {

        String[] strArray = {"10","2a"};

        int value = 0;

        for (int i = 0; i <=2; i++) {

            try {

                value = Integer.parseInt(strArray[i]);

            } catch (ArrayIndexOutOfBoundsException e) {

                System.out.println("인덱스를 초과했음");

            } catch (NumberFormatException e) {

                System.out.println("숫자로 변환할 수 없음");

            } finally {

                System.out.println(value);

            }

        }

    }

 

}

 

10

숫자로 변환할 수 없음

10

인덱스를 초과했음

10

 

 

 

 

 

7. 로그인 기능을 Member 클래스의 login () 메소드에서 구현하려고 합니다. 존재하지 않는 ID를 입력했을 경우 NotExistIDException을 발생시키고, 잘못된 패스워드를 입력했을 경우 WrongPasswordException을 발생시키려고 합니다. LoginExample의 실행 결과를 보고 빈칸을 채워보세요.

package sec10_7;

 

public class NotExistIDException extends Exception{

    public NotExistIDException() { }

    public NotExistIDException(String message) {

        super(message);

    }

}

package sec10_7;

 

public class WrongPasswordException extends Exception{

    public WrongPasswordException() { }

    public WrongPasswordException(String message) {

        super(message);

    }

}

 

package sec10_7;

 

public class LoginExample {

    public static void main(String[] args) {

        try {

            login("white","12345");

        } catch (Exception e) {

            System.out.println(e.getMessage());

        }

        

        try {

            login("blue","54321");

        } catch (Exception e) {

            System.out.println(e.getMessage());

        }

    }

    

    public static void login(String id,String password) throws NotExistIDException,WrongPasswordException{

        //id가 "blue"가 아니라면 NotExistIDException 발생시킴

        if(!id.equals("blue")) {

            throw new NotExistIDException("아이디가 존재하지 않습니다.");

 

        }

        

        //password가 "12345"가 아니라면 WrongPasswordException 발생시킴

        if(!password.equals("12345")) {

            throw new WrongPasswordException("패스워드가 틀립니다.");

        }

    }

}

 

아이디가 존재하지 않습니다.

패스워드가 틀립니다.

반응형

' > 이것이 자바다' 카테고리의 다른 글

12. 멀티 스레드  (0) 2020.10.03
11. 기본 API 클래스  (0) 2020.10.02
09. 중첩 클래스와 중첩 인터페이스  (0) 2020.10.01
08. 인터페이스  (0) 2020.09.30
07. 상속  (0) 2020.09.29

+ Recent posts