예외처리
Error / Exception
오류의 종류에는 다음과 같은 것이 있다.
- 컴파일 에러 : 소스상의 문법 에러
- 런타임 에러 : 입력값이 틀렸거나, 배열의 입력 범위를 벗어났거나 계산식의 오류 등으로 인해 발생
- 논리 에러 : 문법상 문제가 없고, 런타임에러도 발생하지 않지만, 개발자 의도대로 작동하지 않는 에러
- 시스템 에러 : 컴퓨터 오작동으로 인한 에러 . => 소스 구문으로 해결 불가능
Error와 Exception에는 차이가있는데, 이를 알아보자
Error
- 프로그램 진행시 치명적 상황이 발생한 것. 소스상 해결 불가.
ex) OutOfMemoryError, StackOverflowError 등
1. OutOfMemoryError
- jvm이 할당한 heap영역을 모두 소진한 경우.
- 해결방법 : heap메모리를 늘리던지, 적절하게 코드를 수정해야 한다.
private void test1() {
long[] arr=new long[Integer.MAX_VALUE];
}
2. StackOverflowError
- 메소드호출스택을 모두 소진한 경우
- 종료조건이 적절히 설정되지 않은 재귀메소드 호출 시 발생하기가 쉬움.
private void test2() {
test2();
}
Exception
- 프로그램 오류중 적절한 코드에 의해서 수습될 수 있는 오류. 예외발생상황을 예측해서 미리 예외처리코드를 작성해둔다.
ex)NullPointerException, ArithmeticException, IOException 등
이중, Ctrl + T를 눌러서 에러의 부모자식관계를 확인할 때
RumtimeException의 후손인 것들은 Unchecked Exception (언체크드 익셉션), 아닌것들은 checked Exception(체크드 익셉션) 이라고 한다.
언체크드 익셉션은 예외처리 강제화가 없고, 확인이 불가능하지만
체크드 익셉션은 예외처리가 강제화 되어있어, 예외처리를 안하면 빨간줄이 생기며 컴파일 오류가 발생한다.
예외처리는 try catch 문으로 가능하다.
try {
// 오류가 발생할 수 있는 코드
} catch (오류 이름 e ) {
//처리 방법
} catch ( ~~~ e ) {
// 처리방법
} ...
...
} finally {
//try가 시행되어도, 조기 리턴이 되어도 실행할 강력한 구문. 사용한 자원(메모리)를 반납한다.
}
try catch문은 위와 같이 쓴다. catch를 여러개 두어 여러가지 오류 상황에 대비할 수도 있고, finally라는 강력한 구문도 존재한다. 만약 try절에서 예외가 발생하면 그 하위코드는 실행하지 않고 catch절로 넘어간다.
catch절의 다형성
- 부모타입의 catch 절에서 자식예외객체를 처리할 수 있다.
- 자식, 부모타입의 catch절을 모두 써야하는 경우 자식 catch절을 먼저 작성한다.
사진 설명을 입력하세요.
try{
String s=null;
s.hashCode();
} catch (NullPointerException e) {
System.out.println("NPE 처리");
} catch (RuntimeException e){
e.printStackTrace();
}
아래와 같이는 쓸 수 있지만,
try{
String s=null;
s.hashCode();
} catch (RuntimeException e){
e.printStackTrace();
} catch (NullPointerException e) {
System.out.println("NPE 처리");
}
위와 같이 사용하면 RuntimeException 에서 NullPointerException도 포함되기 때문에 오류가 발생한다.
/* 자주 애용하는 try catch블럭
모든 예외처리 가능 */
try {
} catch (Exception e) {
e.printStackTrace();
}
Checked Exception의 특징
1. 예외처리 강제화 . try catch구문을 써야 한다.
2. 메소드 선언부에 해당 외를 던진다는 선언을 추가해서 예외처리를 호출부로 전가한다.
private void test2() {
try {
checkAgeOrThrow(); // 미성년자인 경우 예외던지는 메소드 . 진행시 아래의 adultgame은 실행x
adultGame();
} catch (UnderAgeException e) {
System.out.println("당신의 나이는 " + e.getMessage() + "세, 미성년자입니다.");
System.out.println("미성년자는 이용할 수 없습니다.");
} catch (Exception e) {
System.out.println(e.getMessage());
System.out.println("미성년자는 이용할 수 없습니다.");
}
}
이런 실행구문이 있다고 할 때,
private void checkAgeOrThrow() {
System.out.print("나이를 입력하세요 : ");
int age = sc.nextInt();
if (age < 20)
throw new RuntimeException(String.valueOf(age));
}
다음과 같이 쓸 수 있다.
또한 RuntimeException을 UnderAgeException으로 이름을 보다 정확히 명명하고, 클래스를 따로 만들어 줄 수도 있다.
CheckedException(예외처리강제화)의 경우 class 명 뒤에 extends exception을 붙인다.
UnderAgeException은 RuntimeException이므로 class명 뒤에 extends RuntimeException을 붙이고,
클래스 안에는 Alt+Shift+S 로 슈퍼생성자를 모두 불러와 적는다.
Throws와 throw
//메인함수
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
ThrowStudy study = new ThrowStudy();
try{
study.test3();
} catch(FileNotFoundException e){
}
}
private void test3() throws FileNotFoundException{
FileReader fr = new FileReader("test.txt"); //파일이 존재하지 않는다고 가정
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
ThrowStudy study = new ThrowStudy();
study.test3();
}
private void test3(){
try {
FileReader fr=new FileReader("test.txt");
} catch(FileNotFoundException e) {
e.printStackTrace();
System.out.println("파일을 찾을 수 없습니다.");
}
}
위와 아래는 같은 코드이다. 함수 안에서 예외처리를 해줄 수 도 있고, (아래 코드)
메소드에서 throws 선언 후, 실행 메인함수에서 예외처리를 해줄수도 있다. (위의 코드)
다만 메소드 뒤에는 throws이고, 실제로 예외를 던지는 경우는 throw를 쓴다.
Overriding Throws
public static void main(String[] args){
Child child = new Child();
}
class Parent {
public void foo() throws SQLException, IOException{
}
}
class Child extends Parent{
}
다음과 같은 구조의 코드가 존재할 때, main에서 child.foo();를 그냥 쓰면 오류가 발생한다.
Parent의 foo()를 그대로 물려받았기 때문에 예외처리 역시 자식클래스에서 사용하려면 또 해줘야 하는 것이다.
매번 이런식으로 사용을 할 때마다 불편하게 예외처릴 할 수는 없다.
굳이 예외처리가 필요하지 않은 경우,
class Child extends Parent { //------(1)
@Override
public void foo(){
}
}
class Child extends Parent { //------(2)
@Override
public void foo() throws SQLException{
}
}
위와 같이 예외를 자식 클래스 내에서 오버라이드 하여 줄일 수 있다.
예외를 전부 없앤 (1)의 코드로 쓴다면, child.foo();를 main에서 그냥 사용할 수 있다.
마지막으로 체크드와 언체크드의 구분 !!
Runtime을 기준으로 나눈다는 것을 잊지 말자
ㅎ ㅏ ㅇ ㅏ.................
점점 복습에 걸리는 시간이 길어진다
흑흑
원래 수업끝나고 바로잤는데
끝나고도 공부하고 일어나서도 해야되게 생겼다
^^
이게 다 코로나때문^^!
kt aivle들을때는 스터디하고 그래서 공부 동기부여도 잘됐는데
혼자하려니까 더 오래걸린다 ㅇ_ㅠ
예외 throw, throws관련 정리 잘된 블로그