과거
class Car {
static final int CLOVER = 0;
static final int HEART = 1;
static final int DIAMOND = 2;
static final int SPADE = 3;
static final int TWO = 0;
static final int THREE = 1;
static final int FOUR = 2;
final int kind;
final int num;
}
특정 상수값을 사용하기 위해선 모두 상수로 선언해서 사용
→ 개발자의 실수, 가시성↓, 지저분한 변수명 등... 문제 발생
대안
Enum 클래스
class Car {
enum Kind { // 열거형 Kind 정의
CLOVER, HEART, DIAMOND, SPADE // 각각의 값은 '열거 상수(enumeration constant)'
}
enum Value { // 열거형 Value 정의
TWO, THREE, FOUR
}
final Kind kind; // 주의! Kind 타입이다
final Value value;
}
여러 상수를 선언할 경우, 편리하게 사용할 수 있는 방법
모든 enum들은 내부적으로 java.lang.Enum 클래스에 의해 상속된다.
(클래스는 하나의 부모 클래스에 의해서만 상속되므로, enum은 다른것을 상속할 수가 없다.)
열거 타입은 참조 타입이기 때문에, 열거 타입 변수에 null값을 저장할 수 있음
Enum으로 관리하면, DB접근이 없다.
→ DB로 관리하면, 테이블과 조회쿼리가 복잡해진다.
런타임환경에서는 카테고리가 변하지 않는다.
→ 컴파일 타임 안전성을 제공
열거체를 비교할 때, '실제 값' + '타입'까지도 체크
열거체의 상숫값이 재정의되더라도, 다시 컴파일할 필요 X
허용 가능한 값들을 제한 가능
(문자열과 달리) IDE 의 적극적인 지원을 받을 수 있다. (동완성, 오타검증, 텍스트 리팩토링 등...)
리팩토링 시, 변경 범위가 최소화
→ 내용의 수정/추가가 필요하더라도, Enum 코드 외에 수정할 필요 X
첫 글자는 대문자, 나머지는 소문자
여러 단어로 구성된 이름은? 각 단어의 첫 글자를 대문자로
소스 파일 이름과 대소문자 모두 일치해야 함
대문자
여러 단어로 구성될 경우? 단어 사이를 언더바( _ )로 연결
열거 상수는 객체
// 문법
enum 열거형이름 { 상수이름1, 상수이름2, ... }
// 예시 : 상수로 정의하는 방법
enum Direction { EAST, SOUTH, WEST, NORTH }
// 예시 : 정의된 상수를 사용하는 방법
class Unit {
int x; // 유닛의 위치
int y; // 유닛의 위치
Direction dir; // 열거형 인스턴스 변수 선언
void init() {
dir = Direction.EAST; // 유닛의 방향을 EAST로 초기화
}
}
열거형이름.상수이름
if (DIR == Direction.EAST) {
x++;
} else if (dir > Direction.WEST) { // 에러 : '>' 사용 X
...
} else if (dir.compareTo(Direction.WEST) > 0) {
...
}
==
: 사용 O
equals : 사용 X
compareTo()
: 사용 O
<, > : 사용 X
참고: 자바 컬렉션 (Java Collection, 컬렉션 프레임워크) - 4. Comparable, Comparator
static E values()
해당 열거체의 모든 상수를 저장한 배열을 생성하여 반환
자바의 모든 열거체에 컴파일러가 자동으로 추가
enum Rainbow { RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET }
public class Enum01 {
public static void main(String[] args) {
Rainbow[] arr = Rainbow.values();
for (Rainbow rb : arr) {
System.out.println(rb);
}
}
}
// 실행 결과
RED
ORANGE
YELLOW
GREEN
BLUE
INDIGO
VIOLET
static E valueOf(String name)
전달된 문자열과 일치하는 해당 열거체의 상수를 반환
기본 타입의 값을 문자열로 변환
//예시 1
enum Rainbow { RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET }
public class Enum02 {
public static void main(String[] args) {
Rainbow rb = Rainbow.valueOf("GREEN");
System.out.println(rb);
}
}
/* 실행 결과
GREEN */
// 예시 2
public class StringvalueofExample {
public static void main(String[] args) {
String str1 = String. valueof(10);
String str2 = String.valueof(10.5);
String str3 = String.valueof(true);
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
}
}
/* 실행 결과
10
10.5
true */
int ordinal()
해당 열거체 상수가 열거체 정의에서 정의된 순서(0부터 시작)를 반환
이때 반환되는 값은 열거체 정의에서 해당 열거체 상수가 정의된 순서 (상숫값 자체가 아님)
enum Rainbow { RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET }
public class Enum03 {
public static void main(String[] args) {
int idx = Rainbow.YELLOW.ordinal();
System.out.println(idx);
}
}
// 실행 결과
2
해당 Enum 클래스가 final 메소드를 가질 수 없게 됨
해당 열거체 상수의 이름을 반환
// 예시 1
enum Direction {
EAST(1), SOUTH(5), WEST(-1), NORTH(10);
private final int value; // 정수를 저장할 인스턴스 변수(필드) 추가
Direction(int value) { // 생성자 추가
this.value = value;
}
publid int getValue() { // 외부에서 해당 값을 얻을 수 있도록 함
return value;
}
}
// 예시 2 : 값이 두 개일 경우
enum Direction {
EAST(1, ">"), SOUTH(5, "V"), WEST(-1, "<"), NORTH(10, "^");
private final int value; // 정수를 저장할 인스턴스 변수(필드) 추가
private final String symbol;
Direction(int value, String symbol) { // 생성자 추가
this.value = value;
this.symbol = symbol;
}
publid int getValue() { // 외부에서 해당 값을 얻을 수 있도록 함
return value;
}
publid int getSymbol() { // 외부에서 해당 값을 얻을 수 있도록 함
return symbol;
}
}
(원하는 값)
을 적어 줄 수 있다// 기존 코드
LoginResult result = LoginResult.FAIL_PASSWORK;
if (result == LoginResult.SUCCESS) {
...
} else if (result == LoginResult.FAIL_ID) {
...
} else if (result == LoginResult.FAIL_PASSWORK) {
...
}
// 열거 타입으로 변형
public enum LoginResult {
SUCCESS,
FAIL_ID,
FAIL_PASSWORD
}
상품의 카테고리를 관리하려고 한다.
DB 로 관리
SELECT item.* FROM
item INNER JOIN categories ON item.category_id = categories.id
WHERE item.is_active = 1 AND (categories.is_active = 1 AND categories.parent_id IN
(SELECT id FROM categories WHERE parent_id IS NULL AND is_active = 1)) OR ( item.is_active = 1 AND categories.parent_id IS NULL AND categories.is_active = 1 )
계층형 구조를 지닌 카테고리의 경우, 매우 복잡해진다.
→ 그 대안으로 Enum 을 사용한다.
Enum 으로 관리
public enum Category {
ROOT("카테고리", null),
FASHION("패션의류/잡화", ROOT),
FASHION_MEN("남성", FASHION),
MEN_T_SHIRT("티셔츠", FASHION_MEN),
MEN_SWEATSHIRT_HOOD("스웻셔츠/후드", FASHION_MEN),
MEN_SHIRT("셔츠", FASHION_MEN),
MEN_SUIT("정장", FASHION_MEN),
MEN_PANTS("바지", FASHION_MEN),
FASHION_WOMEN("여성", FASHION),
WOMEN_T_SHIRT("티셔츠", FASHION_WOMEN),
WOMEN_BLOUSE("블라우스/셔츠", FASHION_WOMEN),
WOMEN_SWEATSHIRT_HOOD("스웻셔츠/후드", FASHION_WOMEN),
WOMEN_SUIT("정장", FASHION_WOMEN),
WOMEN_ONE_PIECE("원피스", FASHION_WOMEN),
WOMEN_SKIRT("치마", FASHION_WOMEN),
WOMEN_PANTS("바지", FASHION_WOMEN),
UNISEX("남녀공용", FASHION),
UNISEX_T_SHIRT("티셔츠", UNISEX),
UNISEX_PANTS("바지", UNISEX),
BAG_ACC("가방/잡화", FASHION),
BAG("가방", BAG_ACC),
BACKPACK("백팩", BAG),
CROSS_BAG("크로스백", BAG),
SHOULDER_BAG("숄더백", BAG),
MINI_BAG("미니백", BAG),
ECO_BAG("캔버스/에코백", BAG),
WALLET_BELT("지갑/벨트", BAG_ACC),
WALLET("지갑", WALLET_BELT),
BELT("벨트", WALLET_BELT),
SHOES("신발", FASHION),
SNEAKERS("운동화/스니커즈", SHOES),
FLAT_SHOES("단화/플랫", SHOES),
HEEL("힐", SHOES),
BOOTS("워커/부츠", SHOES),
SLIPPER("슬리퍼", SHOES),
FASHION_CHILDREN("아동", FASHION),
GIRL_FASHION("여아", FASHION_CHILDREN),
BOY_FASHION("남아", FASHION_CHILDREN),
FOOD("식품", ROOT),
INSTANT("가공/즉석식품", FOOD),
BEVERAGE("생수/음료", FOOD),
FRESH("신선식품", FOOD),
MEAT_EGG("축산/계란", FOOD),
RICE("쌀/잡곡", FOOD),
DIGITAL("가전/디지털", ROOT),
VIDEO("TV/영상가전", DIGITAL),
TV("TV", VIDEO),
PROJECTOR("프로젝터/스크린", VIDEO),
COMPUTER("컴퓨터/게임/SW", DIGITAL);
// 카테고리 이름
private final String title;
// 부모 카테고리
private final Category parentCategory;
// 자식카테고리
private final List<Category> childCategories;
Category(String title, Category parentCategory) {
this.childCategories = new ArrayList<>();
this.title = title;
this.parentCategory = parentCategory;
if(Objects.nonNull(parentCategory)) {
parentCategory.childCategories.add(this);
}
}
public String getTitle() {
return title;
}
// 부모카테고리 Getter
public Optional<Category> getParentCategory() {
return Optional.ofNullable(parentCategory);
}
// 자식카테고리 Getter
public List<Category> getChildCategories() {
return Collections.unmodifiableList(childCategories);
}
// 마지막 카테고리(상품추가 가능)인지 반환
public boolean isLeafCategory() {
return childCategories.isEmpty();
}
// 마지막 카테고리(상품추가 가능)들 반환
public List<Category> getLeafCategories() {
return Arrays.stream(Category.values())
.filter(category -> category.isLeafCategoryOf(this))
.collect(Collectors.toList());
}
private boolean isLeafCategoryOf(Category category) {
return this.isLeafCategory() && category.contains(this);
}
private boolean contains(Category category) {
if(this.equals(category)) return true;
return Objects.nonNull(category.parentCategory) &&
this.contains(category.parentCategory);
}
}
코드명("배달비", "가상계좌" 등...)만 or 코드번호(01, 02 등...)가 if문으로 구현되었을 때,
이것들만 봐서는 해당 데이터가 무엇을 나타내는지 정확히 알 수 없다.
→ 따라서, 서버코드에서 실행되는 코드는 확인하고, 이를 DB 에서 조회해야한다.
→ 문서가 업데이트 됐는지 확신할 수 없기에, DB 에서 또다시 조회해야한다.
→ 이런 방시은 항상 '테이블 조회 쿼리'가 실행되었어야만 한다.
카테고리 코드를 기반으로 한 서비스 로직 추가 시, 위치의 모호성
→ 해당 코드에 따라 수행 할 기능이 있을 경우, 메소드의 위치는 Service 또는 Utility Class ?
카테고리 코드의 추가/수정은 그리 자주 일어나는 일이 아니므로, 굳이 테이블로 카테고리를 관리한다는 것은 비효율적
Enum 인스턴스 생성을 위한 interface 생성(클래스 선언)
public interface EnumMapperType {
String getCode(); // 해당 Enum의 이름을 조회하는 변수 → DB 의 컬럼값으로 사용
String getTitle(); // 해당 Enum의 설명을 조회하는 변수
}
모든 Enum 데이터들이 공통으로 갖는 데이터
interface 를 구현(implements)
@RequiredArgsConstructor
poublic enum FeeType implements EnumMapperType {
// PERCENT, MONEY 는 code 에 해당 → 아래의 getCode() 통해 조회 가능
// 정율, 정액은 title 에 해당
PERCENT("정율"),
MONEY("정액");
@Getter
private final Stirng title; // Enum 의 변수들은 불변이므로, final 키워드를 붙여줄 수 있다
FeeType(String title) {
this.title = title;
}
@Override
public String getCode() {
return name();
}
@Override
public String getTitle() {
return title();
}
}
interface 를 인자로 받아서, 인스턴스를 생성
public class EnumMapperValue {
private String code;
private String title;
// interface 를 인자로 받음
public EnumMapperValue (EnumMapperType enumMapperType) {
code = enumMapperType.getCode();
title = enumMapperType.getTitle();
}
public String getCode() {
return code;
}
public String getTitle();
return title;
}
@Override
public Stirng toString() {
return "{" + "code='" + code + '\'' + ", title='" + title + '\'' + '}';
}
}
EnumMapperValue 는 EnumMapperType을 구현한(implements) 구현체에 대해 실제 값을 갖는다.
Enum 을 Value 클래스로 변환한 후, 전달
@GetMapping("/no-bean-categories")
pbulci List<EnumMapperValue> getNoBeanCategories() {
return Arrays.stream(FeeType.values())
.map(EnumMapperValue::new)
.collect(Collectors.toList());
}
JSON 으로 출력된 결과
[
{
"code": "PERCENT",
"titel": "정율"
},
{
"code": "MONEY",
"titel": "정액"
}
]
CodeVO 테이블 + 조회
@Entity
@Table("codeVO")
@Getter
@NoArgsConstructor
public class CodeVO extends CommonVO implements Serializable {
private String codeSn; // 코드일련번호
@Setter
private String lvl1; // 레벨1코드
@Setter
private String lvl2; // 레벨2코드
private String codeName; // 코드한글명
private String codeDesc; // 코드설명
@Setter
private String selType; // 조회유형
@Builder
public CodeVO(String lvl1, String selType){
this.lvl1 = lvl1;
this.selType = selType;
}
}
상수와 관련된 코드들을 별도의 테이블로 만들어서 관리한다.
BoardVO 테이블 + 조회
public class BoardVO extends CodeVO implements Serializable {
private String title; // 제목
private String contents; // 내용
private String status; // 상태
}
BoardController 로 조회하기
@RestController
@RequestMapping("/board")
@Log4j2
public class BoardController {
@Resource(name = "boardService")
private BoardService boardService;
@GetMapping(value = "/list")
public ResponseEntity<List<BoardVO>> list() {
BoardVO boardVO = new BoardVO();
boardVO.setLvl1("001");
boardVO.setLvl2("002");
List<BoardVO> boardList = boardService.findAll(boardVO);
return new ResponseEntity.ok(boardList);
}
}
모든 Enum 데이터들이 공통으로 갖는 데이터(인터페이스)
public interface EnumMapperType {
String getCode(); // 해당 Enum의 이름을 조회하는 변수
String getTitle(); // 해당 Enum의 설명을 조회하는 변수
}
interface 를 구현
@RequiredArgsConstructor
public enum Status implements EnumMapperType {
// PROCEEDING, COMPLETE 는 code 에 해당
// "진행중", "진행완료" 는 title 에 해당
PROCEEDING("진행중"),
COMPLETE("진행완료");
// Enum의 변수들은 불변이기 때문에 final 키워드를 붙여줄 수 있다
@Getter
private final String title;
// getCode()를 통해 위의 code 를 조회할 수 있다
@Override
public String getCode() {
return name();
}
}
Enum 종류들을 관리하기 위한 EnumMapperFactory
@Getter
@AllArgsConstructor
public class EnumMapperFactory {
// 다양한 종류의 Enum을 생성 및 관리하는 factory
private Map<String, List<EnumMapperValue>> factory;
// 새로운 Enum 종류를 추가하는 함수
public void put(String key, Class<? extends EnumMapperType> e) {
factory.put(key, toEnumValues(e));
}
// 특정 Enum의 항목들을 조회하는 함수
public List<EnumMapperValue> get(String key) {
return factory.get(key);
}
// Enum의 내용들을 List로 바꾸어주는 함수
// toEnumValues 함수 : Enum 타입을 Enum의 Code와 Title을 변수로 갖는 EnumMapperValue 로 변환시켜줌
private List<EnumMapperValue> toEnumValues(Class<? extends EnumMapperType> e) {
return Arrays.stream(e.getEnumConstants()).map(EnumMapperValue::new)
.collect(Collectors.toList());
}
}
EnumMapperValue
@Getter
public class EnumMapperValue {
private String code;
private String title;
public EnumMapperValue(EnumMapperType enumMapperType) {
code = enumMapperType.getCode();
title = enumMapperType.getTitle();
}
}
EnumMapperType을 implements한 구현체에 대해 실제 값을 갖는다.
Enum Status 를 EnumMapperFactory 에 등록
@Configuration
public class EnumMapper {
@Bean
public EnumMapperFactory createEnumMapperFactory() {
EnumMapperFactory enumMapperFactory = new EnumMapperFactory(new LinkedHashMap<>());
enumMapperFactory.put("Status", Status.class);
return enumMapperFactory;
}
}
BoardVO 테이블 + 조회
public class BoardVO extends CodeVO implements Serializable {
// 수정 전
private String title; // 제목
private String contents; // 내용
private String status; // 상태
// 수정 후
private String title; // 제목
private String contents; // 내용
@Column(nullable = false, length = 10)
@Enumerated(EnumType.STRING) // Enum의 Code가 DB에 저장되도록 설정
private Status status; // 상태
}
DB 에 insert 했을 때
→ Query 속도↑ 가동성↑
프론트 쪽으로 상태를 전달해주려면?
@ReqruiedArgsConstructor
@RestController
public class EnumsController {
private final EnumMapperFactory enumMapperFactory;
@GetMapping("/status")
public ResponseEntity status(){
return ResponseEntity.ok(enumMapperFactory.get("Status"));
}
}
origin 테이블에 있는 내용을 table1 테이블, table2 테이블에 등록
public class LegacyCase {
public String toTable1Value (String originValue) {
if ("Y".equals(originValue)) {
return "1"
} else {
return "0";
}
}
public boolean toTable2Value (String originValue) {
if ("Y".equals(originValue)) {
return true;
} else {
return false;
}
}
}
여기서 문제가 발생한다.
"Y", "1", true 는 모두 같은 의미
→ Y 가 "1" 이 될 수도 있고, true 가 될 수도 있다.
→ 이를 확인하기 위해서는 항상 위에서 선언된 클래스와 메소드를 찾아야만 힌다.
불필요한 코드량 多
→ (Y, N 외에) R, S 등...의 추가 값이 필요한 경우, if문을 포함한 메소드 단위로 코드가 증가된다.
→ 동일한 타입의 값이 추가되는것에 비해, 너무 많은 반복성 코드가 발생
위의 코드를 Enum 으로 구현
public enum TableStatus {
Y ("1", true), // "Y", "1", true 를 한 묶음으로
N ("0", false); // "N", "0", false 를 한 묶음으로
private String table1Value;
private boolean table2Value;
TableStatus (String table1Value, boolean table2Value) {
this.table1Value = table1Value;
this.table2Value = table2Value;
}
public String getTable1Value() { // @Getter 을 사용하면, 더 깔끔한 코드가 된다.
return table1Value;
}
public boolean isTable2Vaule() {
return table2Value;
}
}
TableStatus 의 데이터를 전달받는 곳
@Test
public void origin테이블에서_조회한_데이터를_다른_2테이블에_등록한다() throws Exception {
TableStaus origin = selectFromOriginTable();
String table1Value = origin.getTable1Value();
boolean table2Value = origin.getTable2Value();
assertThat(origin, is(TableStaus.Y));
assertThat(table1Value, is("1"));
assertThat(table2Value, is(true));
}
계산식 설정
public class LegacyCalculator {
public static long calculate (String code, long originValue) {
if ("CALC_A".equals(code)) { // DB 에 저장된 code의 값이 "CALC_A"일 경우, 값 그대로 전달
return originValue;
} else if ("CALC_B".equals(code)) { // DB 에 저장된 code의 값이 "CALC_B"일 경우, * 10 한 값을 전달
return originValue * 10;
} else if ("CALC_C".equals(code)) { // DB 에 저장된 code의 값이 "CALC_C"일 경우, * 3 한 값을 전달
return originValue * 3;
} else {
return 0;
}
}
메소드 호출하기
@Test
public void 코드에_따라_서로다른_계산하기_기존방식() throws Exception {
// 코드는 코드대로 조회
String code = selectCode();
// 계산은 메소드를 통해 코드와는 별개로 진행
logn originValue = 10000L;
long result = LegacyCalculator.calculate(code, originValue);
assertThat(result, is(10000L));
}
LegacyCalculator 의 메소드인 calculate() 와 code 가 서로 관계있다는 것을 표현 할 수 없다.
계산 메소드를 만들어놓은 것을 잊어버리고, 동일한 기능의 메소드를 중복 생성하는 경우 발생
위의 코드를 Enum 으로 구현
public enum CalculatorType {
CALC_A (value -> value),
CALC_B (value -> value * 10),
CALC_C (value -> value * 3),
CALC_ETC (value -> 0L),
private Function<Long, Long> expression;
CalculatorType(Function<Long, Long> expression) {
this.expression = expression;
}
public long calculate (lone value) {
return expression.apply(value);
}
}
Enum 을 Entity 클래스에 선언할 경우
@Column
@Enumerated(EnumType.STRING) // Enum 의 name 인 'CALC_A', 'CALC_B', 'CALC_C', 'CALC_ETC' 이 저장된다
private CalculatorType calculatorType;
메소드 호출하기
@Test
public void 코드에_따라_서로다른_계산하기_변경된방식() throws Exception {
CalculatorType code = selectType();
// 계산을 코드에게 직접 요청
logn originValue = 10000L;
long result = code.calculate(originValue);
assertThat(result, is(10000L));
}
결제 종류 & 결제 수단
public class LegacyPayGroup {
public static String getPayGroup(String PayCode) {
if ("ACCOUNT TRANSFER".equals(payCode) || "REMITTANCE".equals(payCode) || "ONE_SITE_PAYMENT".equals(payCode) || "TOSS".equals(payCode)) {
return "CASH";
} else if ("PAYCO".equals(payCode) || "CARD".equals(payCode) || "KAKAO_PAY".equals(payCode) || "BAEMIN_PAY".equals(payCode)) {
return "CARD";
} else if ("POINT".equals(payCode) || "COUPON".equals(payCode)) {
return "ETC";
} else {
return "EMPTY";
}
}
메소드 구현
// PayGroup 을 기준으로 수행되는 메소드가 추가될 때마다, 이런 코드는 계속 늘어나게 된다.
// PayGroup 메소드 1
public void pushByPayGroup(final String payGroupCode) {
if ("CASH".equals(payGroupCode)) {
pushCashMethod();
} else if ("CARD".equals(payGroupCode)) {
pushCardMethod();
} else if ("ETC".equals(payGroupCode)) {
pushEtcMethod();
} else {
throw new RuntimeException("payGroupCode가 없습니다.");
}
}
// PayGroup 메소드 2
public void printByPayGroup(final String payGroupCode) {
if ("CASH".equals(payGroupCode)) {
doCashMethod();
} else if ("CARD".equals(payGroupCode)) {
doCardMethod();
} else if ("ETC".equals(payGroupCode)) {
doEtcMethod();
} else {
throw new RuntimeException("payGroupCode가 없습니다.");
}
}
결제가 이루어지면, 해당 '결제' 가 어떤 결제 종류/수단인지 확인 할 수 있어야 한다.
→ 결제 종류가 결제 수단을 포함하는 관계를 보여야하나, 위의 코드에서 사용된 메소드만으로는 표현이 어렵다.
결제의 결과를 주고받을 때, 결제의 종류로 지정된 값만 받도록 검증 코드가 필요해진다.
그룹별 기능 추가가 어렵다.
(결제 종류에 따라, 추가 기능이 필요할 경우...)
결제 종류를 Enum 으로 구현
public enum PayGroup {
// PayGroup 의 Enum 상수들
CASH("현급", Arrays.asList("ACCOUNT_TRANSFER", "REMITTANCE", "ONE_SITE_PAYMENT", "TOSS")),
CARD("카드", Arrays.asList("PAYCO", "CARD", "KAKAO_PAY", "BAEMIN_PAY")),
ETC("기타", Arrays.asList("POINT", "COUPON")),
EMPTY("없음", Collections.EMPTY_LIST);
private String title;
private List<String> payList;
PayGroup(String title, List<String> payList) {
this.title = title;
this.payList = payList;
}
// 확인하기 1
public static PayGroup findByPayCode(String code) {
return Arrays.stream(PayGroup.values()) // PayGroup 의 Enum 상수들을 순회하며
.filter(payGroup -> payGroup.hasPayCode(code)) // payCode 를 갖고 있는 게 있는지 확인
.findAny()
.orElse(EMPTY);
}
// 확인하기 2
public boolean hasPayCode(String code) {
return payList.stream()
.anyMatch(pay -> pay.equals(code));
}
public String getTitle() {
return title;
}
}
메소드 호출하기
@Test
public void PayGroup에게_직접_결제종류_물어보기_문자열() throws Exception {
String payCode = selectPayCode();
PayGroup payGroup = PayGroup.findByPayCode(payCode);
assertThat(payGroup.name(), is("BAEMIN_PAY));
assertThat(payGroup.getTitle(), is("배민페이));
}
결제 수단을 Enum 으로 구현
public enum PayGroupAdvanced {
// PayGroup 의 Enum 상수들
CASH("현급", Arrays.asList("ACCOUNT_TRANSFER", "REMITTANCE", "ONE_SITE_PAYMENT", "TOSS")),
CARD("카드", Arrays.asList("PAYCO", "CARD", "KAKAO_PAY", "BAEMIN_PAY")),
ETC("기타", Arrays.asList("POINT", "COUPON")),
EMPTY("없음", Collections.EMPTY_LIST);
private String title;
private List<String> payList;
PayGroupAdvanced(String title, List<String> payList) {
this.title = title;
this.payList = payList;
}
// 확인하기 1
public static PayGroupAdvanced findByPayType(String code) {
return Arrays.stream(PayGroupAdvanced.values()) // PayGroup 의 Enum 상수들을 순회하며
.filter(payGroup -> payGroup.hasPayCode(code)) // payCode 를 갖고 있는 게 있는지 확인
.findAny()
.orElse(EMPTY);
}
// 확인하기 2
public boolean hasPayCode(PayType payType) {
return payList.stream()
.anyMatch(pay -> pay == payType);
}
public String getTitle() {
return title;
}
}
public enum PayType {
ACCOUNT_TRANSFER("계좌이체"),
REMITTANCE("무통장입금"),
ONE_SITE_PAYMENT("현장결제"),
TOSS("토스"),
PAYCO("페이코"),
CARD("신용카드"),
KAKAO_PAY("카카오페이"),
BAEMIN_PAY("배민페이"),
POINT("포인트"),
COUPON("쿠폰"),
EMPTY("없음");
private Stirng title;
PayType(Stirng title) {
this.title = title;
public Stirng getTitle() {
return title;
}
}
메소드 호출하기
@Test
public void PayGroup에게_직접_결제종류_물어보기_PayType() throws Exception {
PayType payType = selectPayType();
PayGroupAdvanced payGroupAdvanced = PayGroupAdvanced.findByPayType(payType);
assertThat(payGroupAdvanced.name(), is("BAEMIN_PAY));
assertThat(payGroupAdvanced.getTitle(), is("배민페이));
}
int year = now.get(Canlendar.YEAR); // 연
int month = now.get(Canlendar.MONTH); // 월(1~12)
int day = now.get(Canlendar.DAY_OF_MONTH); // 일
int week = now.get(Canlendar.DAY_OF_WEEK); // 요일(1~7)
int hour = now.get(Canlendar.HOUR); // 시간
int minute = now.get(Canlendar.MINUTE); // 분
int second = now.get(Canlendar.SECOND); // 초
public static void main(String[] args) {
Week today = null; // 열거 타입 변수를 선언
Canlendar cal = Calendar.getInstance(); // 오늘의 요일을 구한다.
int week = cal.get(Calendar.DAY_OF_WEEK); // 일요일~토요일(일주일)
// 열거 타입 변수 today에 해당 열거 상수(요일)를 대입
switch(week) {
case 1:
today = Week.SUNDAY;
break;
case 2:
today = Week.MONDAY;
break;
.
.
.
case 7:
today = Week.SATURDAY;
break;
}
System.out.println("오늘 요일: " + today);
// switch 문에서 얻은 요일을 바탕으로, if 문 실행
if (today == Week.SUNDAY) {
System.out.println("일요일에는 축구를 합니다.");
} else {
System.out.println("열심히 자바 공부합니다.");
}
}
참고: Java Enum 활용기
참고: Enum 클래스
참고: Java Enum 1편 : Enum 기본적인 사용
참고: Java enum의 사용
참고: Java Enum 2편 : 여러가지 활용법
참고: 상품 카테고리 Enum으로 관리
참고: [Java] Enum 사용법 - 고급(Enum 응용하기)