返回

3分钟速读原著-《Effective Java》(四)

见解分享

在编程中,我们经常会遇到一些重复性的代码,这些代码往往会使我们的程序难以阅读和维护。为了解决这个问题,我们可以使用一些设计模式来重构我们的代码,从而提高代码的可读性和可维护性。

在《Effective Java》一书中,作者Joshua Bloch提出了36条编程技巧,这些技巧可以帮助我们编写出更清晰、更易维护的Java代码。在本文中,我们将探讨Effective Java第四部分的编程技巧,包括使用实例域代替序数、使用EnumSet代替位域、使用EnumMap代替枚举当中的数组等。

使用实例域代替序数

在Java中,我们可以使用序数来表示枚举值。例如,我们可以使用以下代码来定义一个枚举类型:

public enum Color {
  RED,
  GREEN,
  BLUE
}

如果我们想要获取枚举值的序数,我们可以使用ordinal()方法。例如,我们可以使用以下代码来获取Color.RED的序数:

Color.RED.ordinal() // 0

但是,使用序数来表示枚举值并不是一个好习惯。因为序数是枚举值在枚举类型中的位置,它可能会随着枚举类型的改变而改变。例如,如果我们向Color枚举类型中添加了一个新的枚举值,那么Color.RED的序数就会从0变为1。

为了避免这种情况,我们可以使用实例域来表示枚举值。例如,我们可以使用以下代码来定义一个枚举类型:

public enum Color {
  RED(0),
  GREEN(1),
  BLUE(2);

  private final int value;

  private Color(int value) {
    this.value = value;
  }

  public int getValue() {
    return value;
  }
}

使用实例域来表示枚举值,可以保证枚举值的唯一性,不会随着枚举类型的改变而改变。

使用EnumSet代替位域

在Java中,我们可以使用位域来表示一组标志。例如,我们可以使用以下代码来定义一个位域:

public class Flags {
  public static final int RED = 1;
  public static final int GREEN = 2;
  public static final int BLUE = 4;
}

如果我们想要设置一个标志,我们可以使用以下代码:

int flags = Flags.RED | Flags.GREEN; // 3

如果我们想要检查一个标志是否被设置,我们可以使用以下代码:

(flags & Flags.RED) != 0 // true

但是,使用位域来表示一组标志并不是一个好习惯。因为位域是使用二进制位来表示的,它很难阅读和理解。例如,如果我们想要知道Flags.RED和Flags.GREEN的组合是什么,我们需要进行以下计算:

Flags.RED | Flags.GREEN // 3

为了避免这种情况,我们可以使用EnumSet来表示一组标志。例如,我们可以使用以下代码来定义一个EnumSet:

import java.util.EnumSet;

public class Flags {
  public static final EnumSet<Color> RED = EnumSet.of(Color.RED);
  public static final EnumSet<Color> GREEN = EnumSet.of(Color.GREEN);
  public static final EnumSet<Color> BLUE = EnumSet.of(Color.BLUE);
}

如果我们想要设置一个标志,我们可以使用以下代码:

EnumSet<Color> flags = EnumSet.of(Color.RED, Color.GREEN);

如果我们想要检查一个标志是否被设置,我们可以使用以下代码:

flags.contains(Color.RED) // true

使用EnumSet来表示一组标志,可以使我们的代码更加清晰和易于理解。

使用EnumMap代替枚举当中的数组

在Java中,我们可以使用枚举当中的数组来存储数据。例如,我们可以使用以下代码来定义一个枚举当中的数组:

public enum Color {
  RED,
  GREEN,
  BLUE;

  private String[] values = new String[3];

  public void setValue(int index, String value) {
    values[index] = value;
  }

  public String getValue(int index) {
    return values[index];
  }
}

如果我们想要设置一个值,我们可以使用以下代码:

Color.RED.setValue(0, "红色");

如果我们想要获取一个值,我们可以使用以下代码:

Color.RED.getValue(0) // "红色"

但是,使用枚举当中的数组来存储数据并不是一个好习惯。因为枚举当中的数组是静态的,它不能随着枚举类型的改变而改变。例如,如果我们向Color枚举类型中添加了一个新的枚举值,那么Color.RED的数组大小就会从3变为4。

为了避免这种情况,我们可以使用EnumMap来存储数据。例如,我们可以使用以下代码来定义一个EnumMap:

import java.util.EnumMap;

public class Color {
  private static final EnumMap<Color, String> values = new EnumMap<>(Color.class);

  public static void setValue(Color color, String value) {
    values.put(color, value);
  }

  public static String getValue(Color color) {
    return values.get(color);
  }
}

如果我们想要设置一个值,我们可以使用以下代码:

Color.setValue(Color.RED, "红色");

如果我们想要获取一个值,我们可以使用以下代码:

Color.getValue(Color.RED) // "红色"

使用EnumMap来存储数据,可以使我们的代码更加清晰和易于维护。

小结

在本文中,我们探讨了Effective Java第四部分的编程技巧,包括使用实例域代替序数、使用EnumSet代替位域、使用EnumMap代替枚举当中的数组等。这些技巧可以帮助我们编写出更清晰、更易维护的Java代码。