在Java1.5版本中,引入了兩個型別:列舉型別enum type
和註解型別annotation type
。
Num1:用enum代替int常量
列舉型別enum type
是指由一組固定的常量組成合法值的型別。比如:
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; // In kilograms
private final double radius; // In meters
private final double surfaceGravity; // In m / s^2
// Universal gravitational constant in m^3 / kg s^2
private static final double G = 6.67300E-11;
// Constructor
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
}
}
public class WeightTable {
public static void main(String[] args) {
double earthWeight = Double.parseDouble(args[0]);
double mass = earthWeight / Planet.EARTH.surfaceGravity();
for (Planet p : Planet.values())
System.out.printf("Weight on %s is %f%n", p, p.surfaceWeight(mass));
}
}
Num2:用EnumSet代替位域
示例程式碼:
public class Text {
public enum Style {
BOLD, ITALIC, UNDERLINE, STRIKETHROUGH
}
// Any Set could be passed in, but EnumSet is clearly best
public void applyStyles(Set<Style> styles) {
// Body goes here
}
// Sample use
public static void main(String[] args) {
Text text = new Text();
text.applyStyles(EnumSet.of(Style.BOLD, Style.ITALIC));
}
}
總而言之,正是因為列舉型別要用在集合Set
中,所以沒有理由用位域來表示它。
Num3:註解優先於命名模式
命名模式有兩個缺點:
- 文字拼寫錯誤會導致失敗,且沒有任何提示。
- 無法確保它們只用於相應的程式元素上。
- 它們沒有提供將引數值與程式元素關聯起來的好方法。
針對以上幾個問題,註解很好地解決了所有這些問題。
/**
* Indicates that the annotated method is a test method. Use only on
* parameterless static methods.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
}
Test註解型別的宣告就是它自身通過Retention
和Target
註解進行了註解。註解型別宣告中的這張註解被稱作”元註解“meta-annotaition
。
那麼宣告的Test註解,則稱作為”標記註解”marker annotation
。因為它沒有引數,只是“標註”被註解的元素。
示例程式碼:
public class Sample {
@Test
public static void m1() {
} // Test should pass
public static void m2() {
}
@Test
public static void m3() { // Test Should fail
throw new RuntimeException("Boom");
}
public static void m4() {
}
@Test
public void m5() {
} // INVALID USE: nonstatic method
public static void m6() {
}
@Test
public static void m7() { // Test should fail
throw new RuntimeException("Crash");
}
public static void m8() {
}
}
另外一種註解方式:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
Class<? extends Exception>[] value();
}
使用方式
public class Sample2 {
@ExceptionTest(ArithmeticException.class)
public static void m1() { // Test should pass
int i = 0;
i = i / i;
}
@ExceptionTest(ArithmeticException.class)
public static void m2() { // Should fail (wrong exception)
int[] a = new int[0];
int i = a[1];
}
@ExceptionTest(ArithmeticException.class)
public static void m3() {
} // Should fail (no exception)
// Code containing an annotation with an array parameter - Page 174
@ExceptionTest({ IndexOutOfBoundsException.class,
NullPointerException.class })
public static void doublyBad() {
List<String> list = new ArrayList<String>();
// The spec permits this method to throw either
// IndexOutOfBoundsException or NullPointerException
list.addAll(5, null);
}
}