建议速读 | Java 常量定义的正确姿势!

简介: 在 Java 中,关于常量的话题似乎有很多困惑。有些人使用整数或字符串来定义常量,而另一些人则使用枚举。我还遇到了在其自己的接口中定义的常量,使用该常量的类必须实现该接口。这种策略通常称为接口常量设计模式。

在 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


目录
相关文章
|
4月前
|
存储 Java
Java学习笔记 List集合的定义、集合的遍历、迭代器的使用
Java学习笔记 List集合的定义、集合的遍历、迭代器的使用
|
29天前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
52 24
|
4月前
|
存储 缓存 Java
Java本地高性能缓存实践问题之如何定义Caffeine的缓存
Java本地高性能缓存实践问题之如何定义Caffeine的缓存
|
1月前
|
Java 编译器
Java重复定义变量详解
这段对话讨论了Java中变量作用域和重复定义的问题。学生提问为何不能重复定义变量导致编译错误,老师通过多个示例解释了编译器如何区分不同作用域内的变量,包括局部变量、成员变量和静态变量,并说明了使用`this`关键字和类名来区分变量的方法。最终,学生理解了编译器在逻辑层面检查变量定义的问题。
Java重复定义变量详解
|
1月前
|
Java 程序员 容器
Java中的变量和常量:数据的‘小盒子’和‘铁盒子’有啥不一样?
在Java中,变量是一个可以随时改变的数据容器,类似于一个可以反复打开的小盒子。定义变量时需指定数据类型和名称。例如:`int age = 25;` 表示定义一个整数类型的变量 `age`,初始值为25。 常量则是不可改变的数据容器,类似于一个锁死的铁盒子,定义时使用 `final` 关键字。例如:`final int MAX_SPEED = 120;` 表示定义一个名为 `MAX_SPEED` 的常量,值为120,且不能修改。 变量和常量的主要区别在于变量的数据可以随时修改,而常量的数据一旦确定就不能改变。常量主要用于防止意外修改、提高代码可读性和便于维护。
|
2月前
|
安全 Java
java BigDecimal 的赋值一个常量
在 Java 中,`BigDecimal` 是一个用于精确计算的类,特别适合处理需要高精度和小数点运算的场景。如果你需要给 `BigDecimal` 赋值一个常量,可以使用其静态方法 `valueOf` 或者直接通过字符串构造函数。 以下是几种常见的方法来给 `BigDecimal` 赋值一个常量: ### 使用 `BigDecimal.valueOf` 这是推荐的方式,因为它可以避免潜在的精度问题。 ```java import java.math.BigDecimal; public class BigDecimalExample { public static void
|
1月前
|
Java
在Java中定义一个不做事且没有参数的构造方法的作用
Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。
|
2月前
|
Oracle Java 关系型数据库
重新定义 Java 对象相等性
本文探讨了Java中的对象相等性问题,包括自反性、对称性、传递性和一致性等原则,并通过LaptopCharger类的例子展示了引用相等与内容相等的区别。文章还介绍了如何通过重写`equals`方法和使用`Comparator`接口来实现更复杂的相等度量,以满足特定的业务需求。
32 3
|
2月前
|
存储 Java 编译器
Java集合定义其泛型
Java集合定义其泛型
21 1
|
3月前
|
Java
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
java小工具util系列4:基础工具代码(Msg、PageResult、Response、常量、枚举)
94 5