예외 클래스
오류란?
- 프로그램에서 오류가 발생하는 상황은 두 가지 이다.
- 프로그램 코드 작성 중 실수로 발생하는 컴파일 오류
- 실행 중인 프로그램이 의도하지 않은 동작을 하거나 프로그램이 중지되는 실행 오류
- 실행 오류 중 프로그램을 잘못 구현하여 의도한 바와 다르게 실행되어 생기는 오류를 버그라 한다.
오류와 예외
- 실행 오류는 크게 두 가지가 있는데, 하나는 자바 가상 머신에서 발생하는 시스템 오류, 하나는 예외 이다.
- 시스템 오류는 프로그램에서 제어할 수 없지만, 예외는 프로그램에서 제어가 가능하다.
예외 클래스의 종류
- 프로그램에서 처리하는예외 클래스의 최상위 클래스는 Exception 클래스이다.
- Exceoption 하위 클래스에중 IOException 클래스는 입출력에 대한 예외 처리를 처리하고,
RuntimeException은 프로그램 실행 중 발생할 수 있는 오류에 대한 예외를 처리한다.
예외 처리하기
try-catch문
- try 블록에는 예외가 발생할 가능성이 있는 코드를 작성하고, 만약 try 블록 안에서 예외가 발생하면 catch 블록이
수행된다. - catch문의 괄호 안에 쓰는 예외 타입은 예외 상황에 따라 달라진다.
try {
예외가 발생할 수 있는 코드 부분
} catch(처리할 예외 타입 e) {
try 블록 안에서 예외가 발생했을 때 예외를 처리하는 부분
}
try-catch문 사용하기
package exception;
public class ArrayExceptionHandling {
public static void main(String[] args) {
int[] arr = new int[5];
try{
for(int i = 0; i<=5; i++){ //예외가 발생할 수 있으므로 try 블록에 작성
arr[i] = i;
System.out.println(arr[i]);
}
}catch(ArrayIndexOutOfBoundsException e){ //예외가 발생하면 catch 블록 수행
System.out.println(e);
System.out.println("예외 처리 부분");
}
System.out.println("프로그램 종료");
}
}
배열 범위가 유효한 값 4까지는 배열에 저장되어 출력하고 그 다음 값을 배열에 넣으려 할때 예외가 발생하여 catch 블록이
수행되고 정상 종료된다.
컴파일러에 의해 예외가 처리되는 경우
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ExceptionHandling1 {
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("a.txt");
} catch (FileNotFoundException e) {
System.out.println(e); //예외 클래스의 toString() 메서드 호출
}
System.out.println("여기도 수행됩니다."); //정상 출력
}
}
a.txt 파일이 없기 때문에 관련된 오류를 catch 블록에서 출력하고 예외 처리 후에도 프로그램이 계속 수행되었음을 알 수 있다.
try-catch-finally문
- 끝나지 않고 계속 수행되는 경우 사용한 시스템 리소스는 사용 후 반드시 close() 메서드로 받아 주어야 한다.
- trty-catch문의 경우에도 close() 메서드를 둘 다 사용하여 닫아주어야 하지만 finally 블록을 추가하여 각 블록마다
리소스를 해제하지 않고, finally 블록에서 한 번만 해제해 주면 된다.
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionHandling3 {
public static void main(String[] args) {
FileInputStream fis = null;
try {
fis = new FileInputStream("a.txt");
} catch (FileNotFoundException e) {
System.out.println(e);
return; //예외 처리 후 강제 리턴
} finally { //리턴문과 상관 없이 finally 블록 수행
if (fis != null) {
try {
fis.close(); //파일 입력 스트림 닫기
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("항상 수행 됩니다.");
}
System.out.println("여기도 수행됩니다.");
}
}
a.txt 파일이 없기 때문에 catch 블록을 수행 하고 강제 리턴을 했지만 finally 블록은 상관 없이 수행이 되기 때문에
finally 블록이 수행된 것을 알 수 있다.
try-with-resource문
- try-with-resource문을 사용하면 close() 메서드를 호출하지 않아도 자동을 리소스를 닫도록 만들 수 있다.
- 이 문법을 사용하려면 해당 리소스가 AutoCloseable 인터페이스를 구현해야 한다.
AuthoCloseable 인터페이스 구현
package exception;
public class AutoCloseObj implements AutoCloseable{
@Override
public void close() throws Exception {
System.out.println("리소스가 close() 되었습니다."); //close() 메서드 구현
}
}
try-with-resource문 사용하기 - 정상적으로 종료된 경우
package exception;
public class AutoCloseTest {
public static void main(String[] args) {
AutoCloseObj obj = new AutoCloseObj();
try (AutoCloseObj obj2 = obj){ //try블록에서 ()안에 사용할 리소스 선언
//리소스를 여러개 생성해야 한다면 세미 콜론으로 구분한다.
throw new Exception();
}catch(Exception e) {
System.out.println("예외 부분입니다.");
}
}
}
try-with-resource문 사용하기 - 예외가 발생하여 종료되는 경우
package exception;
import java.io.FileNotFoundException;
public class AutoCloseTest2 {
public static void main(String[] args) throws FileNotFoundException {
AutoCloseObj obj = new AutoCloseObj();
try (obj){
throw new Exception(); //강제로 예외 발생
}catch(Exception e) {
System.out.println("예외 부분입니다.");
}
}
}
예외 처리 미루기
예외 처리를 미루는 throws 사용하기
- 예외 처리 방법은 두 가지로 try-catch문이 있고 나머지 하나는 throws를 사용하는 것이다.
- 예외를 해당 메서드에서 처리하지 않고 미룬 후 메서드를 호출하여 사용하는 부분에서 예외를 처리하는 방법이다.
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ThrowsException {
public Class loadClass(String fileName, String className) throws FileNotFoundException, ClassNotFoundException{
//throws는 두 예외는 메서드가 호출될 때 처리하도록 미룬다.
FileInputStream fis = new FileInputStream(fileName); //FileNotFoundException 발생 가능
Class c = Class.forName(className); //ClassNotFoundException 발생 가능
return c;
}
public static void main(String[] args) throws FileNotFoundException, ClassNotFoundException {
ThrowsException test = new ThrowsException();
test.loadClass("a.txt", "java.lang.String"); //메서드를 호출할 때 예외를 처리함
}
}
loadClass에서 throws로 미뤄진 예외 처리는 main() 부분에서 이뤄지는데 이 때 처리하는 방법은 세 가지가 있다.
위 코드처럼 함수 선언 부분에 throws를 추가하고 예외 처리를 미루는 것인데 이 경우 대부분의 프로그램이 비정상
종료된다. 그렇기 때문에 두 번째 옵션인 try-catch문을 사용하여 예외를 처리하는 것이 좋다.
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ThrowsException {
public Class loadClass(String fileName, String className) throws FileNotFoundException, ClassNotFoundException{
//throws는 두 예외는 메서드가 호출될 때 처리하도록 미룬다.
FileInputStream fis = new FileInputStream(fileName); //FileNotFoundException 발생 가능
Class c = Class.forName(className); //ClassNotFoundException 발생 가능
return c;
}
public static void main(String[] args) {
ThrowsException2 test = new ThrowsException2();
try {
test.loadClass("a.txt", "java.lang.String");
} catch (FileNotFoundException | ClassNotFoundException e) { //예외처리를 한 문장으로 처리한다.
e.printStackTrace();
}
}
}
다중 예외 처리
- 어떤 예외가 발생할지 미리 알 수 없지만 모든 예외 상황을 처리하고자 할 때 맨 마지막 부분에 Exception 클래스를
활용하여 catch 블록을 추가한다.
package exception;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ThrowsException2 {
public Class loadClass(String fileName, String className) throws FileNotFoundException, ClassNotFoundException{
FileInputStream fis = new FileInputStream(fileName); //FileNotFoundException ¹ß»ý
Class c = Class.forName(className); //ClassNotFoundException ¹ß»ý
return c;
}
public static void main(String[] args) {
ThrowsException test = new ThrowsException();
try {
test.loadClass("a.txt", "java.lang.String");
}catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (Exception e) { //Exception 클래스로 그 외 예외 상황 처리
e.printStackTrace();
}
}
}
사용자 정의 예외
- 자바 프로그램은 예외 클래스를 직접 만들어서 예외를 발생시키고 예외 처리 코드를 구현할 수 있다.
사용자 정의 예외 클래스 구현하기
- 사용자 정의 예외 클래스를 구현할 때는 기존 JDK에서 제공하는 예외 클래스 중 가장 유사한 클래스를 상속받는
것이 좋다. - 예시로 아이디가 null 값이거나 지정 범위를 벗어나는 경우의 예외 클래스를 만들어 보자
사용자 정의 예외 구현하기
package exception;
public class IDFormatException extends Exception{
public IDFormatException(String message){ //String message - 생성자의 매게변수로 예외 상황 메세지를 받음
super(message);
}
}
- Exception 클래스에서 상속을 받아서 구현하였다.
- Exception 클래스에서 메시지 생성자, 멤버 변수와 메서드를 이미 제공하고 있기 때문에 super(message)를 사용하여
예외 메시지를 설정한다. getMessage() 메서드를 호출하여 내용을 볼 수 있다.
사용자 정의 예외 테스트하기
package exception;
public class IDFormatTest {
private String userID;
public String getUserID(){
return userID;
}
//아이디에 대한 제약 조건 구현
public void setUserID(String userID) throws IDFormatException{
////IDFormatException 예외를 setUserID() 메서드가 호출될 때 처리하도록 미룸
if(userID == null){
throw new IDFormatException("아이디는 null 일 수 없습니다"); //강제로 예외 발생시킴
}
else if( userID.length() < 8 || userID.length() > 20){
throw new IDFormatException("아이디는 8자 이상 20자 이하로 쓰세요"); //강제로 예외 발생시킴
}
this.userID = userID;
}
public static void main(String[] args) {
IDFormatTest test = new IDFormatTest();
String userID = null; //아디디 값이 null인 경우
try {
test.setUserID(userID);
} catch (IDFormatException e) {
System.out.println(e.getMessage());
}
userID = "1234567"; //아이디 값이 8자 이하인 경우
try {
test.setUserID(userID);
} catch (IDFormatException e) {
System.out.println(e.getMessage());
}
}
}
예외 처리를 할 때는 로그를 잘 남기자
- 시스템을 개발하여 구축을 했을 때 오류가 발생한다면 어떤 상황에서 오류가 났는지, 시스템에서 어떤 메서드를
호출하고 어떻게 매개변수를 전달했는지 오류 현상만 보고는 알 수 없기 때문에 로그를 남기는 것이 중요하다.
'Java-Study' 카테고리의 다른 글
Java Study : 11주차 - 백준 문제풀이 (0) | 2023.01.22 |
---|---|
Java Study : 11주차 - 자바 입출력 (0) | 2023.01.22 |
Java Study : 9주차 - 백준 문제풀이 (0) | 2023.01.08 |
Java Study : 9주차 정리 - 내부 클래스, 람다식, 스트림 (0) | 2023.01.08 |
Java Study : 8주차 - 백준 문제풀이 (0) | 2022.12.23 |