
컴파일 할 때 발생하는 에러 - 실행이 안됨
system.out.println(); //컴파일 에러!! system -> System으로 수정
실행 할 때 발생하는 에러 - 발생 시 프로그램 종료
int[] arr = new int[5]; // a[0~4]
for(int i = 0; i<=5; i++){
System.out.println(arr[i]); //런타임 에러!! 배열의 범위를 벗어남 (a[5])
}
작성 의도와 다르게 동작
(맞왜틀)- 발생 시 프로그램 종료X
//맞는데 왜 틀림?//
//배열의 합을 구하는 프로그램
long[] arr = new long[5]; // a[0~4]
int sum = 0;
for(int i = 0; i<=5; i++){
sum += arr[i];
}
System.out.println(sum);
//배열의 합이 int를 벗어나면 결과값이 의도와 다르게 나옴
런타임 에러중에 코드에 의해서 수습될 수 없는 심각한 오류
-메모리 부족
런타임 에러중에 코드에 의해서 수습될 수 있는 다소 미약한 오류
-0으로 나누기, 배열범위 초과, 형변환 오류
사용자의 실수와 같은 외적인 요인에 의해 발생하는 예외
프로그래머의 실수로 발생하는 예외
컴파일러가 예외 처리 여부를 체크 (예외 처리 필수)
- 안하면 컴파일 에러
컴파일러가 예외 처리 여부 체크 X (예외 처리 선택)
-안하면 런타임 에러
모두 필수로 처리를 해야한다면 거의 모든 코드에 예외처리를 해줘야 함.
//모두 필수로 예외처리를 해야한다면 아래 코드에서도 예외처리를 해주어야 한다!
int[] arr = new int[10];
System.out.println(arr[0]);
//배열 범위 초과 에러, null포인터 에러가 발생할 수 있으므로 예외처리해주어야함.
연산자 new를 이용해서 발생시키려는 예외클래스의 객체를 만든다음
키워드 throw를 이용해서 예외를 발생시킨다.
Exception e = new Exception("고의로 발생시켰음"); //new로 객체를 생성한 다음~
throw e; //예외를 발생시킨다!
// throw new Exception("고의로 발생시켰음"); // 두줄을 한줄로
프로그램 실행 시 발생할 수 있는 예외에 대비한 코드를 작성하는 것
프로그램의 비정상 종료를 막고, 정상적인 실행상태를 유지하는 것
try{
//예외가 발생할 가능성이 있는 문장들을 넣는다
} catch (Exception e1) {
//Exception e1이 발생했을 경우, 이를 처리하기 위한 문장을 넣는다
} catch (Exception e2) {
//Exception e2가 발생했을 경우, 이를 처리하기 위한 문장을 넣는다
} catch (Exception eN) {
//Exception eN이 발생했을 경우, 이를 처리하기 위한 문장을 넣는다
}
- 발생한 예외와 일치하는 catch문이 있는지 확인
- 일치하는 catch블럭 내의 문장들을 수행하고 전체 try-catch문을 빠져나가서 그 다음 문장을 계속해서 수행.
- 일치하는 catch블럭이 없으면 예외는 처리되지 못한다.
public static void main(String args[]){
System.out.println(1);
try{
System.out.println(0/0); //예외발생!!
System.out.println(2); // 실행X
} catch (ArithmeticException ae) { //예외 처리
System.out.println(3);
} catch (Exception e) { //ArithmeticException을 제외한 모든 예외 처리
// 위의 catch문이 catch했으므로 그냥 지나감
System.out.println(4);
} //try-catch문의 끝
System.out.println(5);
}
//출력
1
3
5
catch블럭을 거치지 않고 전체 try-catch문을 빠져나가서 수행을 계속한다
public static void main(String args[]){
System.out.println(1);
try{
System.out.println(2);
System.out.println(3);
} catch (exception e) { //예외발생X - 그냥 지나감
System.out.println(4); //실행X
} //try-catch문의 끝
System.out.println(5);
}
//출력
1
2
3
5
예외발생 당시의 호출스택에 있었던 메소드 정보, 예외 메세지를 출력
발생한 예외클래스의 인스턴스에 저장된 메세지를 얻을 수 있음
class EX8_5{
public static void main =(String args[]){
System.out.println(1);
System.out.println(2);
try{
System.out.println(3);
System.out.println(0/0); //8번째줄 예외 발생!!
System.out.println(4); //실행안됨
} catch (ArithmeticException ae) {
//printStackTrace()
ae.printStackTrace();
//getMessage()
System.out.println("예외메세지 : " + ae.getMessage);
} // try-catch의 끝
System.out.println(6);
}
}
//출력
1
2
3
java.lang.ArithmeticException: /by zero at EX8_5.main(EX8_5.java:8)
예외메세지 : / by zero
6
예외 발생여부와 관계없이 수행되어야 하는 코드를 넣는다.
try{
//예외가 발생할 가능성이 있는 문장 넣기
} catch (Exception e){
//예외 발생시 예외 처리를 위한 문장 넣기
} finally {
//예외 발생여부와 관계없이 항상 수행되어야하는 문장 넣기
//finally블럭은 항상 try-catch맨 마지막에 위치
}
내용이 같은 catch블럭을 하나로 합친 것
try{
//...
} catch(ExceptionA e1) {
e1.printStackTrace();
} catch(ExceptionB e2) {
e2.printStackTrace();
}
//멀티 catch 문
try {
//...
} catch (ExceptionA | ExceptionB e){
e.printStackTrace();
}
예외들이 부모-자식관계라면 사용X
try {
//...
} //catch (ParentException | ChildException e) { //에러!
catch(ParentException e) { //위 라인과 의미상 동일
e.printStackTrace();
}
예외에 선언된 메소드는 호출불가
try {
//...
} catch (ExceptionA | ExceptionB e){
// e.methodA(); //에러!! ExceptionA에 선언된 methodA는 호출 불가
//사용하려면 아래와 같은방법으로 수행
if(e instanceof ExceptionA) {
ExceptionA e1 = (ExceptionA) e; //형변환하기
e1.methodA(); // 호출가능
} else { //if(e instanceof ExceptionB)
//...
}
}
메소드가 호출시 발생가능한 예외를 호출하는 쪽에 알리는 것
void method() throws Exception1, Exception2, ... ExceptionN {
//메소드의 내용
}
//예제
static void startInstall() throws SpaceException, MemoryException {
if(!enoughSpace())
throw new SpaceException("설치 공간이 부족합니다.");
if(!enoughMemory())
throw new MemoryException("메모리가 부족합니다.");
}
❗ 에러를 발생시키는 키워드 throw와 예외를 메소드에 선언할 때 쓰는 throws 잘 구별하기
우리가 직접 상속을 통해 예외 클래스를 정의
- 조상은 Exception과 RuntimeException중에서 선택
class MyException extends Exception {
MyException(String msg) { //문자열을 매개변수로 받는 생성자
super(msg); //조상인 Exception 클래스의 생성자를 호출
}
}
- 예외를 처리한 후에 다시 예외를 발생시키는 것
- 호출한 메소드와 호출된 메소드 양쪽 모두에서 예외처리하는 것
class EX8 {
public static void main(String[] args){
try{ //예외 처리
method1();
} catch (Exception e) {
System.out.println("main메소드에서 예외가 처리되었습니다.");
}
}
static void method1() throws Exception {
try {
throw new Exception(); //예외 발생!
} catch (Exception e) { //예외 처리
System.out.println("method1에서 예외가 처리되었습니다.");
throw e; //예외 다시 발생
}
}
}
예외 처리를 양쪽에서 분담해서 처리가 가능해짐
- 한 예외가 다른예외를 발생시킬 수 있다.
- 예외 A가 예외 B를 발생시키면, A는 B의 원인 예외(cause exception)
Throwable initCause(Throwable cause) // 지정한 예외를 원인 예외로 등록
Throwable getCause() //원인 예외를 반환
//예제
public class Throwavle implements Serializable {
private Throwable cause = this; //객체 자신(this)를 원인 예외로 등록
//...
public synchronized Throwable initCause(Throwable cause){
this.cause = cause; //cause를 원인 예외로 등록
return this;
}
}
try {
install();
} catch (SpaceException e) { //예외 1
e. printStackTrace();
} catch (MemoryException e) { //예외 2
//...
} catch (Exception e) {
//...
}
// 위 코드를 아래 코드로 줄일 수 있다
try {
install();
} catch (InstallException e) {
e. printStackTrace();
} catch (Exception e) {
//...
}
void install() throws InstallException {
try{
startInstall();
copyFiles();
} catch (SpaceException e) { //예외 1
InstallException ie = new InstallException("설치중 예외발생");
ie.initCause(e); //원인예외 지정
throw ie; //예외 발생
} catch (MemoryException me) { //예외 2
//...
}
}
static void startInstall() throws SpaceException, MemoryException {
if(!enoughSpace())
//필수처리예외
throw new SpaceException("설치 공간이 부족합니다.");
if(!enoughMemory())
//필수처리예외
throw new MemoryException("메모리가 부족합니다.");
}
//위 코드를 변경
static void startInstall() throws SpaceException {
if(!enoughSpace())
//필수처리예외
throw new SpaceException("설치 공간이 부족합니다.");
if(!enoughMemory())
//RuntimeException이 MemoryException을 원인예외로 등록
//선택처리예외
throw new RuntimeException(new MemoryException("메모리가 부족합니다."));
}