βμ΄κ±° νμ μ μ μ μμλ³΄λ€ λ μ½κΈ° μ½κ³ μμ νκ³ κ°λ ₯νλ€β
public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;
public static final int ORANGE_NAVEL = 0;
public static final int ORANGE_TEMPLE = 1;
public static final int ORANGE_BLOOD = 2;
==
)λ‘ λΉκ΅νλλΌλ μ»΄νμΌλ¬λ μλ¬΄λ° κ²½κ³ λ©μμ§λ₯Ό μΆλ ₯νμ§ μμ.public enum Apple { FUJI, PIPPIN, GRANNY_SMITH }
public enum Orange { NEVEL, TEMPLE, BLOOD }
public static final
νλλ‘ κ³΅κ°ν¨.final
μ.final
μ΄μ΄μΌ ν¨.// λ°μ΄ν°μ λ©μλλ₯Ό κ°λ μ΄κ±° νμ
public enum Planet {
MERCURY(3.302e+23, 2.439e6),
VENUS (4.869e+24, 6.052e6),
EARTH (5.975e+24, 6.378e6),
MARS (6.419e+23, 3.393e6),
JUPITER(1.899e+27, 7.149e7),
SATURN (5.685e+26, 6.027e7),
URANUS (8.683e+25, 2.556e7),
NEPTUNE(1.024e+26, 2.477e7);
private final double mass; // μ§λ(λ¨μ: ν¬λ‘κ·Έλ¨)
private final double radius; // λ°μ§λ¦(λ¨μ: λ―Έν°)
private final double surfaceGravity; // νλ©΄μ€λ ₯(λ¨μ: m / s^2)
// μ€λ ₯μμ(λ¨μ: m^3 / kg s^2)
private static final double G = 6.67300E-11;
// μμ±μ
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
surfaceGravity = G * mass / (radius * radius);
}
public double mass() { return mass; }
public double radius() { return radius; }
public double surfaceGravity() { return surfaceGravity; }
public double surfaceWeight(double mass) {
return mass * surfaceGravity; // F = ma
}
}
apply
λΌλ μΆμ λ©μλλ₯Ό μ μΈνκ³ κ° μμλ³ ν΄λμ€ λͺΈμ²΄, μ¦ κ° μμμμ μμ μ λ§κ² μ¬μ μνμμ.// μμλ³ ν΄λμ€ λͺΈμ²΄(class body)μ λ°μ΄ν°λ₯Ό μ¬μ©ν μ΄κ±° νμ
public enum Operation {
PLUS("+") {
public double apply(double x, double y) { return x + y; }
},
MINUS("-") {
public double apply(double x, double y) { return x - y; }
},
TIMES("*") {
public double apply(double x, double y) { return x * y; }
},
DIVIDE("/") {
public double apply(double x, double y) { return x / y; }
};
private final String symbol;
Operation(String symbol) { this.symbol = symbol; }
@Override public String toString() { return symbol; }
public abstract double apply(double x, double y);
// μ½λ 34-7 μ΄κ±° νμ
μ© fromString λ©μλ ꡬννκΈ° (216μͺ½)
private static final Map<String, Operation> stringToEnum =
Stream.of(values()).collect(
toMap(Object::toString, e -> e));
// μ§μ ν λ¬Έμμ΄μ ν΄λΉνλ Operationμ (μ‘΄μ¬νλ€λ©΄) λ°ννλ€.
public static Optional<Operation> fromString(String symbol) {
return Optional.ofNullable(stringToEnum.get(symbol));
}
public static void main(String[] args) {
double x = Double.parseDouble(args[0]);
double y = Double.parseDouble(args[1]);
for (Operation op : Operation.values())
System.out.printf("%f %s %f = %f%n",
x, op, y, op.apply(x, y));
}
}
PayrollDay
μ΄κ±° νμ
μ μμ±μμμ μ μ ν μμ
μλΉ μ λ΅(PayType
)μ μ νPayrollDay
μ΄κ±° νμ
μ μμ
μλΉ κ³μ°μ κ·Έ μ λ΅ μ΄κ±° ν¨ν΄μ μμνμ¬, switch
λ¬Έμ΄λ μμλ³ λ©μλ ꡬνμμ΄ μμ νκ³ μ μ°νκ² μ€κ³.// μ λ΅ μ΄κ±° νμ
ν¨ν΄
enum PayrollDay {
MONDAY(WEEKDAY), TUESDAY(WEEKDAY), WEDNESDAY(WEEKDAY),
THURSDAY(WEEKDAY), FRIDAY(WEEKDAY),
SATURDAY(WEEKEND), SUNDAY(WEEKEND);
private final PayType payType;
PayrollDay(PayType payType) { this.payType = payType; }
int pay(int minutesWorked, int payRate) {
return payType.pay(minutesWorked, payRate);
}
// μ λ΅ μ΄κ±° νμ
enum PayType {
WEEKDAY {
int overtimePay(int minsWorked, int payRate) {
return minsWorked <= MINS_PER_SHIFT ? 0 :
(minsWorked - MINS_PER_SHIFT) * payRate / 2;
}
},
WEEKEND {
int overtimePay(int minsWorked, int payRate) {
return minsWorked * payRate / 2;
}
};
abstract int overtimePay(int mins, int payRate);
private static final int MINS_PER_SHIFT = 8 * 60;
int pay(int minsWorked, int payRate) {
int basePay = minsWorked * payRate;
return basePay + overtimePay(minsWorked, payRate);
}
}
public static void main(String[] args) {
for (PayrollDay day : values())
System.out.printf("%-10s%d%n", day, day.pay(8 * 60, 1));
}
}
values()
: μ μλ μμλ€μ κ°μ λ°°μ΄μ λ΄μ λ°ν.valueOf(String)
: μμ μ΄λ¦μ λ¬Έμμ΄λ‘ μ
λ ₯λ°μ κ·Έ μ΄λ¦μ ν΄λΉνλ μμλ₯Ό λ°νswitch
λ¬Έ λμ μμλ³ λ©μλ ꡬν μ¬μ©νκΈ°βμ΄κ±° νμ μμμ μ°κ²°λ κ°μ
ordinal
λ©μλλ‘ μ»μ§ λ§κ³ , μΈμ€ν΄μ€ νλμ μ μ₯νμβ
ordinal()
: ν΄λΉ μμκ° κ·Έ μ΄κ±° νμ
μμ λͺ λ²μ§Έ μμΉμΈμ§λ₯Ό λ°νnumberOfMusicians
κ° μ€λμνλ©°, μ΄λ―Έ μ¬μ© μ€μΈ μ μμ κ°μ΄ κ°μ μμλ μΆκ°ν λ°©λ²μ΄ μμ.public enum Ensemble {
SOLO, DUET, TRIO, QUARTET, QUINTET,
SEXTET, SEPTET, OCTET, NONET, DECTET;
public int numberOfMusicians() { return ordinal() + 1; }
}
β μΈμ€ν΄μ€ νλμ μ μ₯νλ©΄ μμ κ°μ λ¬Έμ λ€μ΄ λ§λν ν΄κ²°λ¨
// μΈμ€ν΄μ€ νλμ μ μ λ°μ΄ν°λ₯Ό μ μ₯νλ μ΄κ±° νμ
public enum Ensemble {
SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5),
SEXTET(6), SEPTET(7), OCTET(8), DOUBLE_QUARTET(8),
NONET(9), DECTET(10), TRIPLE_QUARTET(12);
private final int numberOfMusicians;
Ensemble(int size) { this.numberOfMusicians = size; }
public int numberOfMusicians() { return numberOfMusicians; }
}
β
EnumSet
ν΄λμ€ : λΉνΈ νλ μμ€μ λͺ λ£ν¨κ³Ό μ±λ₯ + μ΄κ±° νμ μ μ₯μ β
text.applyStyles(STYLE_BOLD | STYLE_ITALIC);
μ²λΌ μ¬μ©.public class Text {
public static final int STYLE_BOLD = 1 << 0; // 1
public static final int STYLE_ITALIC = 1 << 1; // 2
public static final int STYLE_UNDERLINE = 1 << 2; // 4
public static final int STYLE_STRIKETHROUGH = 1 << 3; // 8
// 맀κ°λ³μ stylesλ 0κ° μ΄μμ STYLE_ μμλ₯Ό λΉνΈλ³ ORν κ°μ΄λ€.
public void applyStyles(int styles) { ... }
}
int
or long
)μ μ νν΄μΌ ν¨.β μ΄κ±° νμ
μμμ κ°μΌλ‘ ꡬμ±λ μ§ν©μ ν¨κ³Όμ μΌλ‘ ννν΄μ£Όλ EnumSet
μ μ¬μ©νμ.
EnumSet
μ¬μ© μμ// EnumSet - λΉνΈ νλλ₯Ό λ체νλ νλμ κΈ°λ²
public class Text {
public enum Style {BOLD, ITALIC, UNDERLINE, STRIKETHROUGH}
// μ΄λ€ Setμ λ겨λ λλ, EnumSetμ΄ κ°μ₯ μ’λ€.
public void applyStyles(Set<Style> styles) {
System.out.printf("Applying styles %s to text%n",
Objects.requireNonNull(styles));
}
// μ¬μ© μ
public static void main(String[] args) {
Text text = new Text();
text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
}
}
EnumSet
Set
μΈν°νμ΄μ€λ₯Ό μλ²½ν ꡬννλ©°, νμ
μμ removeAll
κ³Ό retainAll
κ³Ό κ°μ λλ μμ
μ λΉνΈλ₯Ό ν¨μ¨μ μΌλ‘ μ²λ¦¬ν μ μλ μ°μ μ°μ°μ μ¨μ ꡬννμμβλ°°μ΄μ μΈλ±μ€λ₯Ό μ»κΈ° μν΄ ordinalμ μ°λ κ²μ μΌλ°μ μΌλ‘ μ’μ§ μμΌλ, λμ
EnumMap
μ μ¬μ©νλΌβ
// μλ¬Όμ μμ£Ό λ¨μνκ² ννν ν΄λμ€ (226μͺ½)
class Plant {
enum LifeCycle { ANNUAL, PERENNIAL, BIENNIAL }
final String name;
final LifeCycle lifeCycle;
Plant(String name, LifeCycle lifeCycle) {
this.name = name;
this.lifeCycle = lifeCycle;
}
@Override public String toString() {
return name;
}
}
ordinal()
μ λ°°μ΄ μΈλ±μ€λ‘ μ¬μ©νλ μμ// ordinal()μ λ°°μ΄ μΈλ±μ€λ‘ μ¬μ© - λ°λΌ νμ§ λ§ κ²!
Set<Plant>[] plantsByLifeCycleArr =
(Set<Plant>[]) new Set[Plant.LifeCycle.values().length];
for (int i = 0; i < plantsByLifeCycleArr.length; i++)
plantsByLifeCycleArr[i] = new HashSet<>();
for (Plant p : garden)
plantsByLifeCycleArr[p.lifeCycle.ordinal()].add(p);
// κ²°κ³Ό μΆλ ₯
for (int i = 0; i < plantsByLifeCycleArr.length; i++) {
System.out.printf("%s: %s%n",
Plant.LifeCycle.values()[i], plantsByLifeCycleArr[i]);
}
ArrayIndexOutOfBoundsException
μ λμ§ κ²μ.EnumMap
μ μ¬μ©νλ μμMap<Plant.LifeCycle, Set<Plant>> plantsByLifeCycle =
new EnumMap<>(Plant.LifeCycle.class);
for (Plant.LifeCycle lc : Plant.LifeCycle.values())
plantsByLifeCycle.put(lc, new HashSet<>());
for (Plant p : garden)
plantsByLifeCycle.get(p.lifeCycle).add(p);
System.out.println(plantsByLifeCycle);
ordinal()
μΈλ±μ± λ²μ κ³Ό λμΌν¨.EnumMap
λ΄λΆμμ λ°°μ΄μ μ¬μ©νκΈ° λλ¬Έμ μ±λ₯μ΄ λμΌν¨.EnumMap<..., EnumMap<..>>
μΌλ‘ ννν΄μ μ¬μ©. // μ€μ²© EnumMapμΌλ‘ λ°μ΄ν°μ μ΄κ±° νμ
μμ μ°κ²°νλ€
public enum Phase {
SOLID, LIQUID, GAS;
public enum Transition {
MELT(SOLID, LIQUID), FREEZE(LIQUID, SOLID),
BOIL(LIQUID, GAS), CONDENSE(GAS, LIQUID),
SUBLIME(SOLID, GAS), DEPOSIT(GAS, SOLID);
private final Phase from;
private final Phase to;
Transition(Phase from, Phase to) {
this.from = from;
this.to = to;
}
// μμ μ΄ λ§΅μ μ΄κΈ°ννλ€.
private static final Map<Phase, Map<Phase, Transition>>
m = Stream.of(values()).collect(groupingBy(t -> t.from,
() -> new EnumMap<>(Phase.class),
toMap(t -> t.to, t -> t,
(x, y) -> y, () -> new EnumMap<>(Phase.class))));
public static Transition from(Phase from, Phase to) {
return m.get(from).get(to);
}
}
// κ°λ¨ν λ°λͺ¨ νλ‘κ·Έλ¨ - κΉλνμ§ λͺ»ν νλ₯Ό μΆλ ₯νλ€.
public static void main(String[] args) {
for (Phase src : Phase.values()) {
for (Phase dst : Phase.values()) {
Transition transition = Transition.from(src, dst);
if (transition != null)
System.out.printf("%sμμ %sλ‘ : %s %n", src, dst, transition);
}
}
}
}
βμ΄κ±° νμ μ체λ νμ₯ν μ μμ§λ§, μΈν°νμ΄μ€μ κ·Έ μΈν°νμ΄μ€λ₯Ό ꡬννλ κΈ°λ³Έ μ΄κ±° νμ μ μ¬μ©ν΄ κ°μ ν¨κ³Όλ₯Ό λΌ μ μμβ
public interface Operation {
double apply(double x, double y);
}
public enum ExtendedOperation implements Operation {
EXP("^") {
public double apply(double x, double y) {
return Math.pow(x, y);
}
},
REMAINDER("%") {
public double apply(double x, double y) {
return x % y;
}
};
private final String symbol;
ExtendedOperation(String symbol) {
this.symbol = symbol;
}
@Override public String toString() {
return symbol;
}
// 컬λ μ
μΈμ€ν΄μ€λ₯Ό μ΄μ©ν΄ νμ₯λ μ΄κ±° νμ
μ λͺ¨λ μμλ₯Ό μ¬μ©νλ μ (235μͺ½)
public static void main(String[] args) {
double x = Double.parseDouble(args[0]);
double y = Double.parseDouble(args[1]);
test(Arrays.asList(ExtendedOperation.values()), x, y);
}
private static void test(Collection<? extends Operation> opSet,
double x, double y) {
for (Operation op : opSet)
System.out.printf("%f %s %f = %f%n",
x, op, y, op.apply(x, y));
}
}
for (Operation op : opSet)
μ²λΌ.βμ΄λ Έν μ΄μ μΌλ‘ ν μ μλ μΌμ λͺ λͺ ν¨ν΄μΌλ‘ μ²λ¦¬ν μ΄μ κ° μλ€β
test
λ‘ μμνκ²λ νμ.tsetSafetyOverride
λ‘ μ§μΌλ©΄ JUnit3μ μ΄ λ©μλλ₯Ό 무μνκ³ μ§λμΉ¨TestSafetyMechanisms
λ‘ μ§μ΄ JUnitμ λμ Έμ€¬λ€κ³ ν΄λ³΄μ. κ°λ°μλ μ΄ ν΄λμ€μ μ μλ ν
μ€νΈ λ©μλλ€μ μνν΄μ£ΌκΈΈ κΈ°λνκ² μ§λ§ JUnitμ ν΄λμ€ μ΄λ¦μλ κ΄μ¬μ΄ μμ@Retention(RetentionPolicy.RUNTIME)
: μ΄λ
Έν
μ΄μ
μ΄ λ°νμμλ μ μ§λμ΄μΌ νλ€λ νμ@Target(ElementType.METHOD)
: μ΄λ
Έν
μ΄μ
μ΄ λ©μλ μ μΈμμλ§ μ¬μ©λμ΄μΌ νλ€λ νμ/**
* ν
μ€νΈ λ©μλμμ μ μΈνλ μ λν
μ΄μ
μ΄λ€.
* 맀κ°λ³μ μλ μ μ λ©μλ μ μ©μ΄λ€.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
}
javax.annotation.processing
API λ¬Έμ μ°Έκ³ .// λ§μ»€ μ λν
μ΄μ
μ μ¬μ©ν νλ‘κ·Έλ¨ μ
public class Sample {
@Test
public static void m1() { } // μ±κ³΅ν΄μΌ νλ€.
public static void m2() { }
@Test public static void m3() { // μ€ν¨ν΄μΌ νλ€.
throw new RuntimeException("μ€ν¨");
}
public static void m4() { } // ν
μ€νΈκ° μλλ€.
@Test public void m5() { } // μλͺ» μ¬μ©ν μ: μ μ λ©μλκ° μλλ€.
public static void m6() { }
@Test public static void m7() { // μ€ν¨ν΄μΌ νλ€.
throw new RuntimeException("μ€ν¨");
}
public static void m8() { }
}
Class<? extends Throwable>
: Throwable
μ νμ₯ν ν΄λμ€μ Class
κ°μ²΄./**
* λͺ
μν μμΈλ₯Ό λμ ΈμΌλ§ μ±κ³΅νλ ν
μ€νΈ λ©μλμ© μ λν
μ΄μ
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
Class<? extends Throwable> value();
}
// 맀κ°λ³μ νλμ§λ¦¬ μ λν
μ΄μ
μ μ¬μ©ν νλ‘κ·Έλ¨
public class Sample2 {
@ExceptionTest(ArithmeticException.class)
public static void m1() { // μ±κ³΅ν΄μΌ νλ€.
int i = 0;
i = i / i;
}
@ExceptionTest(ArithmeticException.class)
public static void m2() { // μ€ν¨ν΄μΌ νλ€. (λ€λ₯Έ μμΈ λ°μ)
int[] a = new int[0];
int i = a[1];
}
@ExceptionTest(ArithmeticException.class)
public static void m3() { } // μ€ν¨ν΄μΌ νλ€. (μμΈκ° λ°μνμ§ μμ)
}
// λ°°μ΄ λ§€κ°λ³μλ₯Ό λ°λ μ λν
μ΄μ
νμ
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
Class<? extends Exception>[] value();
}
// λ°°μ΄ λ§€κ°λ³μλ₯Ό λ°λ μ λν
μ΄μ
μ μ¬μ©νλ νλ‘κ·Έλ¨
public class Sample3 {
// μ΄ λ³νμ μμ νλμ§λ¦¬ 맀κ°λ³μλ₯Ό λ°λ μ λν
μ΄μ
λ μ²λ¦¬ν μ μλ€
@ExceptionTest(ArithmeticException.class)
public static void m1() { // μ±κ³΅ν΄μΌ νλ€.
int i = 0;
i = i / i;
}
@ExceptionTest(ArithmeticException.class)
public static void m2() { // μ€ν¨ν΄μΌ νλ€. (λ€λ₯Έ μμΈ λ°μ)
int[] a = new int[0];
int i = a[1];
}
@ExceptionTest(ArithmeticException.class)
public static void m3() { } // μ€ν¨ν΄μΌ νλ€. (μμΈκ° λ°μνμ§ μμ)
// λ°°μ΄ λ§€κ°λ³μλ₯Ό λ°λ μ λν
μ΄μ
μ μ¬μ©νλ μ½λ
@ExceptionTest({ IndexOutOfBoundsException.class,
NullPointerException.class })
public static void doublyBad() { // μ±κ³΅ν΄μΌ νλ€.
List<String> list = new ArrayList<>();
// μλ° API λͺ
μΈμ λ°λ₯΄λ©΄ λ€μ λ©μλλ IndexOutOfBoundsExceptionμ΄λ
// NullPointerExceptionμ λμ§ μ μλ€.
list.addAll(5, null);
}
}
@Repeatable
λ©ν μ΄λ
Έν
μ΄μ
μ λ¬λ©΄ λ¨@Repeatable
μ΄λ
Έν
μ΄μ
μ 맀κ°λ³μλ‘ β컨ν
μ΄λ μ΄λ
Έν
μ΄μ
βμ μ λ¬ν΄μΌ ν¨.value
λ©μλλ₯Ό μ μ ν΄μΌν¨// λ°λ³΅ κ°λ₯ν μ λν
μ΄μ
μ 컨ν
μ΄λ μ λν
μ΄μ
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTestContainer {
ExceptionTest[] value();
}
// λ°λ³΅ κ°λ₯ν μ λν
μ΄μ
νμ
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(ExceptionTestContainer.class)
public @interface ExceptionTest {
Class<? extends Throwable> value();
}
// λ°λ³΅ κ°λ₯ν μ λν
μ΄μ
μ μ¬μ©ν νλ‘κ·Έλ¨
public class Sample4 {
// λ°λ³΅ κ°λ₯ μ λν
μ΄μ
μ λ λ² λ¨ μ½λ
@ExceptionTest(IndexOutOfBoundsException.class)
@ExceptionTest(NullPointerException.class)
public static void doublyBad() {
List<String> list = new ArrayList<>();
// μλ° API λͺ
μΈμ λ°λ₯΄λ©΄ λ€μ λ©μλλ IndexOutOfBoundsExceptionμ΄λ
// NullPointerExceptionμ λμ§ μ μλ€.
list.addAll(5, null);
}
}
βμμ ν΄λμ€μ λ©μλλ₯Ό μ¬μ μνλ €λ λͺ¨λ λ©μλμ
@Override
μ΄λ Έν μ΄μ μ λ¬μβ
@Override
μ΄λ
Έν
μ΄μ
μ μμμ μΌλ‘ λ¬λ©΄ μ€μνμ λ, μ»΄νμΌλ¬κ° μ μλ €μ€ κ²μβλ§μ»€ μΈν°νμ΄μ€μ λ§ν° μ΄λ Έν μ΄μ μ κ°μμ μ°μμ΄ μλ€.β
Serializable
μΈν°νμ΄μ€@Target
)μ ElementType.TYPE
μΌλ‘ μ μΈν μ΄λ
Έν
μ΄μ
μ λͺ¨λ νμ
(ν΄λμ€, μΈν°νμ΄μ€, μ΄κ±° νμ
, μ΄λ
Έν
μ΄μ
)μ λ¬ μ μμ. λΆμ°©ν μ μλ νμ
μ μΈλ°ν μ νν μ μμ.Element.TYPE
μΈ λ§μ»€ μ΄λ
Έν
μ΄μ
μ μμ±νκ³ μλ€λ©΄, λ§μ»€ μΈν°νμ΄μ€κ° λ«μ§λ μμμ§ κ³ λ―Όν΄λ³΄μ.