이번 포스팅에서는 예외란 무엇인지, 예외의 처리방법, 예외가 아닌 것을 예외화 하는 법, 예외 미루기에 대한 내용을 정리해보았다.
1. 예외
: 사용자가 서비스를 이용하는데에 불편함을 주는 사항을 어떻게 해결해야하는지를 분석할 수 있도록 한다.
1) 예외란?
- Exception 혹은 오류라고도 표현 할 수 있다
- 문법상(코드상) 문제가 없었으나, 실제 수행과정에서 발생하는 문제
- 예외가 발생하면 프로그램은 즉시 종료된다(ex. 온라인게임 도중 네트워크가 안잡히면 종료되는 현상)
- 프로그램을 끝까지 사용할 수 없게 됨 : 서비스를 이용하는데 불편함을 준다
- Exception도 다양한 class가 존재한다!
2) 예외의 분석
: 예외가 발생하면 콘솔창에 Exception이라는 문구와 함께 오류와 관련된 3가지의 정보를 담고있는 메세지가 출력된다.
- 어떤 class 혹은 type의 예외인지
- 오류에 대한 상세 설명
- 오류가 발생한 ilne number
위의 내용을 토대로 예시를 하나 해석하자면 아래와 같다
Scanner sc = new Scanner(System.in);
System.out.println("티");
int num=sc.nextInt();
System.out.println(num/10);
System.out.println("모");
출력 결과: 티 Exception in thread "main" java.lang.ArithmeticException: / by zero at class01.Test01.main(Test01.java:13)
-> ArithmeticException클래스와 관련된 예외이다(1)
-> 13번 라인에 0으로 입력할 수 없다(2)
-> 오류 발생 라인은 13번(3)
2. 예외처리
: 오류해결의 의미와 비슷하다. 어떤 예외가 발생할지 예상이 불가능하고, if문과 유사한의미의 try catch문을 사용한다
1) try catch
try{
//예외가 발생할지도 모르는 부분
//감싸줘야하는 부분
} catch (Exception클래스명 객체명) { //Exception클래스에 해당하는 오류 발생시
출력문구 //여기 출력
}
선언 방법은 위와 같으며, 구체적으로 적용하면 아래와 같은 형태가 있다.
package class01;
//Exception 클래스에 따라 임폴트의 추가여부 결정됨
import java.util.InputMismatchException;
import java.util.Scanner;
public class Test01 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("티"); //확인개념
try {
System.out.println(">>");
int num=sc.nextInt();
System.out.println("확인1"); //예외가 발생한다면 즉시 catch로 이동
System.out.println(num/10);
System.out.println("확인2");
}catch(ArithmeticException e) { //0이 입력되는것을 방지
System.out.println("계산불가능");
}catch(InputMismatchException e) { //정수외의 입력 방지
System.out.println("정수로 입력하시오");
}
System.out.println("모"); //확인개념
}
}
[출력결과 : ★ = 입력]
티
>>
모
정수로 입력하시오
모
---------------------------------------
티
>>
0
확인1
계산불가능
모
---------------------------------------
티
>>
30
확인1
3
확인2
모
확인개념의 출력문구를 통해 어떠한 로직으로 구현되어있는지 대략적인 이해가 가능하다.
2) 예외 파악
: 예외처리를 통해 발생할 수 있는 예외를 파악하고 대비하는 것을 예외 파악이라고 한다. 예외 파악의 방법으로는 언리쳐블코드에 유의하며 catch문과 getMessage( ) 혹은 printStackTrace( )을 통해 예외를 파악하고 분석하여 대비할 수 있다.
*언터쳐블코드 : 다운캐스팅과 비슷한 개념으로, 상위개념이 더 위에 선언되어 하위개념의 내용이 평생 출력되지 못하는 Ded Code가 발생하는 것
*언터쳐블코드 예시
if(짝수라면){
}else if(6배수라면){
여기 든건 평생 못본다 ! ded
}
try{
}catch(Exception e){
}catch(InputMismatchException e){
하위개념이라 평생 출력XX
}
3) 예제( + finally )
: int 배열에 값을 담고, index를 입력받아 해당 index의 값을 출력하는 코드. if 잘못된 범위의 입력이라면 예외처리
package class01;
import java.util.InputMismatchException;
import java.util.Scanner;
public class Test02 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int [] data = {10 ,20, 30};
System.out.println("0~2의 숫자를 입력해주세요");
System.out.println("정수입력 : ");
try {
//사용자가 입력할 자료형이 무엇인지 모르므로
//출력일지 미출력일지 갈리는 부분
int num = sc.nextInt();
System.out.println(data[num]);
}catch(ArrayIndexOutOfBoundsException e) {//오류라면
System.out.println(e.getMessage()); //오류메세지 띄워라
System.out.println("데이터가 존재하지 않습니다");
}catch(Exception e) {//그외 파악되지 않은 오류라면
e.printStackTrace(); //오류에 대한 상세정보 출력
} finally {
System.out.println("오류의 유무와 상관없이 출력됨 / logging 개념");
}
}
}
[출력결과 : ★ = 입력]
0~2의 숫자를 입력해주세요
정수입력 :
일
오류의 유무와 상관없이 출력됨 / logging 개념
java.util.InputMismatchException
at java.util.Scanner.throwFor(Unknown Source)
at java.util.Scanner.next(Unknown Source)
at java.util.Scanner.nextInt(Unknown Source)
at java.util.Scanner.nextInt(Unknown Source)
at class01.Test02.main(Test02.java:20)
---------------------------------------------------------------------------
0~2의 숫자를 입력해주세요
정수입력 :
5
5
데이터가 존재하지 않습니다
오류의 유무와 상관없이 출력됨 / logging 개념
---------------------------------------------------------------------------
0~2의 숫자를 입력해주세요
정수입력 :
2
30
오류의 유무와 상관없이 출력됨 / logging 개념
3. 예외화
: 내가 원하는 범위가 아니라면 유효성 검사나 경계값 검사를 통해 사용자의 입력값을 제한할 수 있다. 하지만 이때 if문을 사용하기에 데이터 차지가 효율적이지 않으니, 효율성을 높이기 위해 일부러 예외화를 시켜서 처리할 수 있다.
1) 예외화의 배경이론
: 예외화의 방법을 알아보기에 앞서, 평상시에 생략되어있는 Exception클래스의 내용을 다시한번 상기할 필요가 있다.
class Exception{
private String message; //멤버변수
Exception(){}//생성자
Exception(String message){ //생성자 오버로딩
this.message = message;
}
public String getMessage() { //message의 get화
return message;
}
}
즉, Exception클래스의 생성자가 오버로딩 되어있음을 알아야한다!
2) 예외화의 방법
: 종료되지 않는 반복문을 선언하고, 내가 원하는 범위의 입력이 아니라면 "범위 외의 입력"을 출력하는 코드
package class01;
import java.util.Scanner;
//예외클래스를 상속받아 나만의 예외클래스 정의
//1. 상세설명(message) 설정강제
//2. 미확인 예외들(Exception)과 섞임 방지
class MyException extends Exception{
MyException(String message){
//자식클래스의 생성자는
//부모클래스의 기본 생성자를 호출하므로
super(message);
}
}
public class Test03 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
MyException myExcep = new MyException("범위 외의 입력"); //내가 만든 예외
// Exception클래스의 생성자는 오버로딩 되어있음을 알 수 있다.
while(true) {
System.out.println("입력 : ");
try {
int num = sc.nextInt();
if(num<1 || num>3) { //내가 원하는 범위가 아니라면
// throw : 일부러 예외를 만드는 역할
// 즉, try catch를 반드시 필요로 함
throw myExcep;
}
}catch(Exception e) {
System.out.println(e.getMessage()); //범위외의 입력이라면
}
}
}
}
[출력결과 : ★ = 입력]
입력 :
6
범위 외의 입력
입력 :
1
입력 :
78
범위 외의 입력
입력 :
3) 예제
1번예제 : 0~100 사이의 정수를 입력받고, 10과 입력받은 값을 나눈 결과를 출력하라. 단, 예외를 파악하고 처리할 것.
-> 해당문제 풀이를 통해 다른 타입의 입력을 받았을때 발생하는 버퍼문제를 해결할 수 있다.
package class01;
import java.util.InputMismatchException;
import java.util.Scanner;
//예외가 아닌 것을 예외화 할 목적(: 0~100이외 예외화)
class MyException extends Exception{
MyException(String message){
super(message);
}
}
public class Test04 {
public static void main(String[] args) {
MyException myExcep = new MyException("0~100사이의 정수를 입력하세요");
Scanner sc = new Scanner(System.in);
int num=10;
System.out.println("10과 나눌 수를 입력하세요");
while(true) {
try {
System.out.println("입력: ");
int x = sc.nextInt();
if(x<0 || x>100) { //범위외의 입력이면
throw myExcep;
}
//if문을 통과해야 값을 조회해야하므로
System.out.println(num + "/" + x + "=" + num/x);
}catch(ArithmeticException e) { //0이 입력되면
System.out.println("0으로 나눌 수 없습니다");
}catch(InputMismatchException e) { //정수 외의 입력이면
// 버퍼문제(무한루프) : 콘솔화면을 UI로 사용하기때문에 문제가 되는 부분
// 문제해결 : Double이나 String의 입력을 받아줄 친구 생성!
sc.nextLine();
System.out.println("정수만 입력할 수 있습니다");
}catch(Exception e) { //미확인 예외라면
e.printStackTrace();
}
}
}
}
[출력결과 : ★ = 입력]
10과 나눌 수를 입력하세요
입력:
4
10/4=2
입력:
70
10/70=0
입력:
육
정수만 입력할 수 있습니다
입력:
6.22
정수만 입력할 수 있습니다
입력:
2번예제 : 학생 관리 시스템
package class01;
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.Iterator;
import java.util.Scanner;
class Student{
//멤버변수
String name;
private int pk;
int score;
//생성자
Student(String name, int pk, int score){
this.name = name;
this.pk = pk;
this.score = score;
}
//getter
public int getPk() {
return pk;
}
//setter
public void setPk(int pk) {
this.pk = pk;
}
@Override
public String toString() {
return pk +" | "+ name + " | " + score + "점";
}
}
class MyException extends Exception{
MyException(String message){
super(message);
}
}
public class Test05 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
ArrayList <Student> data = new ArrayList <Student> ();
MyException myExcep1 = new MyException("없는 메뉴입니다");//메뉴선택
MyException myExcep2 = new MyException("0~100사이로 입력하세요");//성적
int pkNum = 2022001; //학번 시작번호
int score;//점수
String name;//이름
String mainMsg = "1. 추가 \n2. 삭제 \n3. 학생조회 \n4. 종료";
int choice;//메뉴선택
int num; //입력받을 학번
while(true) {
System.out.println("=====화면=====");
System.out.println(mainMsg);
System.out.println("=============");
System.out.println(">>");
try {
choice = sc.nextInt();
if(choice==1) { //1. 추가
System.out.println("이름 : ");
name = sc.next();
System.out.println("점수 : ");
score = sc.nextInt();
if(score<0 || score>100) {
throw myExcep2;
}
data.add(new Student(name, pkNum++, score));
System.out.println("추가 완료");
}else if(choice==2) { //2. 삭제
//경계값 검사
while(true) {
System.out.println("삭제할 학번 : ");
num = sc.nextInt();
if(num>2022000 && num<2023000) {
break;
}
}
//유효성검사
boolean flag = true; // T=미존재 / F=존재
for(int i=0; i<data.size(); i++) {
if(num==data.get(i).getPk()) {
flag = false;
data.remove(i);
System.out.println("삭제완료");
break; //for문 종료
}
}
if(flag) {
System.out.println("존재하지 않는 학번입니다");
}
}else if(choice==3) { //3. 학생조회
Iterator itr = data.iterator();
while(itr.hasNext()) {
System.out.println(itr.next());
}
}else if(choice==4) { //4. 종료
System.out.println("프로그램 종료");
break;
}else {
throw myExcep1;
}
}catch(InputMismatchException e) {
sc.nextLine();//무한루프방지
System.out.println("입력 범위를 확인하세요");
}catch(MyException e) {
System.out.println(e.getMessage());
}
}
}
}
[출력결과 : ★ = 입력]
=====화면=====
1. 추가
2. 삭제
3. 학생조회
4. 종료
=============
>>
1
이름 :
김핑구
점수 :
-3
0~100사이로 입력하세요
(생략)
점수 :
68
추가 완료
=====화면=====
1. 추가
2. 삭제
3. 학생조회
4. 종료
=============
>>
3
2022001 | 김핑구 | 68점
=====화면=====
1. 추가
2. 삭제
3. 학생조회
4. 종료
=============
>>
2
삭제할 학번 :
2022004
존재하지 않는 학번입니다
(생략)
삭제할 학번 :
2022001
삭제완료
=====화면=====
1. 추가
2. 삭제
3. 학생조회
4. 종료
=============
>>
4
프로그램 종료
4. 예외처리 미루기
1) 예외처리 미루기란?
: 똑같은 예외가 여러군데에서 발생할 수 있기 때문에, 예외처리에 대한 로직이 여러개 중복될 수 있다. 이럴 경우 유지보수에 굉장히 불리하므로 예외를 미루어 처리하는 경우가 발생한다. "
2) 예외처리 미루기 선언
: "예외 처리를 호출한 대상에게(공간으로) 미루겠습니다."라는 의미이다. 함수를 먼저 선언하고, 메인에서 해당 함수를 호출한다. 일련의 과정일때와 그렇지 않을때로 구분된다.
- throws를 이용한 함수 선언 ( 공통적인 부분 )
public class Test06 {
static void func1() throws Exception{ //머리부분
int a=10, b=0;
System.out.println(a/b);
System.out.println("func1() 함수 종료!");
}
static void func2() throws Exception{ //팔부분
Exception excep = new Exception("예외!");
throw excep;
}
Throws로 인해 (main혹은 지정한 곳으로) 던져지고, catch로던져진 예외를 받는다!
* static 이란? "객체와 무관하게"라는 의미이다. 사용되는 두가지 경우는 순서대로 1. 클래스 변수(공유자원), 2. 클래스 외부에서함수 단독선언이 있다.
- 일련의 과정일때 : func1이 오류이면 func2가 진행되지 않아야할때
try {
//함수 입력시 try catch문 필수 생성 : 오류발생
func1();
func2();
} catch (Exception e) {
e.printStackTrace();
}
- 일련의 과정이 아닐때 : 일련의 과정이 아닐때 : func1이 오류여부와 func2의 작동이 별개일때
try {
func1();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
System.out.println("48번 라인 통과");
}
try {
func2();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
System.out.println("57번 라인 통과");
}
[출력결과] -> 출력할때마다 순서 뒤죽박죽임
java.lang.ArithmeticException: / by zero
at class01.Test06.func1(Test06.java:15)
at class01.Test06.main(Test06.java:30)
java.lang.ArithmeticException: / by zero
at class01.Test06.func1(Test06.java:15)
at class01.Test06.main(Test06.java:41)
java.lang.Exception: 예외!
at class01.Test06.func2(Test06.java:20)
at class01.Test06.main(Test06.java:50)
48번 라인 통과
57번 라인 통과
'JAVA' 카테고리의 다른 글
[파일 입출력] TXT & 이미지형식 (+Wrapper Class) (0) | 2022.01.14 |
---|---|
[Thread] 블록 & 동기화 (0) | 2022.01.13 |
[컬렉션프레임워크] 링크리스트 & 그 외 컬렉션 (0) | 2022.01.12 |
[컬렉션프레임워크] 배열리스트 (0) | 2022.01.11 |
자판기 만들기_재고와 PK (0) | 2022.01.10 |