반응형
01. 예외(Exception)의 개념
- 사용자에 의해 프로그램을 잘못 실행하거나 프로그램을 잘못 개발할 경우 발생되는 프로그램 오류
- 예외가 발생된 경우, 예외가 발생된 지점에서 프로그램은 강제 종료된다.
- 프로그램이 강제 종료되지 않기 위해서는? 예외처리(ExceptionHandle) 필요
- 예외처리의 장점 (예외처리 하는 이유)
- 예외가 발생되어 프로그램이 강제로 종료되는 것을 방지할 수 있음
- 예외가 발생되어 프로그램이 종료된 이유를 명확히 알고 고칠 수 있음
- 개발자를 위한 에러 로그
- 고침으로서 프로그램이 강제 종료되는 것을 방지할 수 있음
02.예외처리(ExceptionHandle)
- 예외처리를 통해 어떤 예외가 발생되었는지 알 수 있음
- 예외를 처리하기 위해 자바에서는 다양한 예외클래스를 제공해줌
(부모) Throwable 클래스
- 프로그램에서 발생되는 모든 오류 정보를 저장하기 위한 부모클래스
- 대다수의 예외 클래스는 Throwable클래스를 상속받음
- 자식클래스 : Exception클래스 , Error클래스
(자식1) 예외 클래스(Exception Class)
- 예외 관련 정보를 저장하기 위한 클래스
- (문법적으로 잘못된 것이 아니라 프로그램 실행시 잘못된 결과 발생할 수 있다는 것)
- (프로그램의 명령 실행시 발생할 수 있는 오류)
- Exception클래스를 상속받아 작성된 자식클래스들..
- 예외가 발생되는 명령에 대해서는 예외처리가 필수!
(자식2) 에러 클래스(Error Class)
- 하드웨어적으로 문제가 발생했을 때 오류정보를 저장하기 위한 클래스 (프로그램 자체의 오류)
- 심각한 프로그램 예외인경우 [에러]로 표시하며 프로그램 실행 불가
03. 예외 클래스(Exception Class)의 분류
1.예외클래스의 API
- java.base모듈 >> java.lang 패키지 >> Throwable클래스
- java.base모듈 >> java.lang 패키지 >> Exception Summary클래스들 확인하기
- java.lang.Object(부모) - java.lang.Throwable(자식)
- All Implemented Interfaces : Serializable
- Direct Known Subclasses : Error , Exception
public class Throwable extends Object implements Serializable{
}
2.실행 예외클래스(RuntimeException)
- RuntimeException 클래스를 상속받은 예외클래스로 예외처리
- 프로그램 실행 시 예외가 발생될 수 있는 가능성이 낮아 컴파일 시 예외처리 불필요
- 예외가 발생된 경우 JVM에서 자동으로 예외처리를 하여 예외메세지 제공하지만 사용자가 보기에는 부적절하므로, 웬만해서는 모두 예외처리 하기
- 정리하자면 실행예외클래스는 예외처리하지 않아도 프로그램은 실행되지만, 예외발생 시 JVM이 개발자를 위한 메세지를 출력해주고, 프로그램이 강제로 종료될 수 있음.
- 사용자입장에서는 메세지를 제대로 읽지 못하고 프로그램이 강제로 종료되는 꼴임.
- 그러므로 반드시 예외처리를 해주자!!!!!!
- 주로 프로그래머 실수에 의해 발생
- (자바 프로그래밍 요소들과 깊은 관련)
- ArrayIndexOutOfBoundsException : 배열의 범위 벗어남
- NullPointerException : 값이 null인 참조변수의 멤버를 호출하려함
- ClassCastException : 클래스 간의 형변환 잘못함
- ArithmeticException : 정수를 0으로 나누려고 함
- InputMismatchException : 입력값의 타입이 맞지 않음
3.일반 예외클래스
- RuntimeException 클래스를 상속받지 않는 예외클래스
- 프로그램 실행 시 예외가 발생될 수 있는 가능성이 높아 컴파일 시 예외처리되어있지 않으면 에러 발생
- 예외가 발생된 경우 반드시 예외처리 필수!!
- 주로 외부의 영향으로 발생할 수 있는 것들
- 프로그램의 사용자들의 동작에 의해서 발생하는 경우가 많음
- FileNotFoundException: 존재하지 않는 파일의 이름을 입력
- ClassNotFoundException : 실수로 클래스의 이름을 잘못 적음
- DataFormatException : 입력한 데이터 형식이 잘못됨
04. 예외처리하기 (try-catch구문)
try - catch 구문 사용
- try { }
- 필수로 작성
- 불필요한 명령은 작성 하지 말기, 속도 느려짐, 필요한 것들만 작성
- 변수 , 배열 선언은 try 외부에 작성. 왜? try블럭이 끝나면 소멸되기 때문
- try 블럭에서 예외가 발생될 경우 JVM이 예외클래스로 객체를 생성함
- 즉, try블럭 안을 JVM이 계속 감시하다가 예외가 발생되면, 예외클래스로 객체를 만들어줌
- catch (예외클래스 참조변수) { }
- try 블럭에서 발생된 예외 관련 객체를 catch 블럭으로 전달받아 참조변수에 저장하여 예외처리함
- catch 블럭의 참조변수에 저장된 예외 관련 객체를 이용하여 예외처리 명령을 작성함
- try 블럭에서 예외가 발생되면 프로그램을 종료하지 않고, 프로그램의 흐름(스레드)이 catch 블럭으로 이동
- catch 블럭은 여러개 작성 가능 - 다양한 예외를 구분하여 예외처리 가능
- finally { }
- finally 블럭에는 예외와 상관없이 무조건 실행될 명령 작성
- 사용자원에 대한 제거 명령 실행
- 생략가능
try{
//예외 발생될 수 있는 명령;
...
} catch (예외클래스 참조변수){
//예외처리 명령;
...
} catch (예외클래스 참조변수){
//예외처리 명령;
...
} catch (예외클래스 참조변수){
//예외처리 명령;
...
} finally {
//예외에 상관없이 무조건 실행 될 명령;
...
}
1. "실행예외" (RuntimeException)의 예외처리
- 실행예외(RuntimeException)는 개발자 중심 예외클래스 이다.
- 즉, 개발자를 위한 메세지를 출력해준다.
- 실행 예외(RuntimeException)는 예외 발생시 JVM에 의해 자동으로 예외처리되어 메세지를 제공받아 출력이 된다.
- 하지만 사용자 중심의 프로그램을 작성하기 위해 직접 예외처리하는 것을 권장한다.
(try - catch 구문 미사용)
- try-catch 구문 쓰지 않아도 JVM이 자동예외처리하고, 예외메세지를 제공해줌
- but 불친절 , 사용자 중심 프로그램을 작성하기 위해 친절하게 예외처리해보자
2. "실행예외" ArrayIndexOutOfBoundsException의 예외처리
ExceptionHandleApp.java
/*
public class ExceptionHandleApp {
public static void main(String[] args) {
int[] array = {10,20,30,40,50};
for(int i = 0; i<=array.length; i++) {
System.out.println("array["+i+"] = "+ array[i]);
}
}
}
//array[0] = 10
//array[1] = 20
//array[2] = 30
//array[3] = 40
//array[4] = 50
//Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5
// at xyz.itwill.exception.ExceptionHandleApp.main(ExceptionHandleApp.java:38)
*/
//
// => 배열 요소의 첨자 사용 시 범위를 벗어난 경우 ArrayIndexOutOfBoundsException 발생
// => 발생하면 JVM에 의해 ArrayIndexOutOfBoundsException객체 생성
// => 단, ArrayIndexOutOfBoundsException객체는 실행예외(RuntimeException)</span>이므로 컴파일 시 예외처리 되어 있지 않아도 에러 미발생
// => try-catch구문 사용해 에외처리
package xyz.itwill.exception;
public class ExceptionHandleApp {
public static void main(String[] args) {
int[] array = {10,20,30,40,50};
try {
for(int i = 0; i<=array.length; i++) {
System.out.println("array["+i+"] = "+ array[i]);
}
//예외가 발생된 경우 예외 발생 명령 하단에 존재하는 명령 미실행
//=> 예외가 발생된 경우 프로그램은 강제 종료 되거나, 프로그램의 흐름이 catch블럭으로 이동
System.out.println("[메세지]프로그램이 정상적으로 실행 되었습니다.");
//예외가 발생하면 JVM에 의해 ArrayIndexOutOfBoundsException 객체 생성
} catch(ArrayIndexOutOfBoundsException e){//예외 객체를 전달받아 참조변수에 저장
//1.
//프로그램 사용자에게는 예외 관련 메세지 출력 - 🌈생략 가능
System.out.println("[에러] 프로그램 실행에 예기치못한 오류가 발생되었습니다.");
//2.
//프로그램 개발자에게는 예외 관련 메세지를 기록하여 전달 - 🌈에러 로그(필수)
// => ArrayIndexOutOfBoundsException 객체를 전달받아 참조변수에 저장하여 예외처리
//Throwable.getMessage() : 예외객체에 저장된 예외 메세지를 문자열로 반환하는 메소드 - 🌈에러 로그(필수) / 간단한기록 / 기록할 때 많이 호출
System.out.println("[예외] " + e.getMessage()); //[예외]Index 5 out of bounds for length 5
//Throwable.printStackTrace() : 예외가 발생된 경로를 역추적하여 발생된 상세정보를 제공받아 출력하는 메소드 - 🌈에러 로그(필수) / 자세한기록 / getMessage()로 모르겠다면
e.printStackTrace(); //java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5 at xyz.itwill.exception.ExceptionHandleApp.main(ExceptionHandleApp.java:67)
//Throwable.getStackTrace(): 🌈에러 로그(필수)
e.getStackTrace();
} finally { //생략 가능
System.out.println("[메세지]예외와 상관없이 무조건 실행되는 명령");
}
}
}
//array[0] = 10
//array[1] = 20
//array[2] = 30
//array[3] = 40
//array[4] = 50
//[에러] 프로그램 실행에 예기치못한 오류가 발생되었습니다.
//[예외] Index 5 out of bounds for length 5
//java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5 at xyz.itwill.exception.ExceptionHandleApp.main(ExceptionHandleApp.java:67)
//[메세지]예외와 상관없이 무조건 실행되는 명령
05. 예외전달(throws) 후 예외처리 (훨씬 효율적)
try-catch만 작성했을 때(모든 명령에 예외처리를 했을 경우) 단점
- 위와 같이 작성하는 것은 매우 비효율적
- JVM이 명령을 실행 후 예외가 발생했는지 안했는지 계속감시해야하므로 실행속도 느려짐
- 모든 명령들을 try로 묶지는 않음
- 만약 모두 묶으면 실행속도가 매우 떨어짐
- 그래서 try의 예외처리는 프로그램에서 딱 한번만 처리하고, 나머지는 호출메소드에게 떠넘김
- ex) 사장(JVM) → 부장(메소드호출) → 대리(스스로 처리, 혹은 스스로 처리 못할 수 있음)
- 부장에게 문제해결요청 → 처리 못한다 → 사장에게 문제해결요청
- 즉, 문제처리를 직접 처리할 수 있지만, 스스로 처리하지 못하면 일을 시킨 사람에게 책임을 전가함 (예외처리 전달)
- 이 방법은 각각의 예외처리들을 위 처럼 직접 처리하지않고, 예외를 전달시켜 메소드를 호출한 곳에서 한꺼번에 예외처리하는 것이다.
1. 예외전달하기 (throws)
- 예외가 발생된 명령에서 예외처리하지 않고 발생된 예외를 메소드를 이용하여 전달 가능
- 메소드의 명령에서 발생된 예외를 메소드를 호출하는 명령으로 전달할 수 있게 됨
- 즉, 예외처리를 먼저 하지 않고,, 나는 이런 예외가 발생될거야! 라고 미리 알려주는 것임
public 반환형 메소드명(자료형 매개변수, 자료형 매개변수,...) throws 예외클래스,예외클래스...{
//호출하는메소드에서..
//try-catch구문 사용하기
}
2. "실행예외" ArrayIndexOutOfBoundsException의 예외전달 후 예외처리
ExceptionThrowsApp.java
package xyz.itwill.exception;
// => ArrayIndexOutOfBoundsException 예외 전달하기
// => 받은 예외들을 메소드호출하는 곳에서 try-catch구문 사용해 ArrayIndexOutOfBoundsException 예외처리하기
public class ExceptionThrowsApp {
//누구한테? 메소드를 호출하는 곳으로! display();이곳에
//직접 예외처리가 아닌 대신 처리해줘~ 하고 호출메소드에게 전달하는 것
//정적메소드
public static void display() throws ArrayIndexOutOfBoundsException{
int[] array = {10, 20, 30, 40, 50};
for(int i = 0; i <= array.length; i++) { //컴파일할 때는 예외처리 안되지만, 실행할 때 예외처리됨(실행예외)
System.out.println("array["+i+"] ="+array[i]);
}
}
//메인메소드
public static void main(String[] args) {
try {
//정적메소드는 클래스 이름을 이용하여 호출 - 같은 클래스에 선언된 정적메소드는 클래스 표현 없이 메소드 호출 가능
//ExceptionThrowsApp.display(); //ok
//display(); //ok
//예외가 발생되는 메소드를 호출한 명령을 try ~ catch 구문으로 예외처리하기
//=> 만약 try ~ catch 구문으로 예외처리하지 않는다면?? 일반 예외시에는 컴파일 예외 발생, 실행 예외시에는 JVM에 의해 자동으로 예외처리
display(); //예외를 발생하는 메소드를 호출하는 곳에서 try-catch구문으로 묶은 것
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("[에러] 프로그램 실행에 예기치못한 오류가 발생되었습니다.");
}
}
}
//array[0] =10
//array[1] =20
//array[2] =30
//array[3] =40
//array[4] =50
//[에러] 프로그램 실행에 예기치못한 오류가 발생되었습니다.
3. "실행예외" InputMismatchException, ArithmeticException의 예외전달 후 예외처리
CalcApp.java
package xyz.itwill.exception;
import java.util.InputMismatchException;
import java.util.Scanner;
//키보드로 정수값 2개를 입력받아 첫번째 정수값으로 두번째 정수값을 나눈 몫을 계산하여 출력하는 프로그램 작성
public class CalcApp {
public CalcApp() throws InputMismatchException, ArithmeticException {
//public CalcApp() throws Exception {//메소드에서 발생된 모든 예외를 Exception 클래스 하나로 전달 가능
Scanner scanner=new Scanner(System.in);
System.out.print("첫번째 정수값 입력 >> ");
//Scanner.nextInt() : 입력값을 정수값으로 변환하여 반환하는 메소드
// => 입력값이 정수값으로 변환되지 못할 경우 InputMismatchException 발생 - 예외처리
// => 직접 예외처리하지 않고 메소드를 사용하여 발생 예외 전달 가능
int num1=scanner.nextInt();
System.out.print("두번째 정수값 입력 >> ");
int num2=scanner.nextInt();
//어떤수를 0으로 나눈 경우 ArithmeticException 발생
System.out.println("[결과]"+num1+" / "+num2+" = "+(num1/num2));
scanner.close();
}
public static void main(String[] args) {
//방법1. 가장좋은방법 : 예외를 하나씩 하나씩 잡아서 처리하기
/*
try {
//생성자를 이용하여 객체 생성 - 생성자의 명령 실행
// => 예외가 전달된 메소드 호출 - 예외처리
new CalcApp();
} catch (InputMismatchException e) {
System.out.println("[에러]정수값만 입력 가능합니다.");
} catch (ArithmeticException e) {
System.out.println("[에러]0으로 나눌수 없습니다.");
} catch (Exception e) {//예측하지 못한 예외에 대한 처리
//Exception : 모든 예외클래스의 부모클래스
// => 모든 예외 객체를 전달받아 참조변수에 저장하여 예외처리 가능
System.out.println("[에러]프로그램에 예기치 못한 오류가 발생되었습니다.");
}
*/
//방법2.
try {
new CalcApp();
} catch (InputMismatchException | ArithmeticException e) {
//catch 블럭에서 예외클래스를 | 연산자로 연결하여 다수의 예외에 대한 처리 가능
System.out.println("[에러]형식에 맞는 값을 입력해 주세요.");
} catch (Exception e) {
System.out.println("[에러]프로그램에 예기치 못한 오류가 발생되었습니다.");
}
}
}
//메소드호출 시 예외전달 가능
// => try{ }구문 안에 - 객체 생성 & 메소드호출 같이 해도 되지만, try{ }구문 밖에 - 객체 생성
// => try{ }구문 안에 - 메소드호출 따로 해도 됨, 단 try{ }구문이 끝나면 객체소멸
4. "일반 예외"의 예외전달 후 예외처리
💜PasswordMatchApp.java - 일반예외발생
package xyz.itwill.exception;
import java.util.Scanner;
//키보드로 정수값을 입력받아 저장된 비밀번호와 비교하여 비교결과를 출력하는 프로그램 작성
public class PasswordMatchApp {
public static void main(String[] args) {
//1. 💜그동안 작성해온 예외처리 안된 프로그램을 작성해보자!
/*
Scanner scanner=new Scanner(System.in);
System.out.print("비밀번호 입력 >> ");
// => 3개의 Exception 발생 가능함
// => InputMismatchException, rangeNoSuchElementException, exhaustedIllegalStateException
int password=scanner.nextInt();
if(password==123456) {
System.out.println("[결과]입력된 비밀번호가 맞습니다.");
} else {
System.out.println("[결과]입력된 비밀번호가 다릅니다.");
}
scanner.close();
*/
//2. 💜예외처리된 프로그램으로 변경해보자!
// => 💜 알고가기
// => throw : 인위적으로 예외객체를 생성하여 예외를 발생시키는 명령
// => throw new 예외클래스(String message);
// => 여기서 에외클래스란? 런타임을 상속받지 않은 일반 예외클래스를 의미
// => 고급(대형)프로그램 : 비정상적인 결과를 발생할 때 인위적예외를 일부러 직접 발생시켜 예외를 전달하여 프로그램 작성함
Scanner scanner=new Scanner(System.in);
try {
System.out.print("비밀번호 입력 >> ");
int password=scanner.nextInt();//InputMismatchException 발생 가능
if(password!=123456) {
//인위적으로 예외 객체를 생성하여 예외를 발생시키는 명령 - 프로그램의 흐름이 catch 블럭으로 이동하여 명령 실행
//형식)throw new 예외클래스(String message);
throw new PasswordMismatchException("[결과]입력된 비밀번호가 다릅니다.");
}
//인위적 예외가 발생되지 않을 경우 실행되는 명령
System.out.println("[결과]입력된 비밀번호가 맞습니다.");
} catch (InputMismatchException e) {
System.out.println("[에러]숫자만 입력 가능합니다.");
} catch (PasswordMismatchException e) {
System.out.println(e.getMessage());
} finally {
scanner.close();
}
}
}
💜PasswordMismatchException.java - 개발자가 직접 만든 일반 예외클래스
- 프로그램 개발자가 직접 선언한 예외클래스
- 반드시 Exception 클래스를 상속받아 작성
- 대형프로그램에 효율적
package xyz.itwill.exception;
//프로그램 개발자가 직접 선언한 예외클래스
// => 반드시 Exception 클래스를 상속받아 작성
public class PasswordMismatchException extends Exception {
//경고를 없애기 위한 serialVersionUID 필드 선언
//=> 객체직렬화클래스가 되기 위해서 필요한 필드 (입출력 프로그램만들 때 배울예정)
private static final long serialVersionUID = 1L;
//기본생성자
public PasswordMismatchException() {
// TODO Auto-generated constructor stub
}
//🍑매개변수가 있는 생성자 (필수!!!!!)
public PasswordMismatchException(String message) {
//Exception 클래스에는 예외 메세지를 저장하기 위한 필드 선언
// => super 키워드를 사용하여 Exception 클래스의 필드에 초기값(예외 메세지) 저장
super(message);
}
}
반응형
'java > java.lang' 카테고리의 다른 글
[java/lang] 8. 입출금프로그램 (feat. 다중 스레드) (1) | 2024.06.17 |
---|---|
[java/lang] 7. Thread 클래스 (1) | 2024.06.16 |
[java/lang] 5. StringBuffer 클래스 (0) | 2024.06.15 |
[java/lang] 4. Wrapper 클래스 (1) | 2024.06.15 |
[java/lang] 3. String 클래스 (0) | 2024.06.14 |