관련이 있는 상수들의 집합.
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));
}
}
예) System.out.println(Fruit.BANANA.ordinal()); => enum Fruit의 BANANA의 인덱스 번호 출력
예) Fruit f1 = Fruit.valueOf("ORANGE"); => enum Fruit에서 값이 "ORANGE"인 상수를 찾음.
- 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;
}
}
}
!!!개념설명 보충필요!!!
- 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);
}
}
- 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();
}
}
예외와 오류는 다름. 오류는 실행 전 발생.
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);
}
}
}
예) number = Integer.parseInt(line); => line을 Integer형으로 변경
- 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도 일 때
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값을 넣었을 때 결과
"펭수"를 넣었을 때 결과
=> 예외 발생여부에 따라 실행되는 문장의 수에 차이가 있음.
프로그램 실행 중 발생하는 에러
예외처리를 하지 않아도 됨
예) 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);
}
}
실행전에는 문법오류가 나타나지 않지만 실행 시 오류가 발생함.