문법/기본 문법
예외처리
코딩 화이팅
2023. 1. 30. 14:10
Error
- 메모리 부족, stack overflow 와 같이 일단 발생하면 복구할 수 없는 상황->코드를 써서 해결 불가능
- 프로그램의 비정상적 종료를 막을 수 없음 -> 디버깅 필요
Exception
- 읽으려는 파일이 없거나, 네트워크 연결이 안 되는 등 수습될 수 있는 비교적 상태가 약한 것들
- 프로그램 코드에 의해 수습될 수 있는 상황
예외<->에러
- 둘 다 어떤 원인에 의해 오동작하거나 비정상적으로 종료되는 경우
- 코드를 통해서 프로그램의 비정상적 종료를 막을 수 있는가
- 프로그래밍을 통해서 대체가 가능한가? 그럴 필요가 있는가? 프로그램의 관심사인가?
예외처리
- 예외 발생 시 프로그램의 비정상 종료를 막고 정상적인 실행 상태를 유지하는 것
- 예외의 감지 및 예외 발생 시 동작할 코드 작성 필요
- 쓰는 이유? : 주된 관심사와(메서드의 본래의 기능) 보조관심사 분리 / 미리 발생할 수 있는 문제점(메서드에 throws 발생할 수 있는 예외)을 알려주는 효과 / 메서드 잘못 사용 방지 ex)Integer.parsent("문자열")->정수
Checked exception(Exception 클래스의 상속(RuntimeException 상속 X))
예외에 대한 대처 코드가 없다면 컴파일이 진행되지 않음(강제)
Unchecked exception(RuntimeException의 하위 클래스)
예외에 대한 대처 코드가 없더라도 컴파일은 진행됨.
package test01;
public class test1 {
public static void main(String[] args) {
int[] nums= {10};//인덱스는 0뿐
//java.lang.ArrayIndexOutOfBoundsException
System.out.println(nums[1]);
//java.lang.ArrayIndexOutOfBoundsException: 1
System.out.println(nums[-1]);//오버플로우가 발생할 때 음수가 나올 수 있다->int보다는 long
//java.lang.ArrayIndexOutOfBoundsException: -1
int num=5/0;
//java.lang.ArithmeticException: / by zero
int num=Integer.parseInt("ssafy");
//java.lang.NumberFormatException
예외는 언제 발생? throw 키워드 사용해서
new 예외생성자()->예외 객체
예외 객체를 던질 때 발생
예외가 발생? 내부적으로 예외 객체가 생성돼서 던져진 것
// throw new ArrayIndexOutOfBoundsException(); //nums[2]
// throw new ArithmeticException();
// throw new NumberFormatException();
}
}
예외 처리 키워드
- 직접 처리
- try
- catch
- finally
try {//try 문 안에서 예외처리가 난다면
throw new Exception();
} catch (Exception e) {//catch문 안에 있는 메소드 출력
System.out.println("예외를 처리합니다.");
}
System.out.println("프로그램 끝.");
//예외를 처리합니다.
// 프로그램 끝.
============================================================================
package test01;
public class test2 {
public static void main(String[] args) {
//try~catch 문 사용
int[] nums={10};
try {
System.out.println(nums[1]);
//발생한 예외 : ArrayIndexOutOfBoundsExceqtion
// }catch(ArrayIndexOutOfBoundsException e) {//ArrayIndexOutOfBoundsExceqtiond이거나, 이 클래스의 자식 객체만
}catch(Exception e) {//어떤 예외든 처리 가능
//catch가 잡을 수 있는 예외 객체
//catch() 안에 온느 예외 클래스는
//그 예외 클래스이거나, 그 클래스의 자식 클래스인 경우
System.out.println("배열의 크기가 넘어가면 대처 코드");
}
System.out.println("프로그램이 정상 종료");
}
배열의 크기가 넘어가면 대처 코드
프로그램이 정상 종료
}
try {
int num=Integer.parseInt("ssafy");
}catch(ArithmeticException e) {
System.out.println("해당 문자열은 정수로 바꿀 수 없어요");
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("인덱스 범위가 넘어갔네요");
}catch(Exception e) {//모든 예외를 처리할 수 있는 블록
//다형성이 적용.
System.out.println("모든 예외처리 가능");
}
//모든 예외처리 가능
}
}
=======================================================================
package test01;
public class test4 {
public static void main(String[] args) {
//try ~ catch ~ catch
try {
int num=Integer.parseInt("ssafy");
//다중 예외처리를 할 때는 순서가 중요
//자식 예외를 먼저 검사하고, 나중에 큰 예외를 검사
}catch(Exception e) {//모든 예외를 처리할 수 있는 블록
//다형성이 적용.
System.out.println("모든 예외처리 가능");
}catch(ArithmeticException e) {
System.out.println("해당 문자열은 정수로 바꿀 수 없어요");
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("인덱스 범위가 넘어갔네요");
}
//error
}
}
package test01;
public class test5 {
public static void main(String[] args) {
//try ~ catch ~ catch
try {
int num=Integer.parseInt("ssafy");
}catch(ArithmeticException e) {
System.out.println("해당 문자열은 정수로 바꿀 수 없어요");
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("인덱스 범위가 넘어갔네요");
}
//해당하는 catch 블록을 만나지 못한다면
//예외는 처리되지 않는다.
// }
}
}
======================================================================
package test01;
public class test6 {
public static void main(String[] args) {
//try ~ catch ~ catch
try {
int num=Integer.parseInt("ssafy");
//|연산자를 이용해서, 하나의 catch 블록에서
//다양한 종류의 예외를 동시에 처리 가능
}catch(ArithmeticException |ArrayIndexOutOfBoundsException| NumberFormatException e) {
System.out.println("하나의 블록에서 세 가지 예외를 처리합니다.");
}
//하나의 블록에서 세 가지 예외를 처리합니다.
}
}
- 간접 처리
- throws
- 사용자 정의 예외 발생시킬 때
- throw
try~catch 문에서의 흐름
- try 블록에서 예외가 발생하면 JVM이 해당 Exception 클래스의 객체 생성 후 던짐(throw) : throw new XXException()
- 던져진 exception을 처리할 수 있는 catch 블록에서 받은 후 처리 (적당한 catch 블록을 만나지 못하면 예외처리는 실패)
- 정상적으로 처리되면 try-catch 블록을 벗어나 다음 문장 진행
- try 블록에서 어떠한 예외도 발생하지 않은 경우 catch문을 거치지 않고 try-catch 블록의 다음 흐름 문장을 실행
다중 exception handling
- try 블록에서 여러 종류의 예외가 발생할 경우
- 하나의 try 블록에 여러 개의 catch 블록 추가 기능(예외 종류별로 catch 블록 구성)
다중 catch 문장 작성 순서 유의 사항
- JVM이 던진 예외는 catch 문장을 찾을 때는 다형성이 적용됨.(그 블록은 그 클래스 또는 그 클래스의 자식)
- 상위 타입의 예외가 먼저 선언되는 경우 뒤에 등장하는 catch 블록은 동작할 기회가 없음
- 상속 관계가 없는 경우는 무관
- 상속 관계에서는 작은 범위(자식)에서 큰 범위(조상)순으로 정의
package test01;
public class test7 {
public static void main(String[] args) {
//try catch finally
try {
String str="1234";
System.out.println("code 1 - before pare : "+str);
int num = Integer.parseInt(str);
System.out.println("code 2 - after pare : "+str);
}catch(Exception e) {
System.out.println("code 3 - exception handling을 완료");
}finally {
// //언제나 실행 된다.
System.out.println("code 4 - 언제나 실행? O");
// }
System.out.println("code 5 - 언제나 실행? X");
System.out.println("프로그램의 끝");
// code 1 - before pare : ssafy
// code 3 - exception handling을 완료
// code 4 - 언제나 실행? O
// code 5 - 언제나 실행? X
// 프로그램의 끝
try {
String str="1234";
System.out.println("code 1 - before pare : "+str);
int num = Integer.parseInt(str);
System.out.println("code 2 - after pare : "+str);
}catch(Exception e) {
System.out.println("code 3 - exception handling을 완료");
}finally {
// //언제나 실행 된다.
System.out.println("code 4 - 언제나 실행? O");
}
System.out.println("code 5 - 언제나 실행? X");
System.out.println("프로그램의 끝");
// code 1 - before pare : 1234
// code 2 - after pare : 1234
// code 4 - 언제나 실행? O
// code 5 - 언제나 실행? X
// 프로그램의 끝
try {
String str="1234";
System.out.println("code 1 - before pare : "+str);
int num = Integer.parseInt(str);
System.out.println("code 2 - after pare : "+str);
return;
}catch(Exception e) {
System.out.println("code 3 - exception handling을 완료");
}finally {
// //언제나 실행 된다.
System.out.println("code 4 - 언제나 실행? O");
}
System.out.println("code 5 - 언제나 실행? X");
System.out.println("프로그램의 끝");
// code 1 - before pare : 1234
// code 2 - after pare : 1234
// code 4 - 언제나 실행? O
try {
String str="ssafy";
System.out.println("code 1 - before pare : "+str);
int num = Integer.parseInt(str);
System.out.println("code 2 - after pare : "+str);
}catch(Exception e) {
System.out.println("code 3 - exception handling을 완료");
return;
}finally {
//언제나 실행 된다.
System.out.println("code 4 - 언제나 실행? O");
}
//언제나 실행이 되지 않는다.
//try , catch, finally 블록 안에 return이 있다면
//메인 메서드는 그 순간 종료되므로.
System.out.println("code 5 - 언제나 실행? X");
System.out.println("프로그램의 끝");
//code 1 - before pare : ssafy
// code 3 - exception handling을 완료
// code 4 - 언제나 실행? O
//finally가 필요한 이유?
//DB 연결하는 상황
//연결을 종료할 때, 관련된 리소스들을 정리할 필요
//파일 입출력 - 입출력 stream, 관련된 리소스들을 정리
try~catch~finally구문
- finally는 예외 발생 여부와 상관 없이 언제나 실행
- 중간에 return을 만나는 경우도 finally 블록을 먼저 수행 후 return 실행
package test02;
import java.io.FileNotFoundException;
import java.io.FileReader;
public class test1 {
public static void main(String[] args) {
method1("123");
try {
method2("input.txt");
} catch (FileNotFoundException e) {
System.out.println("CheckedException이니까 반드시 처리");
}
}
public static void method1(String str) {
//numberformatexception : uncheckedexception
//굳이 예외처리 하지 않아도 컴파일은 됨.
//강제 사항 X
int num=Integer.parseInt(str);
}
//throws 키워드를 사용해서
//내 메서드 안에서 일어날 수 있는 예외를
//나를 호출한 곳으로 전가시킴
public static void method2(String filename) throws FileNotFoundException{
//filenotfoundexcepion : checked exception ->컴파일이 되지 않음
//강제 사항
//try catch 또는 throws
FileReader reader=new FileReader(filename);
}
}
throws 키워드를 통한 처리 위임
- method에서 처리해야 할 하나 이상의 예외를 호출한 곳으로 전달(처리 위임)
- 예외가 없어지는 것이 아니라 단순히 전달됨
- 예외를 전달받은 메서드는 다시 예외 처리의 책임 발생
- 처리하려는 예외의 조상 타입으로 throws 처리 가능