예외와 예외 클래스
컴퓨터 하드웨어의 오동작 또는 고장 -> 응용프로그램 실행 오류가 발생하는 것을 자바에서 -> 에러
에러 JVM 실행에 문제가 생겼다는 것
JVM위에서 실행되는 프로그램을 아무리 견고하게 만들어도 실행 불능
에러에 대처할 방법이 없음
에러 이외에 예외(exception) 오류
사용자의 잘못된 조작, 개발자의 잘못된 코딩으로 발생하는 프로그램 오류
예외가 발생되면 프로그램은 곧바로 종료
예외처리 (Exception Handling) 통해 프로그램을 종료하지 않고 정상 실행 상태가 유지
일반예외(Exception)
- 컴파일러 체크 예외
- 자바 소스를 컴파일 하는과정에서 예외 처리 코드가 필요한지 검사
- 예외 처리 코드가 없다면 컴파일 오류 발생
실행예외(Runtime Exception)
- 컴파일하는 과정에서 예외 처리 코드를 검사하지않는 예외
- 컴파일시 예외 처리를 확인 하는지 차이 일뿐
- 두가지 예외는 모두 예외 처리 필요
자바에서는 예외를 클래스로 관리
JVM은 프로그램을 실행하는 도중에 예외가 발생하면 해당 예외 클래스로 객체를 생성
예외 처리 코드에서 예외 객체를 이용 할 수 있도록 해준다.
모든 예외 클래스들은 java.lang.Exception 클래스를 상속
일반 예외는 Exception 을 상속받지만
Runtiome Exception을 상속받지 않는 클래스들
실행 예외는 다음과 같이 RuntimeException을 상속받은 클래스들
RuntimeException 역시 Exception을 상속
JVM은 RuntimeException을 상속
실행 예외
자바 컴파일러가 체크 하지 않음
개발자의 경험에 의해서 예외 처리 코드 삽입
해당 예외가 발생하면 프로그램 곧바로 종료
NullPointerException
가장 빈번한 실행 예외
객체 참조가 없는 상태
null 값을 갖는 참조 변수로 객체 접근 연산자인 도트(.) 사용
프로그램 예외가 발생하면 예외 메시지가 Console 뷰에 출력되면서 프로그램종료
Console 뷰에 출력되는 내용에는 어떤 예외 소스의 몇 번재 코드에서 발생했는지에 대한 정보
ArrayIndexOutOfBoundsException
배열에서 인덱스 범위를 초과하여 사용할 경우
public class ArrayIndexOutofBoundsExceptionExample{
public static void main(String[] args){
String data1 = args[0];
String data2 = args[2];
System.out.println("args[0] : " + data1);
System.out.println("args[0] : " + data2);
}
}
String data1 = args[0] 에서 오류 발생
두개의 실행 매개값을 주지 않았기 때문
cmd 에서 java ArrayIndexOutofBoundsExceptionExample 값 1 값 2
[Run -> Run Configurations 선택 ] [Arguments] 탭의 [Program arguments] 입력란에 입력
예외 처리 방법
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 ArraIndexOutofBoundsExceptionExample 값1 값2");
}
}
}
NumberFormatException
문자열로 되어 있는 데이터를 숫자로 변경하는 경우가 자주 발생
가자 많이 사용되는 코드
반환 타입 | 메소드명(매개변수) | 설명 |
int | Integer.parseInt(String s) | 주어진 문자열을 정수로 변환해서 리턴 |
double | Double.parseDouble(String s) | 주어진 문자열을 실수로 변환해서 리턴 |
Integer, Double 은 Wrapper 클래스
parseXXX() 메소드로 이용 문자를 숫자로 변환
문자열이 숫자로 변환되면 숫자를 리턴
숫자로 변환 될수 없는 문자가 포함 되면 -> java.lang.NumberFormatException을 발생
public class NumberFormatExceptionExample {
public static void main(String[] args){
String data1 = "100";
String data2 = "a100";
int value1 = Integer.parseInt(data);
int value2 = Integer.parseInt(data2); // NumberformatException 발생
int result = value1 + value2;
System.out.println(data1+ "+" + data2 + "=" + result);
}
}
data 변수의 "100" 문자열은 숫자로 변환이 가능
ClassCastException
타입 변환(Casting)은 상위 클래스와 하위 클래스 간에 발생하고 구현 클래스와 인터페이스 간에도 발생한다.
-> 다운캐스팅 이전에 객체를 확인 해야 한다
ClassCastException을 발생시키지 않으려면 타입변환 전에 타입변환이 가능한지 instanceof 연사자로 확인하는것 좋다
instanceof 연산의 결과가 true이면 좌향객체를 우향 타입으로변환이 가능하다
Animal animal = new Dog();
if(animail instanceof Dog){
Dog dog = (Dog) animal;
} else if(animal instanceof Cat){
Cat cat = (Cat) animal;
}
Remocorn rc = new Audio();
if(rc instanceof Television){
} else if(rc instanceof Audio){
Audio audio = (Audio) rc;
}
예외 처리 코드
프로그램에서 예외가 발생 했을 경우 프로그램의 갑작스러운 종료를 막고, 정상 실행을 유지 할수 있도록 처리 코드
자바 컴파일러는 소스 파일을 컴파일 할때 일반 예외가 발생할 가능성이 있는 코드를 발견하면 컴파일 오류를 발생
강제적으로 예외 처리 코드를 작성하도록 요구.
실행 예외는 컴파일러가 체크해주지 않기 때문에 예외처리코드를 개발자의 경험을 바탕으로 작성
예외 처리 코드는 tryc-catch-finally 블록을 이용
try-catch-finally 블록을 생성자 내부와 메소드 내부에서 작성되어 일반 예외와 실행 예외 발생 경우 예외처리를 할수 있도록 해줌
try 블록에는 예외 발생 가능 코드 위치
try 블록의 코드가 예외 발생없이 정상 실행 되면 catch 블록의 코드는 실행되지 않고 finally 블록의 코드를 실행
만약 try 블록의 코드에서 예외가 발생하면 즉시 실행을 멈추고 catch 블록으로 이동 예오 처리 코드 실행
그리고 finally 블록의 코드 실행
finally 블록은 옵션으로 생략 가능
예외 발생 여부와 상관없이 향상 실행할 내용이 있을 경우에만 finally 블록을 작성
try블록과 catch 블록에서 return 문을 사용하더라도 finally 블록은 항상 실행
이클립스 -> Unhandled exception(처리되지 않은 예외)
Class.forName() 메소드 매개값으로 주어진 클래스가 존재하면 class 리턴
존재 하지 않으면, ClassNotFoundException 예외 발생
ClassNotFoundException 예외는 일반 예외 컴파일러는 개발자로 하여금 예외처리 코드를 작성하도록 요구
public class TryCatchFinallyExample(){
public static void main(String[] args){
try {
Class clazz = Class.forNmae("java.lang.String");
} catch(ClassNotFoundException e ){
System.out.println("클래스가 존재하지 않습니다.");
}
}
}
try 문에서 예외 발생 -> Catch 문에서 예외 처리
ArrayIndexOutOfBoundsException, NumberFormatException 과 같은 실행 예외는 컴파일러가 예외 처리 코드를 체크하지 않기 때문에 이클립스에서도 빨간 밑줄이 생기지 않는다
-> 개발자의 경험에 의해 예외처리를 작성
public class TryCatchFinallyRuntimeExceptionExample{
public static void main(String[] args){
String data1 = null;
String data2 = null;
try{
data1 = args[0];
data2 = args[1];
} catch(ArrayIndexOutOfBoundsException e){
System.out.println("실행 매개값의 수가 부족합니다");
System.out.println("[실행 방법]");
System.out.println("java TryCatchFinallyRutimeExceptionExample num1 num2");
return;
}
try{
int value1 = Integer.parseInt(data1);
int value2 = Integer.parseInt(data2);
int result = value1 + value2;
System.out.println(data1 + "+" + data2 + "=" + result);
} catch(NumberFommatException e){
System.out.println("숫자로 변환할수 없습니다");
} finally
{
System.out.println("다시 실행하세요");
}
}
}
이클립스 메뉴에서 [Run - Run Configurations] 를 선택한 후 첫번째 실행 매개값을 숫자가 아닌 문자를 주고 실행
NumberFormatException 발생
예외 종류에 따른 처리 코드
다중 catch
try블록 내부는 다양한 종류의 예외가 발생
발생되는 예외별로 예외처리코드를 다르게,
-> 다중 catch 블록 작성
catch 블록 예외 클래스 타입은 try블록에서 발생된 예외의 종류
try 블록에서 해당 타입의 예외가 발생하면 catch 블록을 실행 하도록 되어있다
try{
//ArrayIndexOutOfBoundException 발생
//NumberFormatException 발생
} catch(ArrayIndexOutOfBoundsException e){
예외처리 1
} catch(NumberFormatException e ){
예외처리 2
}
catch 블록이 여러 개라 할지라도 단하나의 catch 블록만 실행,
그 이유는 try 블록에서 동시다발적으로 예외가 발생하지 않고
하나의 예외가 발생하면 즉시 실행을 멈추고 해당 catch 블록으로 이동
catch 순서
다중 catch 블록을 작성할 때 주의할 점은 상위 예외 클래스가 하위 에외 클래스보다 아래쪽에 위치
try 블록에서 예외가 발생했을 때, 예외를 처리해줄 catch 블록을 위에서 부터 차례대로 검색
만약 상위 예외 클래스의 catch 블록이 위에 있다면
하위 예외 클래스의 catch블록은 실행되 않음
-> 하위 예외는 상위 예외를 상속했기 때문에 상위 예외 타입도 되기 때문
try {
ArarayIndexOutoufBoundsException 발생
NumberFormatException 발생
} catch(Exception e)
{
예외 처리 1
} catch(ArrayIndexOutofBoundException e){
예외 처리 2 -> 발생이 안됨
}
-> ArrayIndexOutofBoundException 이 위로 오게 설정
멀티 catch
자바 7부터 하나의 catch 블록에서 여러개의 예외를 처리할수 있도록 멀티(multi) catch 기능을 추가
멀티 catch 블록을 작성하는 방법을 보여줌. catch 괄호() 안에 동일하게 처리 하고 싶은 예외를 | 로 연결
try{
ArrrayIndexOutOfBoundException 또는 NumberFormatException 발생
} catch(ArrayIndexOutOfBoundException | NumberFormatException e ){
예외 처리1
} catch(Exception e){
예외 처리2
}
자동 리소스 닫기
자바 7에서 새로 추가된 try-with-resources 를 사용하면 예외 발생 여부와 상관없이
사용했던 리소스 객체 (각종 입출력 스트림, 서버 소켓, 소켓, 각종 채녈)의 close() 메소드를 호출해서 안전하게 리소스를 닫아 준다.
*리소르란 여러가지 의미-> 데이터를 읽고 쓰는 객체
FileInputStream 객체와 파일에 쓰는 FileOutputStram 은 리소스 객체
자바 6이전까지 사용했던 코드
FileInputStream fis = null;
try{
fis = new FileInputStream("file.txt");
....
} catch(IOException e ){
} finally {
if(fis != null){
try{
fis.close();
} catch (IOException e){}
}
}
finally 블록에서 다시 try-catch 를 사용해서 close() 메소드를 예외 처리해야하므로 다소 복잡
-> 자바8 try -with-resources 를 사용하면 다음과 같이 간다
try(FileInputStream fis = new FileInputStream("file.txt")){
...
} catch(IOException e){
...
}
try 블록이 정상적으로 실행을 완료 했거나 도중에 예외가 발생하게 되면 자동으로 FileInputStream의 close() 메소드가 호출.
try()에서 예외가 발생하면 우선 close()로 리소스를 닫고 catch 블록을 실행
복수 개의 리소스 작성시
try(
FileInputStream fis = new FileInputStream("file1.txt");
FileInputStream fos = new FileOutputStreaam("file2.txt");
){
...
} catch(IOException e){
...
}
*throw new Exception(); -> 강제적으로 예외 발생 시킴
try-with-resources를 사용하기 위해서는 조건이 있는데
리소스 객체는 java.lang.AutoCloseable 인터페이스를 구현
AutoClosealbe에는 close() 메소드가 정의
try-with-resources는 close() 메소드를 자동 호출
API 도큐먼트에서 AutoCloseable 인터페이스 찾아 "All Known Implementin Classes" 를 보면 try- with -resouces 와 함께 사용할 수 있는 리소스가 어떤 것이 있는지 알수 있다.
예외 떠넘기기
메소드 내부에서 예외가 발생할 수있는 코드르 작성할 때 try-catch 블록으로 예외를 처리하는 것이 기본
경우에 따라 메소드 호출한 곳으로 예외 떠넘기기
-> throws 키워드
throws 키워드는 메소드 선언부 끝에 작성되어 메소드에서 처리하지 않은
예외를 호출한 곳으로 떠넘기는 역할
throws 키워드 뒤에는 떠넘길 예외 클래스로 쉼표를 구분해서 나열
리턴타입 메소드명(매개변수, ...) throws 예외클래스1,. 예외클래스2, ... {
}
발생할 수 있는 예외의 종류별로 throws 뒤에 나열하는 것이 일반적이지만 다음과 같이
throws Exception 만으로 모든 예외를 간다히 넘기수 있다
리턴타입 메소드명(매개변수, ..) throws Exception{
}
throws 키워드가 붙어있는 메소드는 반드시 try 블록 내에서 호출 되어야 함
그리고 catch 블록에서 떠넘겨 받은 예외를 처리
public void method1(){
try{
method2();
} catch(ClassNotFoundException e){
//예외 처리 코드
System.out.println("클래스가 존재하지 않습니다.");
}
}
public void method2() throws ClassNotFoundException {
Class clazz =Class.forName("java.lang String2");
}
호출한 곳에서 예외 처리
method1() 에서 try-catch 블록으로 예외 처리 하지 않고 throws 키워드로 다시 예외를 떠넘길수 있다.
public void method1() throws ClassNotFoundException{
method2();
}
자바 API 도큐먼트 에서 보면 throws 하는 클래스 부분들을 명시
main()메소드에서도 throws 키워드를 사용해서 예외를 떠넘길수 있다
결국 JVM이 최종적으로 예외 처리를 하게 됨
JVM은 예외의 내용을 콘솔(Console)에 출력하는 것으로 예외 처리
main () 메소드에 throws Exception 을 붙이는 것은 좋지 못한 예외 처리 방법
프로그램 사용자는 프로그램이 알 수 없는 예외 내용을 출력하고 죵료되는 것을 좋아하지 않음
main()에서 try-catch 블록으로 예외를 최종 처리하는 것이 바람직
사용자 정의 예외와 예외 발생
프로그램을 개발하다 보면 자바 표준 API에서 제공하는 예외클래스만으로는 다양한 종류의 예외를 표현 불가
애플리케이션 서비스와 관련된 예외를 얘플리케이션 예외(Application Exception) 애플리케이션 예외는 개발자가 직접 정의해서 만들어야함
-> 사용자 정의 예외
사용자 정의 예외 클래스 선언
사용자 정의 예외 클래스는 컴파일러가 체크하는 일반 예외로 선언 할 수도 있고,
컴파일러가 체크하지 않는 실행 예외로 선언 할 수도 있다.
일반 예외로 선언할 경우 Exception 을 상속
실행 예외로 선언할 경우 RuntimeException을 상속
public class XXXException extends[Exception | RuntimeException] {
public XXXException(){}
public xxxException(String message) {super(message)}
}
사용자 정의 예외 클래스 이름은 Exception으로 끝나는 것이 좋다
사용자 정의 예외 클래스도 필드, 생성자, 메소드 선언 들을 포함할 수 있다.
대부분 생성자만 선언망 포함
생성자는 두개 를 선어하는 것이 일반적,
- 하나는 매개변수 없는것
- 예외 발생 원인(예외 메시지)을 전달하기 위해 String 타입의 매개변수를 갖는 생성자
-> String 타입의 매개 변수를 갖는 생성자는 상위 클래스의 생성자를 호출, (예외 메시지 넘김)
예외 메시지의 용도는 catch {} 블록의 예외 처리 코드에서 이용하기 위해서
예외 발생 시키기
사용자 정의 예외 또는 자바 표준 예외를 코드에서 발생 시키는 법
throw new XXXException();
thorw new XXXException("메시지");
에외 객체를 생성할 때는 기본 생성자 또는 예외 메시지를 갖는 생성자 어떤 것 사용 가능
catch 블록에서 예외 메시지가 필요하다면, 예외 메시지를 갖는 생성자를 이용
예외 발생 코드를 가지고 있는 메소드는 내부에서 trey-catch 블록으로 예외를 처리할 수 잇다
대부분은 자신을 호출한 곳으로 예외를 처리하도록 throws 키워드로 예외를 떠넘김
public void method() throws XXXException {
throw new XXXException("메시지");
}
throws 키워들 포함하고 있는 메소드는 호출한 곳에서 예외처리
try{
method();
} catch(XXXException e){
// 예외 처리
}
예외 정보 얻기
try 블록에서 예외가 발생되면 예외 객체는 catch 블록의 매개변수에서 참조
매개변수를 이용하면 예외 객체의 정보를 알수 있다.
모든 예외 객체는 Exception 클래스를 상속
Exception이 가지고 있는 메소드들을 모든 예외 객체에서 호출 가능
많이 사용되는 메소드 getMessage(), printStatchTrace()
예외를 발생 시킬 때 다음과 같이 String 타입의 메시지를 갖는 생성자를 이용,
메시지는 자동적으로 예외 객체 내부에 지정
throw new XXXException("예외 메시지");
예외 메시지의 내용에는 왜 에외가 발생했는지에 대한 간단한 설명 포함
printStackTrace() 메소드 이름에서도 알수 있듯이 예외 발생 코드를 추적
모두 콘솔에 출력
어떤 예외가 어디에서 발생했는지 상세하게 출력
try{
} catch(예외클래스 e//예외 객체 생성 ){
//예외가 가지고 있는 Message 얻기
String message = e.getMessage();
//예외의 발생 경로를 추격
e.printStackTrace();
}
'Back-end > 이것이 자바다[신용권 한빛미디어]' 카테고리의 다른 글
java.lang 과 java.util 패키지 (0) | 2021.10.22 |
---|---|
자바 API 도큐먼트 (0) | 2021.10.22 |
중첩 클래스와 중첩 인터페이스 (0) | 2021.10.10 |
인터페이스 (0) | 2021.10.09 |
추상 클래스 (0) | 2021.10.04 |