
이번챕터는 스레드와 입출력에 관한 내용도 있으므로 완강 후에 다시 보자
예외 : 연산오류, 포맷오류등으로 개발자가 해결 가능한 오류
에러 : JVM 자체의 오류로 개발자가 해결할 수 없는 오류
*checked => 문법을 체크한다는 의미 = 예외처리 필수
: 예외 클래스에서 바로 상속받은 것
| 오류사항예시 | 예외발생명 | 설명 |
|---|---|---|
| Thread.sleep(1000); | InterruptedException | thread 실행 중 interrupt 발생가능 |
| class.forName("java.lang.Object"); | ClassNotFoundException | class가 없는 경우 예외발생가능 |
| isr.read(); | IOException | 입출력 수행시 예외 발생 |
| new FileInputStream("text.txt") | FileNotFoundException | 파일이 없을 경우 발생가능 |
| b1.clone(); | CloneNotSupportedException | 복제기능(클론)이 안되는 클래스가 있을때 복제가 안되는 경우 발생 |
: 예외클래스에서 상속받은 RuntimeException 클래스에서 상속받은 것
| 오류사항예시 | 예외발생명 | 설명 |
|---|---|---|
| (3/0); | ArithmeticException | 분모가 0인 연산불가인 경우 발생 |
| (B)a; | ClassCastException | 클래스 캐스팅이 불가능한 경우 발생 |
| a[3]; | ArrayIndexOutOfBoundException | 입출력할 수 없는 배열출력의 경우 발생 |
| Integer.parseInt("10!"); | NumberFormatException | 숫자가 아닌 것을 숫자로 바꿀 경우 발생 |
| Sys~(a.charAt(2)) | ⭐️NullPointerException | 객체 생성없이 멤버를 사용할 경우, 발생(static제외) |
: 일반예외와 실행예외 모두 예외처리를 통해서 정상실행 가능하게 하는 것
: try, catch, finally만 기억하면 된다
try{
//예외 발생가능 코드
//일반예외or실행예외 발생가능코드
}
catch(예외타입(클래스명) 참조변수명){
//해당 예외가 발생한 경우 처리블록
}
finally{
//예외 발생여부와 상관없이 무조건 실행블록
}
위에서 ArithmeticException으로 예시
try{
System.out.println(3/0); //에외가 발생한만한 것들
}
catch(ArithmeticException e){
System.out.pritnln("0으로 나눌 수 없습니다.");
//예외발생하면 실행, 정상이면 실행x
}
finally{
System.out.println("프로그램 종료");
System.out.exit(0); //무조건 진행
}
try{}에서 예외가 발생-->JVM에게 전달
JVM은 발생한 예외클래스에 대한 객체를 생성
-> ArithmeticException e = new ArithmeticException();
❗️❗️catch()를 호출해주는 개념일 뿐, _실제 메서드 아님
객체를 받을 수 있는 catch{}로 전달
❗️객체를 받을 수 있는 catch블록이 없는 경우, 예외처리되지 않음
try{
System.out.println(3/0);
int a= Integer.parseInt("20A");
//숫자로 바꿔주는 부분에서 예외처리대상
}
catch(ArithmeticException e){
System.out.pritnln("0으로 나눌 수 없습니다.");
}
catch(NumverFomatException e){
System.out.println("숫자로 변환할 수 없습니다.");
//예외처리방법 추가
}
finally{
System.out.println("프로그램 종료");
System.out.exit(0); //무조건 진행
}
: or(|)로 연결한다
try{
//예외 발생가능 코드
//일반예외or실행예외 발생가능코드
}
catch(예외타입A | 예외타입 B 참조변수명){
//해당 예외가 발생한 경우 처리블록
try{
System.out.println(3/0);
int a= Integer.parseInt("20A");
//숫자로 바꿔주는 부분에서 예외처리대상
}
catch(ArithmeticException | NumverFomatException e){
System.out.pritnln("프로그램을 종료합니다.");
}
: 리소스를 자동을 해지할 수 있는 문법구조(JDK 1.7이후)
기존 리소스 예외처리 : 복잡하고 close()를 작성해야만 콘솔객체를 끝낼 수 있음
InputStreamReader is = null;
try{
is = new InputStreamReader(System.in);
System.out.println(is.read());
}
catch(IOException e){
//해당 예외가 발생한 경우 처리블록
finally {
if(is!=null) {
is.close();
}
catch (IOException e){
//예외처리
}
}
개정 후 : close()를 명시적으로 없어도 존재함
try(리소스를 사용하는 코드){
//리소스를 사용하지 않는 예외 발생가능코드
}
catch(예외타입(클래스이름) 참조변수명){
//해당 예외가 발생한 경우 처리블록
finally{
//예외 여부에 상관없이 무조건 실행블록
}
try(InputStreamReader is = new InputStreamReader(system.in);) {
System.out.println(is.read());
}
catch (IOException e) {
//예외처리
}
-> 원래라면 try에 리소스를 사용하는 코드들은 close메서드(___.close())반드시 포함해야한다.
-> close()가 포함되어있는지 아닌지 알 수 있는 방법은 AutoCloseable 인터페이스를 구현해야한다
system.in은 콘솔객체, close()는 콘솔을 나가는 메서드
AutoCloseable 인터페이스 내에는 abstract close()메서드가 있기 때문이다
: 예외처리를 자신이 아닌 호출한 상위위치에서 예외처리 (책임)전가
메서드이름(..)throws 예외클래스타입
메서드가 스스로 예외를 처리한 경우
-> bcd()안에 예외처리가 다 되어있으므로 abc()에서 bcd()를 호출시, 아무런 제약조건이 없다
void abc(...){
bcd();
}
void bcd() {
try{
//예외처리 가능 블록;
}
catch(예외클래스타입 참조변수){
//예외처리
}
}
```
메서드가 자신을 호출한 다른 메서드에 예외를 전가한 경우
-> bcd()가 자기를 호출한 메서드 abc()에서 예외를 처리하도록함
void abc(...){
try{
bcd();
}
catch(예외클래스타입 참조변수) {
//예외처리
}
}
void bcd(..) throws 예외클래스타입 {
//예외가능블록
}
-> 해당예외타입을 전가하는 메서드가 포함되어있기 때문이다
ex) Thread.sleep()에서 sleep()메서드가 해당예외처리 타입(InterruptedException)을 전가하는 메서드이기 때문에 sleep()을 호출한 상위위치에서는 try-catch구문을 써야한다.
void abc(..){
try{
Thread.sleep(1000);
}
catch(InterruptedException e) {
//예외처리부분
}
}
똑같다 멀티 catch 구문을 쓰면 된다
void abc() {
try{
bcd();
}
catch(ClassNotFoundException e) {
//예외처리
}
catch(InterruptedException e) {
//예외처리
}
}
void bcd()throws ClassNotFoundException, InterruptedException {
Class cls = class.forName("java.lang.object");
Thread.sleep(1000);
}
❗️무조건 생성자를 2개 지정해야한다
class MyException extends Exception {
MyException(){//일반생성자
}
MyException(String s){
//문자열 생성자
//s에 예외메세지를 저장한다
super(s);//부모 생성자 호출
}
}class MyRTException extends RuntimeException {
MyRTException(){//일반생성자
}
MyRTException(String s){
//문자열 생성자
//s에 예외메세지를 저장한다
super(s);//부모 생성자 호출
}
}MyException me1 = new MyException();
MyException me2 = new MyException("예외메세지"); MyRTException mre1 = new MyRTException();
MyRTException mre2 = new MyRTException("예외메세지");JVM에게 throw함 !철자주의
일반예외: 예외처리하지 않으면 오류발생
throw me1;
throw me2;
throw new MyException();
throw new MyException("예외메세지");
실행예외 : 처리 안 해도 오류발생 안 함
throw mre1;
throw mre2;
throw new MyRTException();
throw new MyRTException("예외메세지");
: 예외 메세지. 예외 발생 시, 생성자로 넘긴 메시지를 출력
// 예외 객체 생성시 메세지를 전달하지 않는 경우
try{
throw new Exception();
}
catch(Exception e){
System.out.println(e.getMessage());
//null -> 전달할 메세지가 없다
}
// 메세지를 전달하는 경우
try{
throw new Exception("예외 메세지");
}
catch(Exception e){
System.out.pritnln(e.getMessage());
//예외 메세지
}
: 예외 발생이 이루어지는 경로. 호출순서를 출력
class A{
void abc() throws NumberFormatException {
bcd();
}
void bcd() throws NumberFormatException {
cde();
}
void cde() throws NumberFormatException {
int num = Integer.parseInt("10A");
}
//abc->bcd->cde cde가 예외처리 진행
}
public static void main(String[] args) {
//객체 생성
A a = new A();
// 메서드 호출 + 예외처리
try {
a. abc;
}
catch(NumberFormatException e) {
e.printStackTrace();
//JVM에게서 전달받은 객체(e)의 경로를 출력한다
}
}