2022.12.15-4 JAVA 복습 예외처리
11. 예외처리
11.1 예외와 예외클래스
에러 : 불가항력적인거 갑자기 전원이 꺼지거나 메모리 부족으로 꺼지는거 등등 외부요인으로 발생하는거
예외: 잘못된사용, 잘못코딩 발생시 곧바로 꺼짐.
정상x 비정상적인거 '내가' 코드를 잘못짜서 발생하는거 예측가능 발생시 정상적으로 돌아가도록하기
프로그램을 아무리 잘작성해도 발생할수있다. 예외가 발생해도 정상적으로 될수잇게끔
일반예외(exception) 컴파일러가 예외 처리 코드 여부를 검사하는 예외
코드작성하다 이미 알수잇음. 작성할때 표시되서 알수있음.
실행예외(Runtime exception) 컴파일러가 예외처리코드 여부를 검사하지 않는 예외
실행하면서 발생하는 거 잘몰라서 경험에 의해서 거를 필요가 있음.
예외가 발생시 예외 객체가 만들어짐. 이 객체는 예외 처리시 사용된다.
자바의 모든 에러와 예외 클래스는 Throwable을 상속받아 만들어지고 추가적인 예외 클래스는
java.lang.exception 클래스를 상속받는다.
사진안에 있는 예외는 거의 다 사용하는 거라 알아두는 것이 좋다.
11.2 예외처리 코드
예외가 발생햇을때 정상흐름으로 가기위한 코드
try-catch-finally블록 으로 구성됨
try 실행코드 -> 예외발생x -> finally있으면 실행(없어도됨)
try 예외발생 -> 건너뛰고 catch블록 실행 -> finally있으면 실행(없어도됨)
구분안해두면 그냥 프로그램 종료시킴.
예외가 발생할거 같으면 try블록으로 감싸고 처리방법인 catch 를 만들어야함.
11.3 예외 종류에 따른 처리
프로그램 실행시 여러가지 예외가 발생할 수 있다. 예외1 발생 예외처리1 예외2 예외처리2 예외의 수만큼 catch를 작성가능하다
catch는 타입으로 구분가능 하나만 처리하고 다른건 발생안함. 동시에 두가지 예외 발생x
처리해야할 예외 클래스들이 상속 관계에 있을 때는 하위 클래스 catch 블록을 먼저 작성하고 상위 클래스 catch 블록을 나중에 작성해야한다.
1센션의 상속관계 사진 확인 예외가 발생하면 catch 블록은 위에서부터 차례대로 검사해서 상위클래스catch블록이 먼저 검사대상이되면 밑에가 실행이안됨.
예를들어 Exception e를 해버리면 가장 상위 클래스이기 때문에 밑의 catch문이 발생이 안됨.
catch(Exception e) {
System.out.println("배열 인덱스가 초과됨: "+ e.getMessage());
} catch(NumberFormatException e) {
System.out.println("숫자로 변환할 수 없음: "+ e.getMessage());
}
//Unreachable catch block for NumberFormatException. 밑에가 절대 실행될수없는데 왜적엇냐고 나옴.
//어떠한 예외든 Exception e의 하위이기때문!
//예외가 많을 때 원하는 것은 1로 해결하고 나머지는 모두 같게 처리하고싶으면
catch(NumberFormatException e) {
System.out.println("숫자로 변환할 수 없음: "+ e.getMessage());
}catch(Exception e) {
System.out.println("배열 인덱스가 초과됨: "+ e.getMessage()); }
// 순서를 바꿔서 작성하기
catch(NullPointerException | NumberFormatException e){
System.out.println("데이터에 문제가 있음")
}
// 2가지 예외를 동일하게 처리할 때는 |을 넣는다.11.4 리소스 자동 닫기
리소스랑 데이터를 제공하는 객체 리소스는 파일을 이야기도 하고 프로그램에서 데이터를 가지고 있는 것을 의미한다.
리소스를 사용하기 위해서는 open 해야하고 사용이 끝나면 close 해야한다.
a에서 사용중인데 b에서 편집하기는 불가능함. 닫아줘야 다른프로그램에서 사용가능.
리소스를 사용하다가 예외가 발생될 경우에도 안전하게 닫는 것이 중요하다. 닫지않으면 리소스가 불안정한 상태로 남아있게됨.
try문에서 닫으면? 중간에 오류가 생기면 안닫히고 캐치문 발생. 캐치문에 클로즈를 쓰면? 중복의 문제 finally에 클로즈를 작성해서 안전하게 닫도록하기
그러나 자동으로 닫게 하는 기능이 있다.
try-with-resources 블록을 사용하면 예외 발생여부와 상관없이 리소스를 자동으로 닫아준다.
try 괄호에 리소스를 여는 코드를 작성하면 try블록이 정상적으로 실행을 완료햇거나 도중에 예외가 발생하면 자동으로 close()메소드가 호출된다.
try(FileInputStream fis = new FileInputStream("file.txt"){...} catch{..}
try-with-resources 블록을 사용하기 위해서는 AutoCloseable 인터페이스를 구현해서 close()메소드를 재정의해야한다.
public class 클래스명 implements AutoCloseable{
@Override
public void close() throws Exception {...}
복수의 리소스를 사용하면 try()괄호안에 세미콜론으로 구분해서 리소스를 여는 코드를 작성하면된다.
public class MyResource implements AutoCloseable {
private String name;
public MyResource(String name){
this.name = name;
System.out.println("[MyResource(" + name + ") 열기");
}
public String read1() {
System.out.println("[MyResource(" + name + ") 읽기");
return "100";
}
public String read2() {
System.out.println("[MyResource(" + name + ") 읽기");
return "abc";
}
@Override
public void close() throws Exception {
System.out.println("[MyResource(" + name + ") 닫기");
}} public class TryWithResourceExample {
public static void main(String[] args) {
// MyResource를 파일이라고 가정
MyResource res3 = null;
try {
//리소스열기
res3 = new MyResource("res3");
//리소스읽기
System.out.println(res3.read1());
} catch(Exception e){
e.printStackTrace();
} finally {
//리소스 닫기
//무조건 닫아주는게 정석임.
//닫을 때 예외는 우리가 처리할게없으니 그냥 비워두기
try {
res3.close();
} catch (Exception e) {}
}
//-------------
try (MyResource res = new MyResource("A")){
String data = res.read2();
int value = Integer.parseInt(data);
} catch(Exception e) {
System.out.println("예외처리: " + e.getMessage()); //예외가 발생하든 아니든 close실행
}
System.out.println();
//파일리소스 여는걸 두개이상 넣을경우에 ;으로 구분
MyResource res1 = new MyResource("A"); //try안에 넣으면 오픈소스가 너무 길어져서 정의해두고 밑에 넣음.
MyResource res2 = new MyResource("B");
try (res1; res2){
//try ( MyResource res1 = new MyResource("A"); MyResource res2 = new MyResource("B"))}
String data1 = res1.read1();
String data2 = res2.read1();
} catch(Exception e) {
System.out.println("예외처리: " + e.getMessage()); //예외가 발생하든 아니든 close실행
}}}11.5 예외떠넘기기
어떤 메소드가 실행하다가 예외가 발생할때 메소드 호출한 곳으로 예외를 떠넘길 수도 있다.
이때 사용하는 키워드고 throws 이다. throws는 메소드 선언부 끝에 작성하는데 떠넘길 예외 클래스를 쉼표로 구분해서 나열한다.
리턴타입 메소드명(매개변수,...) throws 예외클래스1, 예외클래스2 ...{}
자바 표준 api의 메소드에는 다부분 throws 같은 키워드가 들어가있음. 따라서 내가 사용할때 예외처리를 알아서 해야함.
try {
findClass(); //밑에서 던져서 빨간줄나와서 누르고 하면 try catch알아서 나옴.
} catch(ClassNotFoundException e) {
System.out.println("예외처리: " + e.toString());
}
}
public static void findClass() throws ClassNotFoundException{
Class.forName("java.lang.String2");
}public static void main(String[] args) throws ClassNotFoundException {}
메인에 throws해버릴 수도있다. -> 자바 가상 머신 jvm에 예외를 던져버려서 오류 발생해버림. 좋지 못한 코드임.
리턴타입 메소드명(매개변수,...) throws Exception 하면 종류구분없이 예외를 던지겟다는 뜻
11.6 사용자 정의 예외
인터넷 뱅킹 프로그램에서 잔고보다 더 맣은 출금 요청이 들어온 경우에는 잔고 부족예외를 발생시킬 필요가있다.
그러나 잔고 부족 예외는 표준 라이브러리에는 존재하지 않기 때문에 직접 예외 클래스를 정의해서 사용해야한다. 이것을 사용자 정의 예외라고 한다.
애플리케이션에서 특화된 예외가 필요하다.
public class XxxException extends Exception | RuntimeExcpetion{
//생성자 오버라이딩 해서 두개 작성
//기본 생성자
public XxxExcpition(){}
//예외 메시지를 입력받는 생성자
public XxxExcpition(String message){
super(message);
}
}예외발생 이름이 예외발생이유를 나타내는 경우에는 굳이 안에 예외의 이유를 넣고 만들 필요가 없다.
그래서 그냥 냅두는게 낫다.
11.6.1 사용자 정의예외
사용자 정의예외는 컴파일러가 체크하는 일반 예외로 선언할수도 잇고 컴파일러가 체크하지 않는 실행예외로 선언할 수도잇다.
통상적으로 일반 예외는 Exception의 자식클래스로 선언하고 실행예외는 RuntimeException의 자식클래스로 선언한다.
11.6.2 예외발생시키기
throw new Exception() // 예외를 발생시키는 코드
throw new Exception(message) //메시지주고 예외발생
throw 예외하면 결국 그 예외를 발생시키는 것임.
public void withdraw(int money) throws InsufficientException{
if (balance < money) {
throw new InsufficientException("잔고부족: " +(money-balance) + " 모자람");
}
balance -= money;
}withdraw()메소드를 실행햇을때 예금액보다 입력받은 돈이 많으면?
예외를 발생시키게 만들어 놓음. 돈이 빠져나가면 안되니까
예외는 InsufficientException에 보내버려서 예외처리를 정해놓음.
2022.12.15 리뷰
처음 공부할 때 이해하지 못 했던 부분들을 또 이해하게 되니 너무 재밌는 날이었다.
팍팍 복습을 하고자 한다.
중요한것은 꺾이지 않는 마음