예외와 에러
예외는 개발자가 다음과 같은 목적을 위해 제어·처리함
- 프로그램의 정상 종료
- 예외 발생 시 무시하고 프로그램 계속 실행
▼자바에서 제공하는 에러 전체 클래스
- 프로그램에서 처리하는 예외 클래스의 최상위 클래스는 Exception 클래스
- 모든 예외 타입은 클래스로서 서로 상속 관계
예외 종류
- 실행 예외
- 예외 처리를 하지 않아도 컴파일할 수 있는 비검사형 예외(Unchecked Exception)
- 실행 단계에서 체크
- 일반 예외
- 예외 처리를 하지 않으면 컴파일 오류가 발생하므로 꼭 처리해야 하는 검사형 예외(Checked Exception)
- 컴파일 단계에서 체크
예외를 구분하는 이유 : 프로그램 성능 때문
모든 상황에서 예외 처리를 하면 프로그램의 성능 저하 문제로 이어지기 때문에 일반 예외는 컴파일러가 확실히 확인하고, 실행 예외는 개발자가 판단하여 예외를 처리하든지 처리가 안 되었다면 자바 가상 머신에 처리를 맡기게 됨
▼대표적인 실행 예외
실행 예외 | 발생 이유 |
ArithmeticException | 0으로 나누기와 같은 부적절한 산술 연산 수행 시 발생 |
IllegalArgumentException | 메서드에 부적절한 매개변수를 전달할 때 발생 |
IndexOutOfBoundException | 배열, 벡터 등에서 범위를 벗어난 인덱스 사용 시 발생 |
NoSuchElementException | 요구한 원소가 없을 때 발생 |
NullPointerException | null값을 가진 참조 변수에 접근할 때 발생 |
NumberFormatException | 숫자로 바꿀 수 없는 문자열을 숫자로 변환하려 할 때 발생 |
▼대표적인 일반 예외
일반 예외 | 발생 이유 |
ClassNotFoundException | 존재하지 않는 클래스를 사용하려고 할 때 발생 |
NoSuchFieldException | 클래스가 명시한 필드를 포함하지 않을 때 발생 |
NoSuchMethodException | 클래스가 명시한 메서드를 포함하지 않을 때 발생 |
IOException | 데이터 읽기 쓰기 같은 입출력 문제가 있을 때 발생 |
import java.util.Scanner;
public class Ex01_ExceptionCase
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
int num1 = sc.nextInt();
int num2 = 10 / num1;
System.out.println(num2);
//MyBook book1 = new MyBook();
}
}
예외 처리하기
예외 처리의 진행 형식
try
{
JAVA 코드
}
catch (예외 타입 1 e)
{
예외 1 발생 시 이 부분 실행
}
catch (예외 타입 2 e)
{
예외 2 발생 시 이 부분 실행
}
finally
{
이 부분은 마지막에 무조건 실행
}
일부 생략 가능
try
{
JAVA 코드
}
catch (예외 타입 e)
{
예외 발생 시 이 부분 실행
}
try
{
JAVA 코드
}
finally
{
이 부분은 마지막에 무조건 실행
}
try ~ catch
앞에서 작성한 코드의 예외는 2개이므로 다음과 같이 코드를 추가하여 예외를 처리해주도록 함
import java.util.Scanner;
import java.util.InputMismatchException;
public class Ex02_TryCatch
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
try
{
int num1 = sc.nextInt();
int num2 = 10 / num1;
System.out.println(num2);
System.out.println("Good bye~~!");
}
catch(ArithmeticException e)
{
String str = e.getMessage();
System.out.println(str);
if (str.equals("/ by zero"))
System.out.println("0으로 나눌 수 없습니다.");
}
// 입력값이 정수가 아니어서 데이터 형변환에 대한 예외가 발생하면 실행됨
catch(InputMismatchException e)
{
System.out.println(e.getMessage());
//e.printStackTrace(); -> 예외에 대한 자세한 메시지 출력
}
}
}
Ctrl + Shift + O 를 동시에 누르면 이클립스에서 임포트 자동 추가 가능
finally
예외 발생 시에도 무조건 실행
import java.util.Scanner;
import java.util.InputMismatchException;
public class Ex03_Finally
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
try
{
int num1 = sc.nextInt();
int num2 = 10 / num1;
System.out.println(num2);
}
catch(ArithmeticException e)
{
String str = e.getMessage();
System.out.println(str);
if (str.equals("/ by zero"))
System.out.println("0으로 나눌 수 없습니다.");
}
catch(InputMismatchException e)
{
System.out.println(e.getMessage());
//e.printStackTrace();
}
finally
{
System.out.println("Good bye~~!");
}
}
}
예외 처리 합치기
catch문 하나에서 여러 예외를 한꺼번에 처리할 수도 있음
import java.util.Scanner;
import java.util.InputMismatchException;
public class Ex04_CatchConcat
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
try
{
int num1 = sc.nextInt();
int num2 = 10 / num1;
System.out.println(num2);
}
// 예외 처리 | 사용 (or 연산자)
catch(ArithmeticException | InputMismatchException e)
{
//System.out.println(e.getMessage());
//e.printStackTrace();
System.out.println("예외 발생");
}
// try~catch문에 의해 비정상적인 종료는 방지되었으므로, finally를 사용하지 않고
// 그 뒤에 이렇게 사용하면 이 내용을 예외가 발생해도 출력할 수 있음
System.out.println("Good bye~~!");
}
}
모든 예외 한 번에 처리하기
어떤 예외가 발생할지 모를 때 모든 예외의 최상위 클래스를 이용해서 예외 처리 가능
'자식 클래스의 객체는 부모 클래스형의 변수에 대입할 수 있다'
import java.util.Scanner;
public class Ex05_Exception
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
try
{
int num1 = sc.nextInt();
int num2 = 10 / num1;
System.out.println(num2);
}
catch(Exception e)
{
//System.out.println(e.getMessage());
//e.printStackTrace();
System.out.println("예외 발생");
}
System.out.println("Good bye~~!");
}
}
예외를 한 번에 다 처리하려면 Exception 클래스나 Throwable 클래스 사용 가능
예외 처리 미루기(던지기)
결과적으로 JVM은 프로그램을 종료시킴
예외 처리 미루기
public class Ex06_ExceptionThrow
{
public static void myMethod1(int n)
{
myMethod2(n, 0);
}
public static void myMethod2(int n1, int n2)
{
int r = n1 / n2; // 예외 발생 지점
}
public static void main(String[] args)
{
myMethod1(3);
System.out.println("Exception Throw !!!");
}
}
Throwable로 잡기
던져진 예외를 처리하려면 어떤 예외가 올지 모르므로 catch문에서 앞서의 Exception을 활용할 수도 있겠지만, 던져진 것을 처리한다는 의미로 Exception의 상위 객체인 Throwable을 사용할 수도 있음
import java.util.Scanner;
public class Ex07_CatchThrowable
{
public static void myMethod1()
{
myMethod2();
}
public static void myMethod2()
{
Scanner sc = new Scanner(System.in);
int num1 = sc.nextInt(); // 에러 발생 지점
int num2 = 10 / num1; // 에러 발생 지점
System.out.println(num2);
}
public static void main(String[] args)
{
try
{
myMethod1(); // 여기로 myMethod1으로부터 예외가 넘어옴
}
catch(Throwable e)
{
e.printStackTrace();
//System.out.println(e.getMessage());
}
}
}
예외 처리를 미루는 이유
예외가 발생하는 지점의 메서드를 많은 곳에서 호출하는 경우 예외 처리가 다양할 수 있기 때문
예를 들어, 클래스에서 스태틱으로 지정된 유틸 메서드인 경우는 어떤 클래스의 메서드가 자신을 호출할지 모르는 상태이기 때문에, 호출하는 쪽에서 예외 처리를 해야 더 적절한 처리를 할 수 있음
import java.util.Scanner;
public class Ex08_WhyThrow
{
public static void myMethod1()
{
try
{
myMethodA(); // 여기로 myMethod1으로부터 예외가 넘어옴
}
catch(Throwable e)
{
System.out.println("에러 !!!");
}
}
public static void myMethod2()
{
try
{
myMethodA(); // 여기로 myMethod1으로부터 예외가 넘어옴
}
catch(Throwable e)
{
System.out.println("Error !!!");
}
}
public static void myMethodA()
{
Scanner sc = new Scanner(System.in);
int num1 = sc.nextInt(); // 에러 발생 지점
int num2 = 10 / num1; // 에러 발생 지점
System.out.println(num2);
}
public static void main(String[] args)
{
myMethod1(); // 한글 메시지 출력
myMethod2(); // 영문 메시지 출력
}
}
메서드에 예외 선언
public static void 메서드명()
throws 예외, 예외, 예외
{
// 본문
}
- 메서드를 사용하는 사람이 메서드의 선언부만 보아도 이 메서드를 사용하려면 어떤 예외를 처리하면 되는지 쉽게 알 수 있음
- 일반적으로 RuntimeException 클래스들은 적지 않음
import java.util.InputMismatchException;
import java.util.Scanner;
public class Ex09_ThrowsInMethod
{
public static void myMethod1()
{
myMethod2();
}
public static void myMethod2()
throws ArithmeticException, InputMismatchException
{
Scanner sc = new Scanner(System.in);
int num1 = sc.nextInt(); // 에러 발생 지점
int num2 = 10 / num1; // 에러 발생 지점
System.out.println(num2);
}
public static void main(String[] args)
{
try
{
myMethod1();
}
catch (ArithmeticException | InputMismatchException e)
{
e.printStackTrace();
}
System.out.println("-------");
}
}
'JAVA > 이재환의 자바 프로그래밍 입문' 카테고리의 다른 글
[Java] Ch.18 열거형, 가변 인수, 어노테이션 (1) | 2023.10.23 |
---|---|
[Java] Ch.17 자바의 기본 클래스 (0) | 2023.10.23 |
[Java] Ch.15 배열 (0) | 2023.10.20 |
[Java] Ch.14 String 클래스 (0) | 2023.10.20 |
[Java] Ch.13 패키지와 클래스 패스 (0) | 2023.10.20 |