在 Java 中,关于常量的话题似乎有很多困惑。有些人使用整数或字符串来定义常量,而另一些人则使用枚举。我还遇到了在其自己的接口中定义的常量,使用该常量的类必须实现该接口。这种策略通常称为接口常量设计模式。
在这篇文章里,我会介绍在 Java 中存储常量的两种最常见的策略:整数和枚举。首先,无论何时决定使用常量,都应确保常量不会随时间变化,因此可以避免重新编译。
场景
我们选用一个非常常见的关于常量的例子:Weekday
。
假定我们在线商店中有一个代表订单 Order 的类,我们希望在其中跟踪订单在一周的哪一天发生。
我们的类看起来像这样:
public class Order { private [datatype] weekDay; public [datatype] getWeekDay() { return weekDay; } public void setWeekDay([datatype] weekDay) { this.weekDay = weekDay; }}
请注意,该类暂时无法编译,datatype
只是我们将要使用的常量类型的占位符。
用整数定义常量
在 Java 中定义常量的最常见方法之一是使用整数,其中整数变量使用 static final
修饰。
public static final int MONDAY = 0;public static final int TUESDAY = 1;public static final int WEDNESDAY = 2;public static final int THURSDAY = 3;public static final int FRIDAY = 4;public static final int SATURDAY = 5;public static final int SUNDAY = 6;
定义整数常量时,我们要考虑的第一个问题是将它们放在哪里。我们是否将它们直接放置在 Order 类中?还是我们将它们放在一个单独的类中。
由于 Weekday 不一定只应用到 Order 类型的对象中,因此我们在一个单独的类 Weekday 中定义它们。
public class WeekDay { private WeekDay() {} public static final int MONDAY = 0; public static final int TUESDAY = 1; public static final int WEDNESDAY = 2; public static final int THURSDAY = 3; public static final int FRIDAY = 4; public static final int SATURDAY = 5; public static final int SUNDAY = 6;}
你可能注意到了私有构造函数,这是为了避免客户端实例化该类。该类仅包含不与对象绑定的静态变量,因此无需实例化该类。
现在,每当需要为 Order 设置特定的日期时,我们可以这样操作:
Order order = new Order();order.setWeekDay(WeekDay.MONDAY);
当我们要检查订单是否在星期五发生时,我们可以简单地调用 getter 方法:
if (order.getWeekDay() == WeekDay.FRIDAY) {}
到目前为止,一切都很好。这种设计看起来似乎没有任何问题。
好吧,假设你在一年后再次回到此代码,并且你必须检查是否在星期一下了订单。你可能完全忘记了 Weekday 这个类(不排除这种可能)...
在这种情况下,你可以尝试如下操作:
if (order.getWeekDay() == 1) {}
完全忘记了 WeekDay 类,此代码非常合理。星期一是一周的第一天,所以工作日应该是 1,对吗?但是不,不是,因为在我们的 Weekday 类中静态 int 变量 Monday 被定义为 0!
这是为什么你应该考虑避免使用整数常量的一个很好的例子。它们容易出错,混乱并且难以调试。
用枚举定义常量
在 Java 中定义常量的另一种方法是使用枚举。
使用枚举时,常量类将如下所示:
public enum WeekDay { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY}
请注意,这里没有私有构造函数,你也无需强制该类是不可实例化的,因为默认情况下枚举是不可实例化的!
给 Order 设置 WeekDay 的语法与使用整数常量的语法完全相同:
order.setWeekDay(WeekDay.MONDAY);
我们是否可以在星期五处理订单方面也没有区别:
if (order.getWeekDay() == WeekDay.FRIDAY) {}
但是,主要区别在于:这是你可以在 Order 类中设置和比较 weekday 变量的值的唯一方法。
若你使用 order.setWeekDay(1);
和 if(order.getWeekDay()== 1)
,将使编译器抛出错误,因为当你尝试使用整型类型的变量时,它们应为 WeekDay 类型!
回想一下你完全忘记了 “WeekDay” 常量类的情况。对于枚举,这不再是问题!如果你尝试使用整数代替 WeekDay 枚举的成员,则编译器将简单地引发一个错误,告诉你需要使用 WeekDay 枚举。
换句话说,检查订单是否在星期五发生的唯一方式是:
if (order.getWeekDay() == WeekDay.FRIDAY) {}
你不再需要记住常数类,而且如果有任何客户端要使用你的代码,则不必怀疑星期一实际上是用 0 还是 1 表示。
我希望这个例子可以清楚地展示为什么在定义常量时应该考虑对整数使用枚举。枚举将使我们的代码不易出错,更易于阅读,并且更易于维护!
最后,推荐阅读《Effective Java 第3版[2019]》[1]这本好书。
引用链接
[1]
《Effective Java 第3版[2019]》: https://github.com/doocs/technical-books#backend
[2]
GitHub 技术社区 Doocs: https://github.com/doocs