
내일배움캠프 31일차 TIL : Java - Enum 실무 활용, Lambda
예전에 다뤘었나...? 강의를 봤으니 복습을 할 겸 다시 ㄱㄱ
자바에서 Enum은 특정 값들의 집합을 나타내는 특별한 데이터 타입으로 열거형이라고도 부른다.
Enum 자체를 보면 말 그대로 단순히 데이터를 나타내지만 Java에서 다양하게 활용된다.
public int getResult(int type, int data) {
int result = 0;
if (type == 1) {
result = data - (data * 0.1);
}
else if (type == 2) {
result = data - 5000;
if (result < 0) {
result = 0;
}
}
return result;
}
이러한 코드를
private static final int DISCOUNT_TYPE_RATE = 1;
private static final int DISCOUNT_TYPE_PRICE = 2;
private static final int EDIT = 2;
private static final int DELETE = 2;
public int getResult(int type, int data) {
if (type == DISCOUNT_TYPE_RATE) {
return data - (data * 0.1);
}
else if (type == DISCOUNT_TYPE_PRICE) {
int result = data - 5000;
if (result < 0) {
result = 0;
}
return result;
}
}
/* 사용 */
getResult(-100, 40_000);
getResult(DISCOUNT_TYPE_PRICE, 40_000);
getResult(DELETE, 40_000);
이렇게 보기 편하게 사용할 수 있다.
다만 해당 코드에서는 몇가지 문제점이 발생되는데
상수로 RATE, PRICE를 정의했지만 매개변수의 정의가 int이므로 여기에는 -1, 100, 3 등 많은 값이 들어갈 수 있다.
위의 EDIT, DELETE를 보면 실수로 같은 값을 정의 했지만, 문법 오류가 전혀 없기 때문에 컴파일러는 이 오류를 잡아 낼 수 없다.
여기서 매개변수 type만 보면 어떤 type을 의미하는지 전혀 예상할 수 없기에 if문 안에 사용한 코드를 봐야만 의미를 유추할 수 있다.
자바 8 부터 Enum을 지원하게 되었는데 앞의 코드를 수정하게 되면
public enum DistcountType {
RATE, PRICE
}
public enum Method {
CREATE, EDIT, DELETE
}
public int getResult(DistcountType type, int price) {
if (DistcountType.RATE.eqauls(type)) {
return price - (price * 0.1);
}
else if (DistcountType.PRICE.eqauls(type)) {
int result = price - 5000;
if (result < 0) {
result = 0;
}
return result;
}
}
이렇게 수정할 수 있고 해당 코드의 장점은 위에서 봤던 문제점을 해결할 수 있다.
타입 안정성
getResult() 메소드의 매개변수 type은 DiscountType으로 제한므로 Method는 넣을 수 없다.
데이터 제약
DiscountType에 정의된 enum 값만 넘길 수 있으므로 예상하지 못 한 값이 넘어오지 않는다.
가독성
의미를 가지는 단어이므로 어디에 활용되는 값인지 유추할 수 있다.
lambda를 지원하기 전의 java는 값과 식 으로만 매개변수로 전달이 가능했다.
매개변수로 넘길 수 있는 값은 일급시민이며 일급시민의 조건은 다음과 같다.
여기는 코드로 설명하도록 하겠다.
public enum DiscountEvent {
NONE,
SUMMER,
WINTER,
BLACK_FRIDAY,
NEW_YEAR;
}
public class Coupon {
public int calcPrice(DiscountEvent event, int price) {
int benefit;
switch (event) {
case NONE -> benefit = price;
case SUMMER -> benefit = (int) (price * 0.1); // 10% 할인
case WINTER -> benefit = (int) (price * 0.2); // 20% 할인
case BLACK_FRIDAY -> benefit = (int) (price * 0.3); // 30% 할인
case NEW_YEAR -> benefit = (int) (price * 0.5); // 50% 할인
default -> benefit = 0;
}
return price + benefit;
}
}
public class Product {
/* 만약 상품에서도 동일한 할인율을 적용하려면 동일하게 계산해주는 코드가 필요하다 */
public int calcPrice(DiscountEvent event, int price) {
int discount;
switch (event) {
case NONE -> result = price;
case SUMMER -> result = (int) (price * 0.1); // 10% 할인
case WINTER -> result = (int) (price * 0.2); // 20% 할인
case BLACK_FRIDAY -> result = (int) (price * 0.3); // 30% 할인
case NEW_YEAR -> result = (int) (price * 0.5); // 50% 할인
default -> result = 0;
}
return price - discount;
}
}
위의 코드는 람다를 적용하지 않은 Enum을 활용하는 예제다
위의 예제를 보면 할인 이벤트와 할인율이 동일함에도 각각 구현을 해줘야 하는 문제가 발생한다.
이런 문제를 해소하기 위해 람다를 사용하여 할인 정책을 한 곳으로 모아두면 동일한 정책을 유지할 수 있고, 어떤 할인 정책을 가지는지 보기 편해진다.
public enum DiscountEvent {
NONE((price) -> price),
SUMMER((price) -> (int) (price * 0.1)),
WINTER((price) -> (int) (price * 0.2)),
BLACK_FRIDAY((price) -> (int) (price * 0.3)),
NEW_YEAR((price) -> (int) (price * 0.5));
private final Function<Integer, Integer> expression;
DiscountEvent(Function<Integer, Integer> expression) {
this.expression = expression;
}
public Integer calc(int price) {
return this.expression.apply(price);
}
}
public class Coupon {
private final String name;
private final int couponPrice;
public Coupon(String name, int couponPrice) {
this.name = name;
this.couponPrice = couponPrice;
}
public int calcPrice(DiscountEvent event, int price) {
return price + event.calc(price)
}
}
public class Product {
private final String name;
private final int price;
public Product(String name, int price) {
this.name = name;
this.price = price;
}
public int calcPrice(DiscountEvent event, int price) {
return price - event.calc(price);
}
}
이런식으로 Enum에 람다이든 다른 연관 데이터이든 연결을 시켜주게 되면 일관적인 데이터를 제공할 수 있게 된다.
장점을 정리해보면,