에러
-하드웨어의 잘못된 동작 또는 고장으로 인한 오류
-정상 실행 상태로 돌아갈 수 없음
-> 더 치명적임
예외
-사용자의 잘못된 조작 또는 개발자의 잘못된 코딩으로 인한 오류
-예외 처리 추가하면 정상 실행 상태로 돌아갈 수 있음
일반예외 : 빨간줄이 뜨면서 에러를 바로 확인 가능
실행예외 : 콘솔에 출력되는 예외. 실행해봐야 에러 확인 가능
예외처리 코드!
<문법>
try{
//예외가 발생할 수도 있을 법한 실행코드들을 감싸는 위치
}catch(발생할 수 있는 예외 클래스){
//해당 예외가 발생했을 때 실행될 코드들을 감싸는 위치
}finally{
//try 안의 실행문이 정상종료되거나 catch가 실행된 후
//맨 마지막으로 반드시 실행되는 코드들을 감싸는 위치
}
발생할 수 있는 대표적인 실행예외 종류 정리!!
NullPointerException
: 참조변수에 참조변수가 없는 상태에서 .(도트연산자) 사용시 발생
String str = null;
System.out.println(str.equals("문자열"));
System.out.println("프로그램 종료"); //오류 발생시 실행안됨
예외처리)
try 안에서 예외 발생시 예외 발생 전 실행문은 정상 실행되며
예외 발생 아래 실행문은 건너뛰고 catch 블럭으로 실행이 옮겨간다
try {
String str = null;
System.out.println("1");
System.out.println(str.equals("문자열")); //exception 발생!
System.out.println("2"); //출력되지 않음
}catch(NullPointerException e) {
System.out.println("참조변수에 참조 데이터가 존재하지 않음!");
}finally {
System.out.println("무조건 실행됩니다!!");
}
실행결과)
1 참조변수에 참조 데이터가 존재하지 않음! 무조건 실행됩니다!! |
ArrayIndexOutOfBoundsException
: 배열에 넘치는 인덱스에 접근할 때 발생하는 예외
int[] arr = {1,2,3};
for(int i = 0; i <= arr.length ; i++)
{
System.out.println(arr[i]);
}
System.out.println("프로그램 종료"); //오류 발생시 실행안됨
예외처리)
int[] arr = {1,2,3};
try {
for(int i = 0; i <= arr.length ; i++)
{
System.out.println(arr[i]);
}
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("배열인덱스 넘침!");
}
ClassCastException
: 객체를 알맞지 않은 클래스 타입으로 강제형변환시 발생하는 예외
Parent parent = new Parent();
Child01 child = (Child01)parent;
System.out.println("프로그램 종료"); //오류 발생시 실행안됨
예외처리)
Parent parent = new Parent();
try {
Child01 child = (Child01)parent;
}catch(ClassCastException e) {
System.out.println("강제형변환 오류!");
}
NumberFormatException
: 숫자로 변환할 수 없는 문자열을 숫자로 변환하는 경우 발생하는 예외
String numberText = "10a";
int sum = Integer.parseInt(numberText) + 20;
System.out.println(sum);
System.out.println("프로그램 종료"); //오류 발생시 실행안됨
예외처리)
try {
String numberText = "10a";
int sum = Integer.parseInt(numberText) + 20;
System.out.println(sum);
}catch(NumberFormatException e){
System.out.println("숫자변환 오류!");
}
ArithmeticException
: 값을 0으로 나누려 시도시 발생하는 예외
int result = 10/0;
System.out.println("프로그램 종료"); //오류 발생시 실행안됨
예외처리)
try {
int result = 10/0;
}catch(ArithmeticException e) {
System.out.println("0으로 나눠 오류!");
}
ClassNotFoundException
: 해당 클래스를 찾지 못할 수도 있기에 발생하는 컴파일 에러
Class.forName("javastudy.ch11_exception.Main01");
예외처리)
try {
Class.forName("javastudy.ch11_exception.Main02");
}catch(ClassNotFoundException e) {
System.out.println("클래스 못찾아 컴파일 에러!");
}
다중 try catch문
1)
try {
String str = "10a";
int number = Integer.parseInt(str); //오류 발생으로 catch로 넘어감
int result = number/0; //윗줄에서 건너뛰었기 때문에 오류실행되지 않음
}catch(NumberFormatException e) {
System.out.println("숫자로 변환할 수 없습니다"); //오류로 넘어왔기 때문에 다음 오류는 건너뜀
}catch(ArithmeticException e) {
System.out.println("0으로 나눌 수 없습니다");
}
System.out.println("프로그램 종료"); //오류 발생시 실행안됨
실행결과)
한 try 블럭 안에서 예외가 다양하게 발생할 가능성이 있는 경우 다중 catch문을 사용하여 여러 예외 처리를 등록할 수 있다. 이때, 첫번째로 발생하는 예외가 catch된 후 try 블럭은 빠져나온다
숫자로 변환할 수 없습니다 프로그램 종료 |
2)
public class ExceptionHandlingExample {
public static void main(String[] args) {
String[] array = {"100","1oo"};
for(int i = 0; i <= array.length; i++) {
try {
int value = Integer.parseInt(array[i]);
System.out.println("array["+i+"]:" + value);
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("배열인덱스가 초과됨:"+e.getMessage());
}catch(NumberFormatException e) {
System.out.println("숫자로 변환할 수 없음:" + e.getMessage());
}
}
}
}
실행결과)
array[0]:100 숫자로 변환할 수 없음:For input string: "1oo" 배열인덱스가 초과됨:Index 2 out of bounds for length 2 |
3)
String[] strArray = {"10","2a"};
int value = 0;
for(int i = 0; i <= 2; i++) {
try {
value = Integer.parseInt(strArray[i]);
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("인덱스를 초과했음");
}catch(NumberFormatException e) {
System.out.println("숫자로 변환할 수 없음");
}finally {
System.out.println(value);
}
}
실행결과)
처음 10이 value에 대입된 이후 value에 대입되는 값이 없으니 finally로 출력되는 값은 계속 10을 출력한다
10 숫자로 변환할 수 없음 10 인덱스를 초과했음 10 |
4) 예외처리시 catch(Exception e) 로 간단하게 입력해도 문제없다
다중 catch문을 사용할때는 예외를 하위부터 상위 순으로 catch 해야한다
이유는 위에서부터 발생한 예외 종류를 비교하기 때문에 상위가 위로 올라올 경우 아래 예외는 처리될 수 없다
가장 상위인 catch(Exception e)를 가장 첫 catch문으로 썻기 때문에 오류 발생
public class ExceptionHandlingExample {
public static void main(String[] args) {
String[] array = {"100","1oo"};
for(int i = 0; i <= array.length; i++) {
try {
int value = Integer.parseInt(array[i]);
System.out.println("array["+i+"]:" + value);
}catch(Exception e) {
System.out.println("예외발생");
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("배열인덱스가 초과됨:"+e.getMessage());
}catch(NumberFormatException e) {
System.out.println("숫자로 변환할 수 없음:" + e.getMessage());
}
}
}
}
catch(Exception e)를 가장 마지막 catch문으로 수정하면 오류없이 동작한다
public class ExceptionHandlingExample {
public static void main(String[] args) {
String[] array = {"100","1oo"};
for(int i = 0; i <= array.length; i++) {
try {
int value = Integer.parseInt(array[i]);
System.out.println("array["+i+"]:" + value);
String str = null;
System.out.println(str.equals("test"));
}catch(ArrayIndexOutOfBoundsException e) {
System.out.println("배열인덱스가 초과됨:"+e.getMessage());
}catch(NumberFormatException e) {
System.out.println("숫자로 변환할 수 없음:" + e.getMessage());
}catch(Exception e) {
//try에서 발생한 예외가 NumberFormatException, ArrayIndexOutOfBoundsException
//이 아닌 경우 실행되는 위치
System.out.println("예외발생" + e.getMessage()); //메시지만 알려줌
e.printStackTrace(); //발생한 예외 종류, 메시지, 위치 알려줌
}
}
}
}
실행결과)
array[0]:100 예외발생Cannot invoke "String.equals(Object)" because "str" is null java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because "str" is null at javastudy.ch11_exception.ExceptionHandlingExample.main(ExceptionHandlingExample.java:16) 숫자로 변환할 수 없음:For input string: "1oo" 배열인덱스가 초과됨:Index 2 out of bounds for length 2 |
멀티 catch
발생한 다양한 예외들에 대하여 처리 코드가 같은 경우 사용하는 catch문
<주의사항>
같은 계층의 예외들로 사용하는 것이 좋다
for(int i = 0; i <= array.length; i++) {
try {
int value = Integer.parseInt(array[i]);
System.out.println("array["+i+"]:" + value);
}catch(ArrayIndexOutOfBoundsException | NumberFormatException e) {
System.out.println("숫자 또는 인덱스 오류:"+e.getMessage());
}
}
실행결과)
array[0]:100 숫자 또는 인덱스 오류:For input string: "1oo" 숫자 또는 인덱스 오류:Index 2 out of bounds for length 2 |
리소스 자동 닫기
try문에서 생성된 리소스 객체를 자동 종료하는 방법
/*
리소스 클래스 정의
-리소스 클래스는 AutoCloseable 인터페이스를 구현해야한다.
*/
public class MyResource implements AutoCloseable {
@Override
public void close() throws Exception {
System.out.println("MyResource 객체 종료!");
}
}
try(MyResource mr = new MyResource()){
//mr은 try 블럭 내부에서 계속 사용 가능
System.out.println("리소스 사용중!");
}catch(Exception e) {
e.printStackTrace();
}
실행결과)
리소스 사용중! MyResource 객체 종료! |
try-resource를 사용하지 않은 경우
MyResource mr2 = null;
try{
mr2 = new MyResource();
}catch(Exception e) {
e.printStackTrace();
}finally {
if(mr2 != null) {
try {
mr2.close();
}catch(Exception e) {
e.printStackTrace();
}
}
}
예외 떠넘기기
- 발생한 곳이 아닌 호출한 곳에서 예외를 처리하도록 발생예외를 떠넘기는 것을 의미한다.
- 떠넘김 받은 예외의 종류와 처리하는 예외의 종류는 같아야 하지만 처리하는 예외가 더 상위 예외라면 문제없이 처리가능!
- main에서 예외를 떠넘기는 경우 JVM이 예외를 받게 되며 JVM은 오류메시지를 콘솔에 출력하며 시스템을 정상 종료한다.
문법)
메소드 선언부 throws 예외클래스1, ... 예외클래스n
기존에는 try catch를 이렇게 작성했다
public class Main02 {
public static void main(String[] args) {
int number = numberTrance("100a");
System.out.println(number + 20);
}
public static int numberTrance(String str){
try {
int result = Integer.parseInt(str);
return result;
}catch(NumberFormatException e) {
e.printStackTrace();
return 0;
}
}
}
예외떠넘기기를 할 경우 밑처럼 작성하면 된다
public class Main02 {
public static void main(String[] args) {
try {
int number = numberTrance("100a");
System.out.println(number + 20);
}catch(Exception e) {
System.out.println("숫자변환오류!");
}
}
public static int numberTrance(String str) throws NumberFormatException {
int result = Integer.parseInt(str);
return result;
}
}
1)
public class ThrowsExample {
public static void main(String[] args) {
try {
findClass();
}catch(ClassNotFoundException e) {
System.out.println("예외처리:" + e.toString());
}
}
public static void findClass() throws ClassNotFoundException{
Class.forName("java.lang.String2");
}
}
실행결과)
예외처리:java.lang.ClassNotFoundException: java.lang.String2 |
2) JVM으로 예외 떠넘기기 => main() throws 예외클래스
public static void main(String[] args) throws NumberFormatException {
int number = numberTrance("100a");
System.out.println(number + 20);
}
public static int numberTrance(String str) throws NumberFormatException {
int result = Integer.parseInt(str);
return result;
}
실행결과)
Exception in thread "main" java.lang.NumberFormatException: For input string: "100a" at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67) at java.base/java.lang.Integer.parseInt(Integer.java:668) at java.base/java.lang.Integer.parseInt(Integer.java:786) at javastudy.ch11_exception.Main02.numberTrance(Main02.java:20) at javastudy.ch11_exception.Main02.main(Main02.java:14) |
예외 발생시키기
- 예외처리에 대한 코드 확인을 하기 위하여 사용한다
문법)
throw new 예외클래스생성자 호출;
public static void main(String[] args) {
try {
System.out.println("정상코드");
throw new NullPointerException();
}catch(NullPointerException e) {
System.out.println("참조 값 없음");
}
}
'Java' 카테고리의 다른 글
[Java] toString(), StringBuilder, StringTokenizer, Math, Wrapper (0) | 2024.08.10 |
---|---|
[Java] Object, equals(), hashCode() (0) | 2024.08.09 |
[Java] 익명 객체, 다중인터페이스 (0) | 2024.08.07 |
[Java] 인터페이스 (0) | 2024.08.06 |
[Java] 상속, 메소드 오버라이딩, 추상클래스 (0) | 2024.08.03 |