为什么Java类库仍然使用字符串常量而不是枚举?

9
我正在使用一些Java类,例如javax.Mail.SessionMessageDigest来构建一个工具。
我注意到由于它们使用String常量,所以分配属性很困难。
例如,对于一个Session对象,您必须在Property实例中分配String键值对,然后用它来创建一个Session。因此,如果您想要会话记录调试消息,请在Property实例中分配"smtp.mail.debug""true"。同样,如果您希望您的MessageDigest使用SHA,则可以将MessageDigest实例创建为MessageDigest.getInstance("SHA")
我还没有弄清楚如果我想使用MD5/RC4等实现MessageDigest,或者向我的Session对象添加另一个属性应该怎么做以及从哪里获取信息。
如果这些相应的类公开枚举以分配属性,那不是更好吗?
至少可以节省程序员很多搜索时间。

不!如果公共枚举由这些相应的类公开分配属性,那不是更好吗? - Unihedron
1
完全同意@Raymond的观点。我认为它只使用String作为常量,是因为[1]需要与在Enum存在之前开发的std库保持向后兼容性,[2]缺乏枚举使用强制执行和[3]唯一可以接受使用字符串的原因是,如果这些参数不能在编译时被发现。当你开始使用用|掩码的数字AWT常量时,情况甚至更糟。 - Leo
4
除非你能用理由支持自己的观点,否则不要提出意见。 - Rajan Prasad
1
有三个原因:向后兼容性、向后兼容性和向后兼容性。 - user207421
3个回答

11
我能看到两个主要原因: 向后兼容性 您给出的这两个示例已经是 Java 1.5 引入 enum 之前 API 的一部分了。还有许多类似的情况。 可扩展性MessageDigest 为例。javadoc 指定:

Java 平台的每个实现都需要支持以下标准 MessageDigest 算法:

• MD5
• SHA-1
• SHA-256

这使得其他 java.security.Provider 库可以为 API 最低要求之外的其他算法提供 MessageDigest 实现。在 API 级别上仅列出默认算法的限制性 enum 将限制可扩展性。
同样的情况也适用于允许其他javax.mail.Provider实现在邮件会话属性的情况下支持附加/自定义属性。

11
这两个原因都不是令人满意的。就像 String.getBytes("UTF-8") 可以接受 String.getBytes(StandardCharsets.UTF_8),而且你不需要处理可能的“UnsupportedEncodingException”一样,类似的映射也应该为 MessageDigest.getInstance("MD5") 提供。在运行时检查编译时已知的事物总是错误的。好的库可以帮助你避免这种情况。 - swalog
2
@swalog 是否可以或应该提供其他映射及相应的方法?当然可以,但出于上述原因,这并不会使基于字符串的方法变得无用。 - Robby Cornelissen
5
同意。我应该明确指出你提供的理由已经回答了问题。我的批评是针对API的。我想指出的是,没有理由不使用常量来避免需要API必需实现时运行时字符串查找。我们可以做到既有常量又具备向后兼容性和可扩展性。 - swalog
2
@swalog StandardCharsets.UTF_8 包含了实际的 Charset 实现,因此它在查找时不会失败,而 MessageDigest.getInstance(HypotheticalEnumType) 仍然需要通过与基于字符串的方法相同的代码路径来查找提供程序,并且唯一的区别是在失败时不允许抛出已检查的异常。 - Holger

2
很容易认为原因只是向后兼容性。
对于JavaMail,因为它有太多与不同连接器相关的设置,您只需要其中一部分来设置与支持的协议之一建立连接。每个连接器都在单独的类中实现,我认为没有理由让例如POP3连接器知道IMAP连接器的设置。
对于MessageDigest,原因是支持非标准加密算法,这些算法未打包到JDK中,但由第三方JCE适配器提供。例如,CryptoPro JCE提供的GOST算法的示例:
  MessageDigest digest = MessageDigest.getInstance("GOST3411"); 

我同意你的两个观点,但我正在寻找更通用的答案(就字符串常量的一般使用而言)。无论如何,谢谢。 - Rajan Prasad

2

这很可能是由于Java主要注重向前兼容以前的版本。

Enum是在Java 1.5中引入的,因此任何针对1.4或更早版本编写的API都不支持此功能。这在JDK的许多API中非常普遍。

还需要记住,enum是不可扩展的,这意味着如果您想在消息摘要中引入新算法,那么您将受到限制...没有办法做到。

同样,邮件API也提供了对明显不同概念的支持,它们不会具有相同的属性系列,并且无法设计单个enum来支持现有或将来存在的不同实现之间的所有各种属性,enum对于这项工作来说过于僵硬。


我已经阅读过了。但他们本可以扩展他们的 API,允许使用枚举来分配属性,对吧? - Rajan Prasad
2
@Raymond232,然而这些API的目的并不是如此。这些API旨在提供一个通用的接口,通过该接口您可以与某些情况下的“接口”进行交互。这些“接口”仍然受到其所知道的内容的限制,而不是未来可能出现的内容...在这种情况下,“枚举”太过于受限制了... - MadProgrammer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接