일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 미국유학생
- i-20
- 개인 프로젝트 개발일지
- 비전공자 git
- 자바 스터디
- 복수학위제도
- 미국대학생활
- California State University Sacramento
- jpa
- 개발일지
- 미국유학생활
- 만다라트프로젝트
- 미국유학
- 파이데이아창의인재학과
- F1학생비자
- 미국대학
- Java 스터디
- Kenneth Park
- 케네스로그
- 자바
- 2+2
- 사이드프로젝트
- JVM아키텍처
- 유학생 준비물
- 부산외대
- 해외유학
- 유학생대학생활
- 케네스
- java
- CSUS
- Today
- Total
케네스로그
[Java] 예외처리 본문
에러(Error)는 프로그램의 비정상적인 종료를 뜻한다. 에러는 두가지로 나뉘어질 수 있는데, 컴파일에러와 런타임 에러가 존재한다. 컴파일에러는 보통의 IDE 차원에서 문법 검사 등으로 확인해주기때문에 프로그램 시작 전에 알 수 있다. 하지만, 런타임 에러는 프로그램이 동작하는 과정에서 발생한다.
런타임 에러는 JVM이 정상적으로 프로그램 동작수행을 할 수 없기에 종료되는 것이며, 이것을 개발자가 핸들링 할 수 있는 방법은 없다. 애초에 코드를 짤 때부터 발생하지 않도록 해야하며, 에러는 로그를 남기거나 종료되기전 적절한 메시지를 보여주는 방법 등을 쓸 수는 있다. 메모리 부족으로 인한 프로그램의 강제 종료를 예로 들 수 있다.
예외(Exception)는 에러와 달리 복구할 수 있으며 프로그램의 종료를 피해서 개발자가 핸들링할 수 있다. 예를 들어, 이메일 입력창에 이메일 형식이 아닌 전화번호를 기입하는 경우, 예외 발생(Illegal Argument Exception)을 처리하는 로직을 짤 수 있다.
Error Exception
Error | Exception | |
발생 원인 | 컴퓨터 하드웨어의 오동작 또는 고장으로 JVM 실행에 문제가 발생 | 사용자의 잘못된 조작 또는 개발자의 잘못된 설계로 인해 발생 |
영향을 받는 대상 | 프로세스 | 쓰레드 |
복구 | 불가 | 가능 |
패키지 | java.lang.error | java.lang.Exception |
예시 | IOError, OutOfMemoryError etc | NullPointerException, SqlException etc |
자바 예외 계층 구조
출처: https://madplay.github.io/post/java-checked-unchecked-exceptions
자바에서는 예외를 클래스로 관리한다. JVM은 실행 중 예외(Exception)나 에러(Error)가 발생하면 이를 객체로 만든다. 그 후, 예외 처리 코드에서 생성된 예외 객체를 이용할 수 있도록 한다.
모든 예외(Exception)와 에러(Error)는 Throwable 클래스의 하위 클래스이다.
Error는 앞서 언급한것처럼 사전에 감지할 수 없는 상황이기때문에 Unchcked Exception에 해당된다.
Exception은 Unchecked Exception과 Checked Exception으로 나뉘어진다.
Checked Exception
컴파일러 수준에서 확인이 가능한 에러를 checked exception이라고 한다. 즉, 예상이 가능한 부분이기때문에 try-catch구문을 통해 핸들링할 수 있다.
Unchecked Exception
Unchecked exception은 컴파일러가 감지하지 못하는 예외를 말한다. 자바에서는 Runtime Exception, Error, 그 하위 클래스들이 이에 속한다. Error는 앞서 언급했듯이 개발자가 핸들링할 수 있는 것이 아니기때문에 예외처리가 불가능하다. 반면, Exception 중 Runtime Exception의 하위 클래스에 해당하는 예외들은 개발자가 직접 예외처리를 해야만 한다.
왜 exception을 두가지로 나누었을까? 출처: https://wisdom-and-record.tistory.com/46
Runtime Exception은 프로그램 코드의 문제로 발생하는 예외로써, 메소드를 호출하는 쪽(클라이언트)에서 이를 해결하거나 대처할것으로 예상하기 힘들다. Runtime Exception은 프로그램 동작 수행 중 빈번하게 발생할 수 있기 때문에 모든 Runtime Exception를 체크한다면 프로그램의 명확성을 떨어뜨릴 수 있다. 따라서, 메소드를 호출하는 쪽(클라이언트)가 에외상황을 적절히 대처할 수 있다면 checked exception으로 만들고, 그렇지 않은 경우엔 unchecked exception으로 만든다.
Runtime Exception
- NullPointerException
가장 빈번하게 발생하는 예외로써, null값을 가진 참조 변수로 객체 접근 연산자(.)을 사용했을때 발생한다.
String s = null;
System.out.println(s.toString()); // NullPointerException
- ArrayIndexOutOfBoundsException
배열에서 인덱스의 범위를 초과하여 참조하는 경우에 발생한다.
int[] nums = new int[3];
System.out.println(nums[5]); // ArrayIndexOutOfBoundsException
- NumberFormatException
문자열을 파싱하는 과정에서 적절치 못한 데이터가 주어질때 발생한다.
String data = "abc"
int value = Integer.parseInt(data); // NumberFormatException
- ClassCastException
ClassCastException은 클래스, 인터페이스 간 타입변환에서 발생하는 예외를 말한다.
Animal animal = new Dog();
Cat cat = (Cat) animal;
자바에서 예외처리 하는 방법
try-catch
try {
...
} catch (ExceptionClass variableName1) {
...
} catch (ExceptionClass variableName2) {
...
}
try블록은 수행할 코드로써, 예외 발생 가능성이 있는 블록
catch블록에 예외클래스에 해당하는 예외가 발생하면 실행할 블록. 1개 이상의 다중 catch블록도 가능하다.
- printStackTrace(): 예외 발생 시 호출스택에 있는 메소드의 정보와 예외 메시지를 출력
- getMessage(): 발생한 예외 클래스의 인스턴스에 저장된 메시지 반환
자바 7 이후부터는 catch 블록에 1개 이상의 Exception 객체를 받도록 할 수 있다. 하지만, Exception객체들이 조상과 자손 관계이면 에러가 발생한다.
catch (ArithmeticException | IOException e) {
e.printStackTrace();
throw e;
}
throw
public static void main(String[] args) {
int i = 10;
int j = 0;
divide(i, j);
}
public static int divide(int i, int j) {
if(j == 0) {
System.out.println("j는 0이 되면 안됩니다");
return 0;
}
return i / j;
}
위의 방법으로 ArithmeticException을 해결할 수 있지만, 잘못된 값(0을 리턴)을 전달하는 것 또한 문제가 된다.
public static void main(String[] args) {
int i = 10;
int j = 0;
divide(i, j);
}
public static int divide(int i, int j) {
if(j == 0) {
throw new IllegalArgumentException("0으로 나눌수없습니다.");
}
return i / j;
}
특정 경우 새로운 Exception을 생성하여 직접 예외를 발생시킬 수 있다.
throws
메소드 선언부에 throws키워드를 사용하여 예외를 발생시킨 메소드에서 예외를 처리하도록 한다. throws 키워드를 지닌 메소드를 호출하는 메소드(클라이언트)에서 try-catch를 통해 예외처리를 반드시 해줘야 한다. 즉, 예외를 처리하는 책임의 주체를 메소드를 호출하는 쪽으로 전가시킨다.
선언부에 예외를 선언해둠으로써 명시적으로 어떤 예외가 일어날 수 있는지 직관적으로 알 수 있다는 장점이 있다.
public static void main(String[] args) {
int i = 10;
int j = 0;
divide(i, j);
} catch (ArithmeticException e) {
System.out.println(e);
}
public static int divide(int i, int j) throws ArithmeticExceptin {
return i / j;
}
<aside> 💡 thorws vs thorw
</aside>
finally
finally 블록은 try 블록이 끝나거나 예상치 못한 에러가 발생하더라도 실행되는 블록이다. 하지만, JVM이 try catch 블록을 실행 중 종료되었다면 finally블록은 실행되지 않는다.
Thread가 try catch 블록을 실행 중 interrupt 당하거나 kill 된다면 finally 블록은 실행되지 않는다.
try-catch-resource
참조: https://catch-me-java.tistory.com/46 https://wisdom-and-record.tistory.com/46
자바 7 이후부터는 try-catch-resource를 사용할 수 있으며, 이것은 InputStream, ServerSocket, DB커넥션 등을 안전하게 사용할수 있도록 지원한다.
FileInputStream fis = null;
try {
fis = new FileInputStream("not_exist.txt");
} catch (IOException e) {
e.printStackTrace();
} fianlly {
if(fis!=null) {
try {
fis.close(); // FileInputStream을 close해줘야한다.
} catch (IOException e) {
e.printStackTrace();
}
}
}
try구문에서 close가 필요한 코드가 있다면 바이트코드를 조작하여 자원을 반환한다. 모든 객체가 자동으로 반환되는것은 아니며, AutoCloseable 인터페이스를 구현한 클래스만 자동으로 반환된다.
try(
FileInputStream fis = new FileInputStream("not_exist.txt")
) {
System.out.println(fis.read());
} catch (IOException e) {
e.printStackTrace();
}
커스텀한 예외를 만드는 방법
public class {Exception_Name} extends Exception {
...
}
Exception이나 Exception의 후손을 상속받아 만들어진 클래스
클래스의 이름만으로 어떤 오류가 발생했는지 알려주어 코드의 직관성을 높인다.
public class BizException extends RuntimeException {
public BizException(String msg) {
super(msg);
}
public BizException(Exception ex) {
super(ex);
}
}
예외 되던지기 (exception re-throwing)
한개의 메소드에서 발생할 수 있는 예외가 여러개라면, 일부는 메소드 내부에서 throw를 통해 해결하고, 일부는 선언부에서 throws를 통해 메소드를 호출한 쪽(클라이언트)에서 해결하도록 할 수 있다. 이를 예외 되던지기라고 한다.
public class ExceptionDemo {
public static void main(String[] args) {
try {
methodA();
} catch (Exception e) {
System.out.println(“main에서 예외 처리”);
}
}
static void methodA() throws Exception {
try {
throw new Exception();
} catch (Exception e) {
System.out.println(“methodA에서 예외 처리”);
throw e;
}
}
}
// get this example code from wisdom-and-record.tistory.com
Chained Exception
한 예외가 다른 예외를 발생시키는 경우가 있다. 예를 들어, 예외A가 예외 B를 발생시켰다면, A는 B의 원인 예외(cause exception)이라고 한다. 원인 예외는 initCause()로 지정할 수 있으며, Throwable클래스에 정의되어 있기 때문에 모든 예외 클래스에서 사용할 수 있다.
public class ExceptionDemo {
public static void main(String[] args) {
try {
methodA(0);
} catch (Exception e) {
e.printStackTrace();
}
}
static void methodA(int num) throws IOException{
try {
if (num == 0) {
throw new IllegalArgumentException();
}
} catch (IllegalArgumentException e) {
IOException ioException = new IOException();
ioException.initCause(e); /// IOException의 예외를 IllegalArgumentException으로 지정/
throw ioException;
}
}
}
// get this example code from wisdom-and-record.tistory.com
'Dev > Java' 카테고리의 다른 글
[Java] 인터페이스 (0) | 2022.02.20 |
---|---|
[Java] 패키지 (0) | 2022.02.18 |
[Java] 메소드 디스패치 (0) | 2022.02.16 |
[Java] 상속, super() (1) | 2022.02.15 |
[Java] 객체의 생성, 인스턴스화, 생성자, this 키워드 (0) | 2022.02.09 |