[예외처리] try~ catch~, finally~, throws

포키·2022년 11월 23일
0

국비과정

목록 보기
32/73

예외처리

  • 예외 (Exception)
    : 실행 중 발생하는 에러 -> 최악의 경우 프로그램 강제종료
  • 예외처리
    : 문제상황을 해결하는 것이 x, 문제발생시 대처법을 알려준다.

ex) 문제상황 = 나가야 하는데 문이 안 열림
-> 어떻게든 나가는 법을 알려준다. (x)
-> 차분히 앉아 강사님을 기다린다. (o) - 즉, 대안 제시

  • 프로그램이 끝까지 수행되지 못하는 것이 가장 큰 문제라서,
    어떤 상황에도 코드는 끝까지 수행되도록 대안을 마련해두는 것.
class ExceptionEx1 {
	public static void divide(int num1, int num2) {
		int result = num1 / num2;
		System.out.println(result);
	}
	public static void main(String[] args) {
		divide(12, 6);
		divide(12, 0);
		System.out.println("end of main");
	}
}


try ~ catch ...

	try {
    	// 기본적으로 수행하려는 문장
    } catch(예외클래스 e) {
    	// 예외 발생시 수행할 문장
    }

finally

	try {
    	// 기본적으로 수행하려는 문장
    } [catch(예외클래스 e) {
    	// 예외 발생시 수행할 문장
    }] finally {
    	// 예외가 발생하든 하지 않든 반드시 수행할 문장
    }
  • 처리되지 않은 예외가 발생할 가능성을 고려
    (ex) catch문 안에서도 예외가 발생할 가능성)
  • 예외에 관계없이 무조건 수행함
  • 코드 중단을 막아주지 않음
  • catch문 제외하고 try ~ finally ... 만 적어도 실행 가능 (예외처리된 것 아님)
  • 주로 '중간에 예외 발생하여 코드가 중단될 때, 후처리를 반드시 해주기 위해' 사용
    (ex) 파일I/O에서 자원해제 처리)
  • stack vs. queue
  • 에러 표시에 나오는 클래스.메서드 구조는 static이라 나오는 게 아님.
    속한 클래스를 알려주려는 것.
    (저 부분은 코드가 아니므로 자바 코드의 규칙이 적용되지 않는다.)

예외 클래스

  • 자바는 예외 상황도 객체다.
    ex) java.lang.ArithmeticException : 0으로 나눈 연산 객체
  • 이름으로 발생한 예외 상황을 설명해줌.
  • 내부에는 예외 상황을 구체적으로 설명하는 메서드 존재.

메서드

  • public void printStackTrace() : 예외 발생시 발생 경로 print
	e.printStackTrace();
  • public String getMassage() : 예외 발생시 예외에 대한 정보 return (not print)
	System.out.println(e.getMessage());

Exception의 구분 : 체크 / 비체크

  • Exception
    : 예외의 최상위 클래스
  • RuntimeException 상속받는 예외
    -> 컴파일 시 예외처리여부 미체크
    -> 예외가 발생한 원인이 코드 내부에 있다.
  • RuntimeException을 상속받지 않는 예외
    -> 컴파일 시 예외처리여부 체크
    -> 예외의 원인이 코드 외부에 있다.

RuntimeException - 비체크 예외

ArithmeticException

class ExceptionEx1 {
	public static void divide(int num1, int num2) {
		String s;
		try {
			s = "Try";
			System.out.println("start of try"); 		// 1번, 5번
			int result = num1 / num2; 
			// 예외가 발생할 수 있는 연산
			System.out.println(result); 				// 2번
			// 위 연산에 의존성을 가진 연산. try에 넣어 같이 처리!
			System.out.println("end of try");			// 3번
		} catch(ArithmeticException e) {
			s = "Catch";
			// ArithmeticException : 0으로 나눈 연산
			// 대신 할 일을 정의
			System.out.println("0으로 나눌 수 없습니다.");	// 6번
			System.out.println("end of catch");			// 7번
		}
		// try 안에서 예외가 발생하면 바로 catch로 넘어간다.
		System.out.println(s);							// 4번, 8번
	}
	public static void main(String[] args) {
		divide(12, 6);
		divide(12, 0);
		System.out.println("end of main");				// 9번
	}
}

NullPointerException

class ExceptionEx3 {
	public static void makeException(int[] arr) {
			int length = arr.length;
			System.out.println("배열의 길이 : " + length);
	}
	public static void main(String[] args) {
		makeException(new int[] {1, 2, 3, 4, 5, 6, 7});
		makeException(null);
		System.out.println("end of main");
	}
}

class ExceptionEx3 {
	public static void makeException(int[] arr) {
		try {
			int length = arr.length;
			System.out.println("배열의 길이 : " + length);
		} catch(NullPointerException e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		makeException(new int[] {1, 2, 3, 4, 5, 6, 7});
		makeException(null);
		System.out.println("end of main");
	}
}

NumberFormatException

class ExceptionEx4 {
	public static void makeException(String str) {
		// String -> int
		// "123" -> 123
		int num = Integer.parseInt(str);
		num++;
		System.out.println(num);
	}
	public static void main(String[] args) {
		makeException("123");
		makeException("???");
	}
}

class ExceptionEx4 {
	public static void makeException(String str) {
		// String -> int
		// "123" -> 123
		try {
			int num = Integer.parseInt(str);
			num++;
			System.out.println(num);
		} catch(NumberFormatException e) {
			System.out.println("Message : " + e.getMessage());
		}
	}
	public static void main(String[] args) {
		makeException("123");
		makeException("???");
	}
}

  • Integer.parseInt(str)
    : String -> int
  • String.valueOf(data)
    : (대충 모든 기초 자료형) -> String

NegativeArraySizeException

Non-RuntimeException - 체크 예외

ClassNotFoundException

  • 파일은 디스크 관리자(운영체제)가 관리

FileNotFoundException

IOException

SqlException

  • catch문 조건 묶기 (예외1 | 예외2 e)
    예외 처리시에 수행할 코드가 같은 경우, 한 번에 처리 가능 (JDK 1.7~)
class ExceptionEx5 {
	public static void makeException(Shoes s, String str) {
		try {
			int price = s.getPrice();
			int num = Integer.parseInt(str);
		} catch(NullPointerException | NumberFormatException e) {
			System.out.println("예외가 발생했습니다.");
		}
	}
	public static void main(String[] args) {
		makeException(null, "123");
		makeException(new Shoes(50000), "");
	}
}
  • 하나의 try에 여러 개의 catch 연결 가능 (다양한 예외의 경우 대비)
  • 처리되는 예외들 간에 계층구조가 존재하는 경우 반드시 하위 예외부터 처리해야 한다. (체크예외)

throws

  • 예외가 생겼을 때 처리방법
  1. 스스로 해결한다 -> 책임은 나에게
  2. 엄마 천원 잃어버렸어요 -> 책임은 엄마에게
  • try … catch …와 차이 : 자신이 직접 오류를 수정하지 않고 자신을 호출한 사용자에게 예외 처리의 책임을 넘긴다.
  • public method -> 어느 누가 어떤 목적으로 호출할지 모름
  1. 다양한 경우의 수를 모두 대비해두기 어려움
  2. 여러 사람이 같이 작업할 때, 독단적으로 예외를 처리하면 문제가 생길 수 있음
    그러므로 호출한 쪽(해당 메서드의 사용자)에게 예외 처리의 책임을 넘기는 것
    하지 않으면 호출한 쪽에서는 오류 발생 여부조차 알 수 없다!
  • 함부로 독단적으로 예외 처리 끝내서는 안 되는 상황이라면, 협업중이라면, throws는 필수다.
import java.io.*;
class CommonObj {
	public void doSomething() {
		try {
			FileReader fr = new FileReader("a.txt");
		} catch(FileNotFoundException e) {
			System.out.println("catch");
		}
	}
}
class UserA {
	public void useCommonObj(CommonObj obj) {
		// 문제발생 : do A
		obj.doSomething();
	}
}
class UserB {
	private CommonObj obj = new CommonObj();
	// 문제발생 : do B
	public void doit() {
		obj.doSomething();
	}
}
class ExceptionEx1 {
	public static void main(String[] args) {
		UserA a = new UserA();
		UserB b = new UserB();
		
		a.useCommonObj(new CommonObj());
		b.doit();
	}
}
  • throws 사용하지 않을 경우 메서드 호출한 사용자는 예외 발생 여부조차 알 수 없다.
import java.io.*;
class CommonObj {
	public void doSomething() throws FileNotFoundException {
			FileReader fr = new FileReader("a.txt");
	}
}
class UserA {
	public void useCommonObj(CommonObj obj) {
		// 문제발생 : do A
		try {
			obj.doSomething();
		} catch(FileNotFoundException e) {
			System.out.println("do A");
		}
	}
}
class UserB {
	private CommonObj obj = new CommonObj();
	// 문제발생 : do B
	public void doit() {
		try {
			obj.doSomething();
		} catch(FileNotFoundException e) {
			System.out.println("do B");
		}
	}
}
class ExceptionEx1 {
	public static void main(String[] args) {
		UserA a = new UserA();
		UserB b = new UserB();
		
		a.useCommonObj(new CommonObj());
		b.doit();
	}
}
  • throws를 사용하면 문제 상황이 발생했을 때 메서드를 호출한 사용자가 자신의 의도대로 처리할 수 있다.

파일을 관리하는 총책임자 os
내가 파일을 읽고 싶다면 os에게 권한을 받아와야 함
그 외의 외부 자원을 사용하는 방식도 비슷함
자바 가상머신도 결국 컴퓨터 자원을 사용하는 프로그램의 하나이기 때문

finally 예시 - 자원해제

import java.io.*;
class CommonObj {
	public void doSomething() throws FileNotFoundException {
		FileReader fr = null;
		try {
			fr = new FileReader("a.txt");
		} finally {
			// finally 주 용례 : 자원해제
			try {
				fr.close();	// fr.close() <- 자원해제
			} catch(Exception e) {
			}
			System.out.println("CommonObj 후처리");
			// 사용자에게 완료 알림
		}
	}
}
class UserA {
	// 문제발생 : do A
	public void useCommonObj(CommonObj obj) {
		try {
			obj.doSomething();
		} catch(FileNotFoundException e) {
			System.out.println("do A");
		}
	}
}
class UserB {
	private CommonObj obj = new CommonObj();
	// 문제발생 : do B
	public void doit() {
		try {
			obj.doSomething();
		} catch(FileNotFoundException e) {
			System.out.println("do B");
		}
	}
}
class ExceptionEx1 {
	public static void main(String[] args) {
		UserA a = new UserA();
		UserB b = new UserB();
	}
}
// throws를 사용하면 문제 상황이 발생했을 때 메서드를 호출한 사용자가 자신의 의도대로 처리할 수 있다.
// throws를 사용하지 않으면 메서드 호출한 사용자가 예외 발생 여부조차 알 수 없다.

지금까지 본 예외는 모두 기술적인 문제
이제는 우리가 원하는 예외 상황 클래스를 만들고 쓸 수 있어야 함

커스텀 예외 클래스

  • 특정 상황을 예외로 처리하는 법
  • 이름 : '~Exception'
  • 컴파일 시 체크여부 결정 : 체크(Exception), 비체크(RuntimeException)
  • 메세지 설정 : 부모 생성자를 통해서 처리 (패러미터로 받아오거나, 직접 쓰거나)
// 커스텀 예외 클래스 만들기 
class MyException extends Exception {
	public MyException() {
		super("예외가 발생했어요");
	}
	public MyException(String msg) {
		super(msg);
	}
}
// 예외 발생시키는 방법
class ExceptionEx2 {

	public static void makeException(int num) throws MyException {
		try {
			// num이 0보다 작은 경우 예외상황이라 정의함 : MyException
			if(num < 0) {
				MyException e = new MyException("이것은 예외!");
				// 예외 발생
				throw e;
			} else {
				System.out.println("num은 양수");
			}
		} finally {
			System.out.println("이것은 finally");
		}
	}
	public static void main(String[] args) {
		try {
			makeException(5);
		} catch(MyException e) {
			System.out.println(e.getMessage());
		}
		try {
			makeException(-5);
		} catch(MyException e) {
			System.out.println(e.getMessage());
		}
	}
}
// 이걸 배우면 예외를 문제상황 말고 다른 의미로도 사용 가능
// 현재 예시에서는 if문과 비슷하게 사용(대체 가능)했지만 다양한 방향 사용 가능

예외 처리 활용 (단순 에러 처리 이외)

class ExceptionEx3 {
	public static void howToUse() {
		int num = 0;
		try {
			while(true) {
				System.out.println("looping");
				num++;
				if(num == 100) {
					throw new Exception();
				}
			}
		} catch(Exception e) {
			System.out.println("Escaped!");
		}
	}
	public static void main(String[] args) {
		howToUse();
	}
}
// roop문 깨는 조건으로도 사용 가능
// break 쓰는 것보다 예쁜 코드

// 예외를 프로그램을 끝낼 정도의 힘이 있다.
// 예외는 단순히 error의 의미가 아니다.

예제

class Human {
	private String name;
	private int age;

	public Human(String name, int age) {
		setName(name);
		setAge(age);
	}
	public String getName() {
		return name;
	}
	public int getAge() {
		return age;
	}
	public void setName(String name) {
		this.name = name;
	}
	public void setAge(int age) {
		this.age = age;
	}

	public void love(Human honey) throws CrazyHumanException{
		if(honey.getAge() > 19) {
			System.out.println(name + " loves " + honey.getName());
		} else {
			// 미성년자를 사랑... 이것은 예외
			CrazyHumanException e = new CrazyHumanException();
			throw e;
		}
	}
}
class CrazyHumanException extends Exception {
	public CrazyHumanException() {
		super("미친 인간입니다.");
	}
	public CrazyHumanException(String msg) {
		super(msg);
	}
}
class ExceptionEx4 {
	public static void main(String[] args) {
		Human h1 = new Human("해인", 34);
		Human h2 = new Human("지민", 40);
		
		try {
			h1.love(h2);
		} catch(CrazyHumanException e) {
			System.out.println(e.getMessage());
		}

		Human h3 = new Human("수미", 17);
		Human h4 = new Human("영수", 47);

		try {
			h4.love(h3);
		} catch(CrazyHumanException e) {
			System.out.println(e.getMessage());
		}

		Human h5 = new Human("착한 사람", 30);

		try {
			h5.love(h3);
		} catch(CrazyHumanException e) {
			System.out.println("그...럴수...도 있......나?");
		}
	}
}
// 특정한 코드 안에 if-else가 들어가면, 그 코드 내용은 정해져있음
// 그러나 예외처리를 이용하면 유연성이 생김. 다양성이 커짐.
// ex) 지금처럼 else 부분에 예외를 넣는 것으로 else가 수행할 일을 바꿀 수 있음
profile
welcome

0개의 댓글