오류에 비해서 심각도가 낮고, 프로그램의 정상적인 흐름만 방해하는 현상
문제 상황을 처리하는 로직을 구현하여, 런타임에서 자연스럽게 해결 가능 하다
사소한 문제들을 유연하게 처리하여 사용자들이 불편함을 느끼지 않고 서비스를 이용할 수 있도로 해주는 기능
예외의 클래스는 Exception클래스이다
그 하위 클래스들로 우리가 접할 수 있는 모든 예외 클래스들이 존재한다
Checked Exception
Unchecked Exception
예외가 발생헀을 경우에, 이 상황을 '감지'하고 '처리'하는 코드
정상적으로 프로그램의 작동 유지되며 에러에 대한 log(기록)을 남기는게 주요 목적이다
try ~ catch, throws, thorw, finally 키워드들을 이용한다
Throwable 클래스를 상속하는 자식 클래스들로 이러한 문제를 해결한다
Throwable 클래스의 주요 메소드
메소드 | 설명 |
---|---|
public String getMessage() | 발생한 예외에 대한 메세지를 반환 => 예외가발생하면 콘솔창에 뜨는 메세지를 가져오는 메서드 |
public String getLocalizedMessage() | 오버라이드하여 추가 메세지 제공 (오버라이드하지 않으면 getMessage()와 동일) => 아래의 예가있다 |
public Throwable getCause() | 예외의 원인이 되는 Throwable 객체 반환한다 |
public void printStackTrace() | 예외가 발생된 메소드가 호출될 때의 Method call stack을 출력 => 어떤메서드에 몇번째줄에서 에러가발생했는지 상세히 표시됨 (우리가 맨날 보는 에러메세지의 긴줄) |
public class Exceptions {
public static void main(String[] args) {
// try ~ catch
try {
// 예외가 발생할 수 있는 코드 작성
// 예외가 발생할 경우 예외 객체를 던짐(throw) 어디로?
} catch (Exception e) { // 던져진 예외를 받음 (catch를 이용해서)
// Exception 클래스 및 그 자식 클래스를 사용해서 받음(클래스였구나)
// 에외상황을 처리하는 코드드
}
// int[] integers = new int[10]; // 0~9까지 되야되는데 20을넣으면 에러발생
// integers[20] = 5; // Exception 발생
try {
int[] integers = new int[10]; // 0~9까지 되야되는데 20을넣으면 에러발생
integers[20] = 5;
} catch (ArrayIndexOutOfBoundsException e) {// 위에서 에러명을 출력해봐서 입력할수 있음
System.out.println(e.getMessage()); //Index 20 out of bounds for length 10
// 객체 e에 메세지를 심어준것임. 그걸 message로보여줌
//에러를 thorw해서 밑에서 catch를 해서 메세지로 출력해준상황
e.printStackTrace();// 시뻘건 메세지도 출력해주는애
// 근데 순서는 맨마지막에 출력됨 // IDE => 버그래, 순서가꼬임
// 콘솔에서 출려하면 이런에러 안뜬데, 에러자연스럽게 받아들이면됨
}
System.out.println("Programm ended normaly");
// 에러가 있었음에도 프로그램이 에러가 나지 않고 끝까지 실행되서 출력문까지 출력되고 종료
}
}
try {}안에 예외가 발생할 수 있는 코드를 작성 한다
try {
}
catch()안에 Throwable의 자식클래스들을 나열하고 {}안에 발생시 어떻게 처리해줄지 적는다
catch (Exception e) {
}
try에서 발생한 예외가 (Exception e)에 예외와 동일한 클래스(혹은 자식클래스)라면 변수 e에 담고 {}안에 수행문을 수행한다
작성된 예외명과 다른 예외가 발생할 시 예외처리가 되지 않고 그냥 예외가 발생한다(프로그램이 종료된다)
{]안에 수행될 수행문에는 Throwalbe의 주요 메서드를 사용할 수 있다
try~ catch 구문을 통해 예외 처리시 예외가 발생해도 프로그램이 종료되지 않고 끝까지 수행된다
이렇게 끝까지 프로그램이 수행되게 하는 것이 예외처리이다.
try ~ catch 구문 바깥에 출력문을 작성하고 예외가 발생해도 출력문은 실행이 된다
public class Exceptions {
public static void main(String[] args) {
// try {
// // 아주아주 예민한 내용이 실행되는 부분
// } catch(ArithmeticException e){// 에러명은 랜덤으로 입력하는 중
// // 첫번째 캐치
//
// } catch(FileAlreadyExistsException e){ // 첫번째 에러가 아니라면 두번째 케치
//
// } catch(EOFException e){
//
// } catch(IOException e){
//
// } catch(Exception e){ // 나머지 모든 Exception을 모두 catch
// // 모든 Exception 객체의 조상
//
// }
}
}
여러개의 catch 구문을 사용하면 다중으로 예외처리를 할 수 있다
특정 catch 구문에 선택되는 조건은 다형성에 의해 결정 된다
Exception 클래스는 모든 예외 클래스에 부모클래스로 사용하면 모든 예외를 모드 catch 할 수 있다
switch case의 default나 if else의 else과 비슷한 역할 이다
하지만 어떤 예외가 발생하는지 모르고 예외처리를 하는것은 위험한 방식으로 사용하길 권장하지 않는다
public class Exceptions {
public static void main(String[] args) {
try {
int[] integers = new int[20];
// integers[21] = 10;
System.out.println("던졌다?"); //
} catch (Exception e) {
System.out.println("받았다!"); // 받았다
} finally {
System.out.println("마침내!"); // 마침내!
// try에서 생성한 리소스를 회수하기 위해
}
FileInputStream file = null;
// file = new FileInputStream(("a.txt"));
// file.read(); // 두번오류 발생할 수 있음
}
}
입출력 스트림은 대표적으로 외부의 파일을 읽고 쓰기 위해서 사용하는데 한번에 그내용을 모두 메모리에 올리기 부담스러우니 스트림이라는 연결통로를 연결하여 언제든지 원하는 부분의 원하는 만큼 내용을 읽어들일수 있도록 한다 그런데 이 연결이라는 스트림은 시스템 자원에서 제공한 것으로 시스템 자원의 낭비를 막기 위해선 사용 후 close()를 통해 닫아주어야 한다. 추가로 스트림이 열려있으면 메모리가 낭비되는 부분도 있지만 열려있는 file에 리소스를 점유해버리는 문제도 발생할 수 있다. 어떤 프로그래밍이 열려있을 때 이름을 수정하거나 삭제하는 일이 안되는 경험처럼 해당 파일에 접근이 안되서 또 다른 문제가 발생할 수 도 있기 때문에 close()를 해주어야 한다
public class Exceptions {
public static void main(String[] args) {
//예시1
try {
file = new FileInputStream(("a.txt"));
file.read(); // 두번오류 발생할 수 있음 => 어디서 두번 오류발생한다는거지?
} catch (IOException e) {
System.out.println("파일 처리 실패");
} finally {
if (file != null) {
try {
file.close(); // 이것도 꼭 해줘야하는 이유가 checked exception 있기 때문
} catch (IOException e) {
System.out.println("앗!.. 아아..");
}
}
//예시2
try(FileInputStream file1 = new FileInputStream("a.txt")){
file1.read();
} catch (IOException e){
System.out.println("파일처리실패");
}
System.out.println("Programm ended normaly");
}
}
}
resource 를 회수하기 위해 finally 구문을 사용하는 경우 예시 1 처럼 중첩해서 try ~catch 구문을 사용 해야 되서 코드가 길어 진다
이런 경우 예시2 처럼 try ~ with ~ resource 구문을 사용하여 구문을 짧게 줄일 수 있다
Java 1.7에서 추가된 기능으로 AutoClosable 인터페이스를 구현하는 리소스에서 close()를 자동으로 해주는 기능이다
try(괄호안에 객체를 생성하고){다른 괄호 안에 예외가 발생할 수 있는 코드를 입력하여 사용할 수 있다}
// throws 키워드를 이용하여 예외 처리 위임
// methodA의 예외를 methodB로 넘겨서처리함
class checkedExceptionThrow {
void methodA() throws IOException {
FileInputStream file1 = new FileInputStream("a.txt");
file1.read();
file1.close();
}
void methodB() {//얘도 throws할수도 있고 직접 try catch할수도 있음
try {
methodA();
} catch (IOException e){
System.out.println("메소드에이실패"); // 처리를 methodB로 위임함
// close()에대한 처리 없음으로 지금 방식은 권장X
}
}
}
class UncheckedExceptionThrow{
void methodA(){ // 언첵트익셉션은 throws안해도 알아서 위임됨
int x= 10/0; //아리스매틱익셉션 // 런타임익셉션
//빨간줄이 안뜨는 에러기때문에 어디서 해도상관이없으니 까 안뜨는거래
}
void methodB() { // 여기서해도 아래에서 해도 되서 에러가안뜸
methodA();
}
public static void main(String[] args) {
try{
new UncheckedExceptionThrow().methodB();
} catch (ArithmeticException e){
System.out.println(e.getMessage()); /// by zero
}
}
}
Unchecked Exception 의 경우에는 throws 키워드를 사용하지 않아도 위임이 된다
예외 처리할 곳에서 try ~catch구문 통해 에외 클래스와 처리할 방식을 입력해주면 된다
class Foo{
void methodA() throws IOException{}// Checked Exception
}
class BarOne extends Foo{
void methodA() throws IOException {} // possible
}
class BarTwo extends Foo{
void methodA() throws FileNotFoundException{}// 더 자식 Exception은 possible
// FileNOtFoundException은 IOException의 자식 클래스이기 때문에 가능함
}
class BarThree extends Foo{
// void methodA() throws Exception {}
}
부모 클래스의 메소드를 오버라이드 할 때, 부모 클래스의 메소드의 예외보다 더 조상인 예외는 thorws 할수 없다
이는 오버라이드된 메서드에 일관성을 부여하는 것으로 예외 클래스의 상속관계가 이루어진다면 메서드들이 어느정도 비슷한 기능을 하게 되기 때문이다
예외를 발생시키는 키워드
new 키워드로 새 Exception 객체를 생성하여 예외 내용을 작성
void exceptMethod() throws Exception {
...
if (Err) {
throw new Exception("Some Error"); // 예외 발생 및 Message 전달
}
...
}
Exception 또는 RuntimeException 클래스를 상속하여 작성
class MyException extends RuntimeException {//Runtime 상속했으니 Unchecked Exception이 된다
enum ErrorCode { // Enum이용해서 예외내의 에러코드들을 작성해준다
ERROR_A, ERROR_B;
}
private ErrorCode errorCode;// Errocode 저장할 수 있게 변수만들어주기
public MyException(ErrorCode errorCode, String message) {// 원래는 message만 초기화하는게 기본// 예제에서는+@로 errocode도 표시되어잇음
super(message);
this.errorCode = errorCode;
}
@Override
public String getLocalizedMessage() {// 위에서 봤던 geLocalizedMessage를 재정의한 것
String message = getMessage();// 그냥 getter메서드
...
return localizedMessage;// 재정의한 에러메세지를 담아줌 // 기본은 그냥 getMessage해주는것
}
}