자바하면서 발생할 수 있는 문제
오류(Error)
•
시스템 상에서 프로그램에 심각한 문제를 발생하여 실행중인 프로그램이 종료되는 것을 말한다.
•
개발자가 미리예측이 불가하며 오류에대한 처리는 할 수없다
•
재부팅이 답!!
예외(Exception)
•
오류와 마찬가지로 실행중인 프로그램을 비정상적으로 종료시키지만 발생할 수 있는 상황을 미리예측하고 처리할 수 있는 미약한 오류
•
개발자는 예외처리를 통해 예외상황을 적절히 처리하여 코드의 흐름을 컨트롤 할 수 있음
예외처리 왜 할까?
프로그램 실행시 에러발생 > 프로그램종료 > 이렇게 끝나면안되 > 잡아서 다시복귀시키게 > 원래프로그램흐름 유지
예외처리방법은?
1. throws로 위임
throw는 강제로 예외를 발생시키는 구문이다
throw new 예외클래스명();
흐름은 그림과같다 (1-1 throws흐름)
그림1-1)throws 흐름
throws를 이용하면 프로그램이 예외일때 그 상태에서 바로 종료가 된다.
그래서 마지막 프로그램을 정상적으로 종료합니다라는 문구는 실행이안된다.
ExceptionTest et = new ExceptionTest();
/* 상품 가격 10000원 이고, 가진 돈은 50000원일 때*/
// et.checkEnoughMoney(10000, 50000); // 정상동작
/*상품 가격은 50000원이고, 가진 돈은 10000원일 때*/ -- 예외상황
et.checkEnoughMoney(50000, 10000);
System.out.println("프로그램을 정상적으로 종료합니다.");--예외상황일때 실행안됨
Java
복사
package com.greedy.section01.exception;
public class ExceptionTest {
public void checkEnoughMoney(int price, int money) throws Exception {
System.out.println("가지고 계신 돈은 " + money + "원 입니다.");
if(money >= price) {
System.out.println("상품을 구입하기 위한 금액이 충분합니다.");
}else {
/* 돈이 충분하지 않은 경우 예외발생 */
throw new Exception();
}
System.out.println("즐거운 쇼핑하세요~");
}
}
--------------------------
ExceptionTest et = new ExceptionTest();
/* 상품 가격 10000원 이고, 가진 돈은 50000원일 때*/
// et.checkEnoughMoney(10000, 50000); // 정상동작
/*상품 가격은 50000원이고, 가진 돈은 10000원일 때*/
et.checkEnoughMoney(50000, 10000);
System.out.println("프로그램을 정상적으로 종료합니다.");
Java
복사
2. try-catch로 처리
try -catch문은 오류 발생시 그 오류를 다시 잡아가지고 와서 프로그램이 다시 실행될수 있게 한다.
흐름은 그림(1-2 try-catch)와 같다.
그림1-2) try-catch의 흐름
코드흐름
1.
예외처리를 할 checkEnoughMoney 메서드를 만들고 thorws로 Exception을던진다.
package com.greedy.section01.exception;
public class ExceptionTest {
public void checkEnoughMoney(int price, int money) throws Exception {
System.out.println("가지고 계신 돈은 " + money + "원 입니다.");
if(money >= price) {
System.out.println("상품을 구입하기 위한 금액이 충분합니다.");
}else {
/* 돈이 충분하지 않은 경우 예외발생 */
throw new Exception();
}
System.out.println("즐거운 쇼핑하세요~");
}
}
Java
복사
2. throw Exception을 던지면 메서드를 호출하는 쪽에서 책임을져야한다는의미이다
메소드를 호출하면서 try-catch구문을 쓴다.
정상적으로 작동할 때는 try구문이 작성되며
그렇지 않을때 catch가 오류를 잡아서 다시끌고와서 프로그램을 작동시키게한다.
예외발생일때 상품구입불가라는 콘솔창에 출력문이 뜨게되고
마지막에 프로그램종료합니다 라는 출력문도 뜨게된다.
package com.greedy.section01.exception;
public class Application2 {
public static void main(String[] args) {
/* try-catch 이용하는 방법*/
ExceptionTest et = new ExceptionTest();
try {
et.checkEnoughMoney(50000, 10000);
System.out.println("============= 상품 구입 가능 =============");
} catch (Exception e) {
// e.printStackTrace();
System.out.println("============= 상품 구입 불가 =============");
}
System.out.println("프로그램을 종료합니다 ");
}
}
Java
복사
예외처리시 개발자가 예외문구를 만들수 있다?없다?
정답은 YES!!
사전에 정의된 예외 클래스외에 개발자가 원하는 명칭의 예외클래스를 작성하는 것이 가능하다.
extends Exception으로 예외처리 클래스를 상속받아 더 구체적인 예외 이름을 정의하는 것이다.
어떻게 만들까...?
1.
Exception 상속을 받아 클래스를 작성한다
2.
자손클래스에서 부모클래스에 초기화한 생성자를 super()를 사용해 불러온다.
예 ) NotEnoghMoneyExcetion 클래스를 만들어 Exception을 상속받는다
기본생성자 및 초기화하는 생성자를 만듬
package com.greedy.section02.userexception.exception;
public class NotEnoughMoneyException extends Exception {
/*사용자 정의의 예외 클래스를 만들기 위해서는 Exception 클래스를 상복받으면된다.*/
/*Exception 클래스는 Throwable 클래스를 상속받아서 구현되어있다.
* Throwable은 Error 와 Exception 두 가지를 추상화해서 만들었다.
* 예외는 Exception의 가장 최상위 클래스이다.
* 따라서 오류 상황을 만들 것은 아니기 때문에 Exception클래스를 상속 받는다.
* */
/*기본 생성자*/
public NotEnoughMoneyException() {
}
/*문자열을 부모생성자 쪾으로 전달하며 초기화하는 생성자*/
public NotEnoughMoneyException(String message) {
super(message);
}
}
Java
복사
2.클래스를하나만들어 throws를 이용해 NotEnoughMoneyException을 던져준다
그리고 throw new NotEnoughMoneyException("가진 돈 보다 상품 가격이 더 비쌉니다");라는
사용자 정의문구를 만들어준다
package com.greedy.section02.userexception;
import com.greedy.section02.userexception.exception.NotEnoughMoneyException;
public class ExceptionTest {
public void checkEnoughMoney(int price , int money)
throws NotEnoughMoneyException {
/*아까 만들었던 Exception을 발생시킨 메소드는 그냥 예외라는 것을 발생시킨 것이다.
* 예외 클래스의 이름만으로도 어떠한 예외가 발생했는지를 알 수 있도록
* 사용자 정의의 예외클래스를 추가하여 명명할 것이다.
*
* */
/*위의 두 값이 정상 입력 되더라도 상품 가격이 가진 돈보다 큰 경우 예외 발생*/
if(money < price) {
throw new NotEnoughMoneyException("가진 돈 보다 상품 가격이 더 비쌉니다");
}
/*모든 조건이 만족하는 경우 정상적으로 물건 구입가능*/
System.out.println("가진 돈이 충분합니다. 즐거운 쇼핑하세요~");
}
}
Java
복사
3. 실행클래스에서 try- catch로 잡는다
package com.greedy.section02.userexception;
public class Application1 {
public static void main(String[] args) {
/* 사전에 정의되어 있는 Exception의 종류는 굉장히 많이 있다.
* 하지만 RuntimeException의 후손 대부분은 예외처리를 강제화 하지 않는다.
* 이 부분은 뒤에서 다시 다룬다.
* */
/*사전에 정의된 예외 클래스외에 개발자가 원하는 명칭의 예외클래스를 작성하는 것이 가능하다.
* extends Exception으로 예외처리 클래스를 상속받아 더 구체적인 예외 이름을 정의하는 것이다.
* 여기서는 사용자 정의의 예외로 아까 만들었던 프로그램을 조금 더 업그레이드 시켜보자.
* */
ExceptionTest et = new ExceptionTest();
try {
/*돈이 부족한 경우*/
et.checkEnoughMoney(70000, 50000);
} catch(Exception e) {
e.printStackTrace();
}
Java
복사
4. 출력화면
예외구문에서 e.getmessage()이용 및 finally 블럭
e.getmassage를 통해 출력문구를 불러올수 있으며 finally는 try-catch문에 상관없이 무조건 동작한다.
그리고 예외구문만들 때 상위타입은 반드시 아래에 작성해야한다.
작성순서는 하위타입>>>> 상위타입 순(위 >>> 아래) 순으로
package com.greedy.section02.userexception;
import com.greedy.section02.userexception.exception.MoneyNegativeException;
import com.greedy.section02.userexception.exception.NegativeException;
import com.greedy.section02.userexception.exception.NotEnoughMoneyException;
import com.greedy.section02.userexception.exception.PriceNegativeException;
public class Application2 {
public static void main(String[] args) {
ExceptionTest et = new ExceptionTest();
try {
et.checkEnoughMoney(40000, 30000);
/*디테일한 예외 상황별로 처리 로직을 다르게 할 수있다.
* 이 떄 주의할 정믄 catch 블럭은 위에서 아래로 자신의 탑이과 맞는 경우 동작하기 때문에
* 상위 탑이 위쪽에 오게되는 경우에는 하단에 작성한 코드는 절대 도달할 수 없는 코드가 되므로
* 컴파일 에러가 난다.
* 그래서 적용할 때 어떤게 상위타입인지 하위타입인지 잘 확인하고 써야한다.*/
} catch (PriceNegativeException e) {
System.out.println("PriceNegativeException 발생!");
System.out.println(e.getMessage());
} catch (MoneyNegativeException e) {
System.out.println("MonetNegativeException 발생!");
System.out.println(e.getMessage());
} catch (NegativeException e) {
System.out.println("NegativeException");
System.out.println(e.getMessage());
} catch (NotEnoughMoneyException e) {
System.out.println("NotEnoughMoneyExceptuin 발생!");
System.out.println(e.getMessage());
} finally {
/* 예외 발생여부와 상관 없이 실행할 내용 */
System.out.println("finally 블럭 내용 동작함...");
}
System.out.println("프로그램을 종료합니다.");
}
}
Java
복사
JAVA1.7부터 나온 Multi-Catch를 알아보자!
Multi-Catch란??
•
JAVA1.7버전부터 추가 된 구문으로 동일한 레벨의 다른타입의 예외를
하나의 catch블럭으로 다룰 수 있다.
package com.greedy.section02.userexception;
import com.greedy.section02.userexception.exception.MoneyNegativeException;
import com.greedy.section02.userexception.exception.NotEnoughMoneyException;
import com.greedy.section02.userexception.exception.PriceNegativeException;
public class Application3 {
public static void main(String[] args) {
/*multi-catch
* JDK 1.7에서 추가된 구문으로
* 동일한 레벨의 다른 타입의 예외를 하나의 catch블럭으로 다룰 수 있다.
* */
ExceptionTest et = new ExceptionTest();
try {
et.checkEnoughMoney(20000, 10000);
} catch (PriceNegativeException | MoneyNegativeException e) {
/*e.getMessage()로 발생한 예외 클래스의 정보를 알 수 있다.*/
System.out.println(e.getClass() + "발생!");
/*e.getMessage()로 예외 발생시 전달한 메세지를 문자열로 반환받을 수 있다.*/
System.out.println(e.getClass());
} catch (NotEnoughMoneyException e) {
/*예외 클래스명, 예외 발생위치, 예외 메세지등을 stack 호출의 역순으로
* 빨간색 글씨를 이용하여 로그형태로 출력해주는 기능을 제공한다.
* */
e.printStackTrace();
} finally {
/*예외 발생여부와 상관없이 실행할 내용*/
System.out.println("fnally블럭의 내용이 동작함");
}
System.out.println("프로글매을 종료합니다.");
}
}
Java
복사
Runtime Exception 후손클래스
NullPointerException을 안나게 방지하는법
IOException보다 EOFException이 더 구체적이다
예외클래스가 가장많이쓰이는곳 IO(Input/Output)패키지!!
package com.greedy.section3.uses;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class Application1 {
public static void main(String[] args) {
/*예외 처리를 많이 사용하는 패키지는 io(input/output) 패키지이다. */
BufferedReader in = null;
try {
/*FileReader라는 클래스의 새엇ㅇ자에 예외를 throws 해 놓았다
* 사용하는 쪽에서 반드시 에외처리를 해야하기 때문에 try-catch 블럭 안에서 생성자를 호출해야한다.
* */
in = new BufferedReader(new FileReader("test.dat"));
String s;
while((s = in.readLine()) != null ) {
System.out.println(s);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
/* 예외 발생여부와 상관없이 반드시 처리할 로직 작성
* 주로 자원을 반납할 목적으로 사용한다.*/
try {
/*NullPointerException이 발생
* 파일을 찾지못해 객체를 생성하지 못하고 래퍼런스 변수는 null값을 가진 상태이기 때문에
* null 을 참조하는 상태에서 참조연산자를 사용하면 발생하는 예외이다.
* NullPointerException은 unchecked Exception으로 try-catch로 처리하기보다는
* 보통 if-else 구문으로 해결 가능하다.
* */
if(in != null) {
/* 입출력에서 사용한 스트림을 닫아주는 메소드이다.
* IOException을 위임한 메소드 이기 떄문에
* finally 블럭 안이라도 예외처리를 중첩으로 해주어야한다.
* try블럭과 finally 블럭은 별개이다.
* */
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Java
복사