Java/JAVA 3 - 유용한 클래스

JAVA 3 - Exception(예외처리)

CNOW 2024. 4. 29. 09:25
💡 학습 목표
  1. 예외 처리에 대해서 알아 보자.
  2. 프로그램에서의 오류와 예외 처리 방법
  3. 상속을 활용한 사용자 정의 예외 클래스 만들기

1. 예외 처리에 대해서 알아 보자.

자바 프로그래밍에서의 예외 처리(Exception Handling)는 프로그램 실행 중 발생할 수 있는 예상치 못한 상황(예외)을 관리하는 방법입니다. 예외 처리를 통해 프로그램의 비정상적인 종료를 막고, 예외 상황을 보다 적절하게 처리하여 프로그램의 안정성과 신뢰성을 높일 수 있습니다.

 

자바에서는 다음과 같은 방법으로 예외를 처리합니다

try {
    // 예외가 발생할 수 있는 코드
} catch (ExceptionType1 e) {
    // ExceptionType1 예외를 처리하는 코드
} catch (ExceptionType2 e) {
    // ExceptionType2 예외를 처리하는 코드
}
try {
    // 예외가 발생할 수 있는 코드
} catch (Exception e) {
    // 예외 처리 코드
} finally {
    // 항상 실행되는 코드
}

finally 블록: try 블록의 실행 여부와 관계없이 항상 실행되어야 하는 코드(예: 자원 해제 로직)를 포함합니다. finally 블록은 모든 catch 블록 다음에 옵니다.

 

if (someCondition) {
    throw new Exception("Custom Error Message");
}

----------------------------------------------------------------

public void someMethod() throws IOException, NullPointerException {
    // 예외가 발생할 수 있는 코드
}

 


2. 프로그램에서의 오류와 예외처리 방법

컴파일 오류(compile error)

프로그램 코드 작성 중 발생하는 문법적 오류

최근에는 개발 환경(eclipse)에서 대부분의 컴파일 오류는 detection 됨

 

실행 오류(runtime error)

실행 중인 프로그램이 의도 하지 않은 동작(bug)을 하거나 프로그램이 중지 되는 오류

실행 오류는 비정상 종료가 되는 경우 시스템의 심각한 장애를

 

예외 처리의 중요성

  • 프로그램의 비정상 종료를 피하여 시스템이 원할이 실행되도록 함
  • 실행 오류가 발생한 경우 오류의 과정을 재현하는 것은 현실적으로 힘들다
  • 오류가 발생한 경우 log를 남겨서 추후 log 분석을 통해 그 원인을 파악하여 bug를 수정하는 것이 중요

오류와 예외 클래스

  • 시스템 오류(error) : 가상 머신에서 발생, 프로그래머가 처리 할 수 없는 오류임
    동적 메모리가 없는 경우, 스택 메모리 오버플로우등
  • 예외(Exception) :프로그램에서 제어 할 수 있는 오류
    읽어들이려는 파일이 존재하지 않거나, 네트웍이나 DB연결이 안되는 경우등
    자바는 안전성이 중요한 언어로 대부분 프로그램에서 발생하는 오류에 대해 문법적으로 예외 처리를 해야함

 

모든 예외 클래스의 최상위 클래스는 Exception 클래스

 

시나리오 코드 1 (try-catch문)

package basic.useful.ch03;

public class ArrayExceptionHandling {

	// 메인 쓰래드
	public static void main(String[] args) {

		// 런타임 에러
		int[] arr = { 1, 2, 3, 4, 5 };

		try {
			// 예외가 발생할 수 있는 코드를 넣어서 수행 시킨다.
			for (int i = 0; i < 10; i++) {
				System.out.println(arr[i]);
			}
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("배열에 크기를 인덱스가 벗어 났습니다.");
//			System.out.println(e.getMessage());
		}
		
		System.out.println("비정상 종료 되지 않았어요!");

	} // end of main

} // end of class

: 실행 오류(runtime error) 발생될 가능성이 있는 코드에 예외 처리를 할 수 있다.

 

시나리오 코드 2 (try-catch-finally 문)

package useful.ch03;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class FileExceptionHandling {
	
	// 메인 쓰레드 
	public static void main(String[] args) {
		
		FileInputStream fis = null;
		
		try {
			fis = new FileInputStream("demo.txt");
			// return; 
		} catch (FileNotFoundException e) {
			System.out.println("catch 구문 실행!!!");
			 e.printStackTrace();
		} finally {
			// 반드시 수행 되어야 하는 코드 영역 
			// 심지어 return 키워드를 만나더라도 여기는 수행이 된다. 
			System.out.println("finally 블록 수행");
			try {
				fis.close(); // 닫는 시점에  fis. <-- 객체가 생성 안될 경우도 존재 함
			} catch (IOException e) {
				e.printStackTrace();
			}  
		}
		
		System.out.println("비정상 종료 되지 않았아요~");
		
	} // end of main 
	
} // end of class

 

package basic.useful.ch03;

import java.util.Scanner;

public class FinallyHandling {

	public static void main(String[] args) {
		
		// try-catch-finally
		// 언제 finally 사용해야 해 ?
		// 자원을 반드시 닫아 주어야 할 때 등등...
		Scanner scanner = new Scanner(System.in);
		
		try {
			int result = scanner.nextInt();
			System.out.println("result : " + result);
			// scanner 의 자원을 다 사용 햇다면 자원을 해제해야 된다.
			
		} finally {
			scanner.close();
			System.out.println("자원 해제 완료");
		}
		
	}

}

: 예외가 발생 되더라도 finally 블록을 실행해서 자원을 닫을 수 있다.

 

시나리오 코드 3 - throws 예외 처리 던지기(미루기)

package basic.useful.ch03;

public class ThrowsHandling {
	
	//메인 쓰레드
	public static void main(String[] args) {
		
		Calc calc = new Calc();
		
		try {
			// 던져서 강제성이 발생이 되고 
			// 사용하는 사람이 직접 예외처리 핸들링을 할 수 있다.
			calc.divide(10, 0);
		} catch (ArithmeticException e) {
			System.out.println("어떤 수를 0으로 나눌 수 없다.");
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
			
		
	}	// end of main

}	// end of class

class Calc {
	
	public int divide(int n1, int n2) throws Exception {
		// 사용자가 0을 입력하면 예외가 발샐 될 수 있는 코드 영역이다.
		// 해결 방법
		// 1. 해당 메서드에서 직업 예외 처리를 구현한다.
		// 2. 사용하는 사람이 직업 예외처리를 할 수 있도록 던져 버린다.
		return n1 / n2;
	}
	
}

 

시나리오 코드 4 ( 사용자 정의 예외 클래스 )

package useful.ch03;

/**
 * 사용자 정의 예외 클래스 생성 
 */
public class PasswordException extends IllegalArgumentException {

	public PasswordException(String message) {
		super(message);
	}
}

 

package useful.ch03;

public class Password {

	private String pwd;
	
	// getter 
	public String getPwd() {
		return pwd; 
	}
	// setter 
	public void setPwd(String pwd) throws PasswordException  {
		
		if(pwd == null) {
			throw new PasswordException("비밀번호는 null 값일 수 없습니다");
		}
		
		if( pwd.length() < 5) {
			throw new PasswordException("비밀번호는 5자 이상이어야 합니다.");
		}
		// 정규 표현식을 활용할 수 있다. 
		// pwd <== a~z, A~Z  ==> true 
		// pwd <== a, 10, !  ==> false  
		if(pwd.matches("[a-zA-Z]+")) {
			throw new PasswordException("비밀번호는 숫자나 특수문자를 포함해야 합니다.");
		}
	}
}

 

package useful.ch03;

public class Password {

	private String pwd;
	
	// getter 
	public String getPwd() {
		return pwd; 
	}
	// setter 
	public void setPwd(String pwd) throws PasswordException  {
		
		if(pwd == null) {
			throw new PasswordException("비밀번호는 null 값일 수 없습니다");
		}
		
		if( pwd.length() < 5) {
			throw new PasswordException("비밀번호는 5자 이상이어야 합니다.");
		}
		// 정규 표현식을 활용할 수 있다. 
		// pwd <== a~z, A~Z  ==> true 
		// pwd <== a, 10, !  ==> false  
		if(pwd.matches("[a-zA-Z]+")) {
			throw new PasswordException("비밀번호는 숫자나 특수문자를 포함해야 합니다.");
		}
		// [...] : 대괄호는 문자열을 나타냄 
		// a-z, A-Z 모든 알파벳 문자열을 말한다. 
		// + : 바로 앞에 표현식이 하나 이상은 반복되어야 한다. 
		// 즉, "Hello", "world" --> true 를 반환 한다.
		// "A1" , "bbb"(3글자)  --> false 
		this.pwd = pwd;
	}
	
}

 

정규식(Regular Expression, 줄여서 regex 또는 regexp)은 문자열을 처리할 때 사용되는 강력한 도구로, 복잡한 검색, 매칭, 치환 작업을 간단하고 유연하게 수행할 수 있도록 돕습니다. 특정한 규칙을 가진 문자열의 집합을 표현하는데 사용되며, 이 규칙에 따라 문자열의 검색, 분할, 대체, 검증 등 다양한 작업을 자동화할 수 있습니다.

 

문제 예시 - 사용자 정의 클래스의 활용

사용자 정의 예외 클래스 만드는 법 

1. 클래스를 설계 ---> 상속을 받아야 한다. 
2. 활용할 수 있는 클래스에서 throws와 throw 를 활용 
2 - 1 : Password 클래스에 활용 
3. 코드 실행 시점에서 테스트 및 예외 처리 작성 

-----------------------------------------------------

NickName 클래스를 설계 
-- String nick; 
-- get
-- set -> 예외를 던지는 코드를 추가하세요  
NickNameException 상속 --> RuntimeExcption 
NickNameTest 클래스로 확인 하기

 

My 코드

더보기
package basic.useful.ch03;

public class NickNameException extends RuntimeException {
	
	public NickNameException(String message) {
		super(message);
	}

}

 

package basic.useful.ch03;

public class NickName {
	private String nick;

	public String getNick() {
		return nick;
	}

	public void setNick(String nick) throws NickNameException {

		if (nick == null) {
			throw new NickNameException("닉네임은 필수로 작성하셔야 합니다.");
		}
		if (nick.length() < 3 || nick.length() > 10) {
			throw new NickNameException("3글자 이상 10자 이하로 작성해주세요.");
		}
		if (nick.matches("[a-zA-Z]*$")) {
			throw new NickNameException("한글로만 작성해주세요");
		}
		this.nick = nick;
	}

}

 

package basic.useful.ch03;

public class NickNameMainTest {

	public static void main(String[] args) {
		
		NickName nickName = new NickName();
		
		String inputNick = null;
		inputNick = "김수한";
		nickName.setNick(inputNick);
		
		try {
			nickName.setNick(inputNick);
			
		} catch (NickNameException e) {
			System.out.println("정의 예외 발생");
		} catch (Exception e) {
			System.out.println("예외 발생" + e.getMessage());
		}
		
	}

}