자바 9일차

하파타카·2021년 12월 15일
0

JAVA수업

목록 보기
9/10

한 일

  • enum
  • enum 생성자
  • enum을 이용한 삼세판 가위바위보게임
  • 예외 (exception)
  • 예외처리 try-catch문
  • 예외처리 throw
  • 커스텀 예외처리
  • 여러개의 예외처리
  • try-catch문의 finally
  • 런타임 에러 (RuntimeException)

enum

관련이 있는 상수들의 집합.
enum으로 선언 시 이 객체가 상수들의 집합임을 나타냄.
클래스처럼 사용이 가능하다.

- Fruit.enum -

package enum_example;
public enum Fruit {		// class와 달리 키워드가 enum임 (클래스로 만든 후 바꿔도 ok)
	APPEL, BANANA, ORANGE, MELON	// 상수들의 집합 (인덱스 번호 0, 1, 2, 3)
}

- App.class -

package enum_methods;
public class App {
	public static void main(String[] args) {
		// enum에서 사용하는 메소드
//		Fruit[] fruits = Fruit.values();	// enum명.values()	=> 선택한 enum의 모든 상수들을 배열로 리턴
//		for (Fruit f : fruits) {
//			System.out.println(f);
//		}
		// 위의 7 ~ 10행을 축약
		for (Fruit f : Fruit.values()) {	// Fruit의 모든 상수들을 배열로 리턴하여 바로 for each문에 사용
			System.out.println(f);
		}
		// ordinal() : enum의 상수의 인덱스 번호 (0부터 시작)
		System.out.println(Fruit.BANANA.ordinal());		// enum Fruit의 BANANA의 인덱스 번호 출력
		System.out.println(Fruit.MELON.ordinal());
		
		// valueOf("상수값") : 상수값과 같은 enum을 찾음
		Fruit f1 = Fruit.valueOf("ORANGE");
		System.out.println(f1);
		System.out.println("f1은 ORANGE와 같은가? " + (f1 == Fruit.ORANGE));
	}
}

ordinal() 메소드

  • enum내 상수의 인덱스 번호를 리턴. 0부터 시작.

예) System.out.println(Fruit.BANANA.ordinal()); => enum Fruit의 BANANA의 인덱스 번호 출력

valueOf("상수값") 메소드

  • 상수값과 같은 enum을 찾아 리턴.

예) Fruit f1 = Fruit.valueOf("ORANGE"); => enum Fruit에서 값이 "ORANGE"인 상수를 찾음.

enum switch문

  • enum의 값들은 고정된 값인 상수이기 때문에 switch-case문의 값으로 사용가능함.

- Fruit.enum -

public enum Fruit {
	APPlE, BANANA, ORANGE, MELON;	// 상수들의 집합 (인덱스 번호 0, 1, 2, 3)
}

- App.class -

public class App {
	public static void main(String[] args) {
		// enum switch
		Fruit fruit = Fruit.ORANGE;
		
		switch (fruit) {
		case ORANGE:
			System.out.println("오렌지");
			break;
		case BANANA:
			System.out.println("바나나");
			break;
		case APPlE:
			System.out.println("사과");
			break;
		case MELON:
			System.out.println("멜론");
			break;
		default:
			System.out.println("없는 과일입니다.");
			break;
		}
	}
}

enum 생성자

!!!개념설명 보충필요!!!

- Fruit.enum -

package enum_methods;
public enum Fruit {
	APPlE("빨간색"), BANANA("노란색"), ORANGE("주황색"), MELON("초록색");
    // 상수들의 집합 (인덱스 번호 0, 1, 2, 3)
	
	private String color;
	Fruit(String color) {	// enum의 생성자. class와 달리 이미 값이 상수로 생성되어 있음
		this.color = color;
	}
	
	public String toString() {
		return super.toString().toLowerCase() + " (" + color + ")";
        	// 상수를 소문자로, 가지고 있던 값까지 함께 출력
		// super를 이용해 enum의 toString을 호출 
	}
}

- App.class -

package enum_methods;
public class App {
	public static void main(String[] args) {
		System.out.println(Fruit.APPlE);	// 상수 APPLE을 소문자 + 갖고있던 color값까지 출력
		System.out.println(Fruit.BANANA);
		System.out.println(Fruit.ORANGE);
		System.out.println(Fruit.MELON);
	}
}

~ enum을 이용한 삼세판 가위바위보 게임 만들기 ~

- GameObject.enum -

package game.objects;
public enum GameObject {
	// name, id값을 enum상수 가위, 바위, 보 값으로 대체
	// enum상수는 class의 객체처럼 사용가능
	가위, 바위, 보;		// 3개의 enum객체 생성
	
	private int[][] comparison = {
	//	나 \ 상대			  가위		바위 		보		
	/* 가위(0) */			{ 0,       -1,		-1 },
	/* 바위(1) */			{ 1,    	0,		-1 },
	/* 보 (2) */			{ -1,	    1,		 0 }
	};
	
	// 상대의 (가위, 바위, 보)와 비교하여 결과를 리턴
	public int compare(GameObject ob) {	// GameObject ob는 enum내 다른 객체를 의미
		return comparison[this.ordinal()][ob.ordinal()];	// enum내 자신의 객체와 다른 객체를 비교한 후 인덱스 번호와 비교
	}	// [this.ordinal()]에는 자신의 인덱스번호가, [ob.ordinal()]에는 다른 객체의 인덱스 번호가 들어가 둘을 배열값과 비교하면 승부결과가 나옴
}

- Game.class -

package game;
import java.util.Random;		// 랜덤클래스의 위치
import java.util.Scanner;
import game.objects.GameObject;

public class Game {
	// 사용할 가위, 바위, 보 객체를 배열로 생성
	GameObject[] objects = GameObject.values();		// enum의 상수들을 배열로 리턴
	Random random = new Random();	// 랜덤클래스 호출(랜덤클래스는 원래부터 존재하므로 호출만 하면됨)
	Scanner scanner = new Scanner(System.in);
	
	public void run() {
		System.out.println("삼세판 게임시작 ...");
		int wins = 0;
		
		for(int i = 1; i <= 3; i++) {		// i를 1부터 3까지 3번 반복
			System.out.println("가위(0), 바위(1), 보(2) 중 숫자로 하나를 선택 : ");
			
			// 질문! 아래처럼 넣었을때 왜 1, 2, 3중 하나를 랜덤선택하는게 아니라 0, 1, 2 중 하나를 고르지?
			// random으로 선택된 objects배열의 길이(여기선 3)에서 하나를 골라 []에 대입 
			GameObject ob1 = objects[scanner.nextInt()];
			GameObject ob2 = objects[random.nextInt(objects.length)];
	
			System.out.println("당신의 선택은 : " + ob1);
			System.out.println("컴퓨터의 선택은 : " + ob2);

			int result = ob1.compare(ob2);		// ob1의 compare메소드를 불러 ob2와 비교한 결과를 result에 대입 
			wins += result;
			
			if(result > 0) {
				System.out.println("당신의 승리!");
			}
			else if(result < 0) {
				System.out.println("당신의 패배...");
			}
			else {
				System.out.println("비겼습니다! Draw!");
			}
		}
		// 세 번의 가위바위보가 끝난 후
		// 총점 wins의 전체 결과를 출력함
		System.out.print("\n삼세판 결과는 : ");
		if(wins > 0) {
			System.out.println("당신의 승리! 🎉🎉🎉🎉");
		}
		else if(wins < 0) {
			System.out.println("당신의 패배... 😢😢");
		}
		else {
			System.out.println("비겼습니다! Draw! 🚩");
		}	
	}
}

- App.class -

package application;
import game.Game;

public class App {
	public static void main(String[] args) {
		// enum을 이용해 클래스를 상수로 바꾸어 축약
		
		// 여기서부터 프로그램 시작
		// 단순히 run()만 실행할거라 객체생성과정을 생략해도 됨, 단 run의 주소는 알 수 없고 실행만 됨
		new Game().run();	
	}
}

예외 (exception)

  • 프로그램 실행과정에서 발생하는 비정상적인 상황.
    예) 존재하지 않는 파일을 오픈, 설정되지 않은 객체의 메소드 호출, 특수문자를 정수형으로 변경 등
  • Exception 클래스는 예외를 생성할 수 있는 클래스.

예외와 오류는 다름. 오류는 실행 전 발생.

예외처리 try-catch문

  • try-catch문을 사용하면 예외 발생 시 직접 처리할 수 있다.
  • 사용
    try {
    예외가 발생할 수 있는 코드
    } catch (예외클래스명 변수명1) {
    지정한 예외발생 시 실행할 코드
    } catch (예외클래스명 변수명2) {
    지정한 예외발생 시 실행할 코드
    } …
public class App {
	public static void main(String[] args) {
		// 예외를 처리하는 try-catch 문
		Scanner scanner = new Scanner(System.in);
		System.out.print("숫자를 입력해주세요 : ");
		String line = scanner.nextLine();	// 문자열로 입력받음
		scanner.close(); 	// 스캐너 종료
		
		int number = 0;
		boolean isNumber = false;
		
		try {		// 예외가 발생 할 수 있는 코드를 작성
			number = Integer.parseInt(line);
			// Integer : int의 객체형, parseInt() : 문자열을 정수형으로 변환 (parseDouble, parseFloot 등도 존재함)
			isNumber = true;	// 숫자이면 true로 변경
		} catch (NumberFormatException e) {		// 예외 발생 시 프로그램 종료가 아니라 여기로 이동함
		// ㄴ (예외클래스명 변수)
			System.out.println("정수로 변활할 수 없습니다.");
		}
		if (isNumber) {
			System.out.println("입력한 숫자는 : " + number);
		}
	}
}

~ 형변환 ~

  • Integer.parse(변환대상) : 대상을 정수형(int)으로 변환
  • Double.parseDouble(변환대상) : 대상을 실수형으로 변환
    이 외에도 있음.

예) number = Integer.parseInt(line); => line을 Integer형으로 변경

예외처리 throw

  • 예외를 직접 처리하는게 아닌 예외사항이 발생한 메소드를 호출할 때 처리하도록 함.
  • main메소드가 호출할때까지 계속 던져주면 결국 예외처리를 main메소드가 해주게 되는데, 이 경우

- Thermostat -

public class Thermostat {
	// 예외처리 throws는 해당 예외 처리를 이 메소드를 호출할 때 처리하도록 함
	public void setTemperature(double temperature) throws Exception {
		
		setMachineTemperature(temperature);
		
		System.out.println("온도 세팅 : " + temperature);
	}

	private void setMachineTemperature(double temperature) throws Exception {
		
		if(temperature < 0 || temperature > 35) {
			throw new Exception("온도가 비정상입니다.");	// 새 예외를 생성
		}
	}
}

- App -

public class App {
	public static void main(String[] args) {
		// throw 예외처리
		Thermostat stat = new Thermostat();
		
		try {
			stat.setTemperature(45.6);
		} catch (Exception e) {
			// 온도 예외 발생
//			e.printStackTrace();
			// ㄴ예외가 처음 발생한 곳 - 다음 발생한 곳 - 그다음 발생한 곳 순으로 콘솔창에 에러위치가 뜸
			System.out.println(e.getMessage());
		}
	}
}

위의 코드에서 e.printStackTrace();로 출력시

위의 코드에서 System.out.println(e.getMessage());로 출력시
=> Thermostat클래스의 setMachineTemperature메소드의 결과인 throw new Exception("온도가 비정상입니다."); 코드가 실행됨.

여러개의 예외처리

예제삼아 볼 것.
- TempOutOfRangeException.class -

package custom_exception.exceptions;
// Exception을 상속받아 새 예외클래스를 만든다.
public class TempOutOfRangeException extends Exception {
	private static final long serialVersionUID = 1L;
	
	public TempOutOfRangeException(String message) {	// 입력된 메세지로 새 예외 객체 생성
		super(message);		
		// message를 상위 클래스인 Exception으로 리턴함
		// Exception는 원래 예외를 생성하는 기능이 있음. 고로 상속받아 message를 넘겨줌으로써 새로운 예외를 만들어준 것.
	}
}

- TempTooHighException.class -

package custom_exception.exceptions;
public class TempTooHighException extends TempOutOfRangeException {
	private static final long serialVersionUID = 1L;

	public TempTooHighException(String message) {
		super(message);	// 상위 클래스인 TempOutOfRangeException로 message를 리턴 
	}
}

- TempTooLowException.class -

package custom_exception.exceptions;
public class TempTooLowException extends TempOutOfRangeException {
	private static final long serialVersionUID = 1L;

	public TempTooLowException(String message) {
		super(message);	// 상위 클래스인 TempOutOfRangeException로 message를 리턴
	}
}

- Thermostat.class -

package custom_exception;
import custom_exception.exceptions.TempTooHighException;
import custom_exception.exceptions.TempTooLowException;

public class Thermostat {
	// 예외처리 throws는 해당 예외 처리를 이 메소드를 호출할 때 처리하도록 함
	public void setTemperature(double temperature) throws TempTooLowException, TempTooHighException  {
		
		setMachineTemperature(temperature);
		System.out.println("온도 세팅 : " + temperature);
	}

	private void setMachineTemperature(double temperature) throws TempTooLowException, TempTooHighException {
		
		if(temperature < 0 ) {
			throw new TempTooLowException("온도가 너무 낮습니다.");	// 새 예외를 생성
		}
		else if(temperature > 35) {
			throw new TempTooHighException("온도가 너무 높습니다.");
		}
	}
}

- App.class -

package custom_exception;
import custom_exception.exceptions.TempTooHighException;
import custom_exception.exceptions.TempTooLowException;

public class App {

	public static void main(String[] args) {
		// throw 예외처리 - 여러개의 예외를 catch문을 추가해 따로 처리
		Thermostat stat = new Thermostat();
		
		try {
			stat.setTemperature(45.6);
		} catch (TempTooHighException e) {	// 온도가 높을 때
			System.out.println(e.getMessage());
		} catch (TempTooLowException e) {	// 온도가 낮을 때
			System.out.println(e.getMessage());
		}
	}
}

temperature가 45.6도 일 때

temperature가 25.6도 일 때

temperature가 -25.6도 일 때

try-catch문의 finally

  • try-catch문 사용 시 try내부에서 에러가 발생하면 그 아래코드를 뛰어넘고 바로 catch문으로 넘어가버린다.
    고로 에러발생여부와 관계없이 무조건 실행되어야 하는 문장이 있을 때 finally 구문을 이용한다.
  • 사용
    try {
    예외가 발생할 수 있는 문장
    } catch (오류1) {
    오류1 발생 시 실행될 문장
    } finally {
    무조건 실행될 문장
    }
public class Person {
	private String name;	// private 로 선언 시 바로 접근할 수 없어 메소드가 필요함 아래는 접근을 위한 메소드
	public void setName(String name) throws Exception {
		if(name == null) {
			throw new Exception("이름에 null값을 입력할 수 없습니다.");	// 예외 발생
		}
		this.name = name;
		System.out.println("이름은 " + name);
	}
}
public class App {
	public static void main(String[] args) {
		Person p1 = new Person();
		try {
			p1.setName(null);	// null, "펭수" 둘 다 넣어보기
			// ㄴ null인 이 문장을 try-catch문 없이 그냥 실행 시 예외 발생, 프로그램 정상종료가 아닌 중단이 되어버림
			System.out.println("예외 발생 시 여기는 실행안됨");	// name에 null값이 들어있으면 윗문장에서 바로 catch문으로 넘어감
		} catch (Exception e) {
			System.out.println(e.getMessage());
		} finally {	// 여기는 예외발생과 상관없이 무조건 실행됭
			System.out.println("fianlly는 예외발생과 상관없이 무조건 실행");
		}	
		System.out.println("프로그램 종료");
	}
}

null값을 넣었을 때 결과

"펭수"를 넣었을 때 결과

=> 예외 발생여부에 따라 실행되는 문장의 수에 차이가 있음.

런타임 에러 (RuntimeException)

프로그램 실행 중 발생하는 에러
예외처리를 하지 않아도 됨
예) NullPointException 등

public class Thermostat {
	// runtime 예외는 예외처리를 하지 않아도 된다
	// runtime : 프로그램 실행중 발생하는 에러이기때문에 문법상 에러는 나타나지 않는다(실행하면 에러가 발생하긴함)
	public void setTemperature(double temperature) {
		
		if(temperature < 0 || temperature > 35) {
			throw new RuntimeException("온도가 비정상입니다.");	// 새 예외를 생성
		}
		System.out.println("온도 세팅 : " + temperature);
	}
}
public class App {
	public static void main(String[] args) {
		// throw 예외처리
		Thermostat stat = new Thermostat();
		
		stat.setTemperature(40);
	}
}

실행전에는 문법오류가 나타나지 않지만 실행 시 오류가 발생함.

profile
천 리 길도 가나다라부터

0개의 댓글

관련 채용 정보