Java命名约定的静态最终variables

有一个规则说:

表示常量(最终variables)的名称必须全部使用下划线来区分单词(取自http://geosoft.no/development/javastyle.html )

对于像int或者string这样的原始types来说工作正常:

private static final int MAX_COUNT = 10; 

但是非基元types呢? 在大多数情况下,我看到以下几点:

 private static final Logger log = Logger.getLogger(MyClass.class); 

或者在单例中,实例variables不是大写。

问题是什么是正确的方式来声明这些types的variables(如日志和实例)?

这仍然是一个常数 。 有关常量的命名约定的更多信息,请参阅JLS 。 但实际上,这只是一个偏好问题。


接口types中常量的名称应该是,并且类types的finalvariables通常可以是一个或多个单词,首字母缩写词或缩写的序列,全部大写,组成部分用下划线"_"字符分隔。 常量名称应该是描述性的,而不是不必要的缩写。 传统上他们可能是任何适当的词性。 常量的名称示例包括类Character MIN_VALUEMAX_VALUEMIN_RADIXMAX_RADIX

一组代表一个集合的替代值的常量,或者不太常见的整数值中的屏蔽位有时用一个通用的首字母缩写词作为名称前缀来指定,如下所示:

 interface ProcessStates { int PS_RUNNING = 0; int PS_SUSPENDED = 1; } 

涉及常数名称的模糊是罕见的:

  • 常量名称通常不包含小写字母,因此它们通常不会隐藏包或types的名称,也不会正常地映射其名称通常至less包含一个小写字母的字段。
  • 常量名称不能掩盖方法名称,因为它们在语法上是有区别的。

这个对话框似乎是关于命名interfaceabstract类的对话的对立面。 我觉得这是令人震惊的,并且认为这个决定要比简单地select一个命名约定更深层次,并且总是使用static final

摘要和接口

当命名接口和抽象类时,接受的约定已经演变成不会为abstract classinterface添加任何标识信息的前缀或后缀,这些标识信息表明它不是类。

 public interface Reader {} public abstract class FileReader implements Reader {} public class XmlFileReader extends FileReader {} 

据说开发者不需要知道上面的类是abstract还是一个interface

静态最终

我个人的偏好和信念是,在提到static finalvariables时,我们应该遵循类似的逻辑。 相反,我们在确定如何命名时评估其使用情况。 似乎所有大写的参数都是从C和C ++语言中被盲目地采用的。 在我看来,在Java中inheritance传统是不合理的。

意向问题

我们应该问自己,在我们的情况下static final的function是什么。 这里有三个例子说明如何在不同的上下文中使用static final

 public class ChatMessage { //Used like a private variable private static final Logger logger = LoggerFactory.getLogger(XmlFileReader.class); //Used like an Enum public class Error { public static final int Success = 0; public static final int TooLong = 1; public static final int IllegalCharacters = 2; } //Used to define some static, constant, publicly visible property public static final int MAX_SIZE = Integer.MAX_VALUE; } 

你能在所有的三种情况下使用全部大写吗? 当然,但我认为这可能会削弱每一个的目的。 所以,我们来分别检查每个案例。


目的:私有variables

在上面的Logger示例中,logging器被声明为private,并且只能在类中使用,或者可能是内部类。 即使它是在protected package可见性下宣布的,其用法也是一样的:

 public void send(final String message) { logger.info("Sending the following message: '" + message + "'."); //Send the message } 

在这里,我们不关心那个logger是一个static final成员variables。 它可能只是一个final实例variables。 我们不知道。 我们不需要知道。 我们需要知道的是,我们将消息logging到类实例提供的logging器。

 public class ChatMessage { private final Logger logger = LoggerFactory.getLogger(getClass()); } 

在这种情况下,你不会把它命名为LOGGER ,那么为什么要把它全部命名为大写呢? 它的背景或意图在两种情况下是相同的。

注意:由于它更像是一种public访问的forms,仅限于package级别,所以我改变了对package可见性的立场。


目的:枚举

现在你可能会说,你为什么使用static final整数作为enum ? 这是一个仍在发展的讨论,我甚至会说是半争议的,所以我会尽量不冒这个讨论的时间。 但是,build议您可以实现以下可接受的枚举模式:

 public enum Error { Success(0), TooLong(1), IllegalCharacters(2); private final int value; private Error(final int value) { this.value = value; } public int value() { return value; } public static Error fromValue(final int value) { switch (value) { case 0: return Error.Success; case 1: return Error.TooLong; case 2: return Error.IllegalCharacters; default: throw new IllegalArgumentException("Unknown Error value."); } } } 

有上面的变化,实现了相同的目的,允许显式转换一个enum->intint->enum 。 在通过networking传输这些信息的范围内,本地Java序列化太简单了。 简单的intshortbyte可以节省巨大的带宽。 我可以深入研究一下,比较和比较enumstatic final int 优缺点 ,包括types安全性,可读性,可维护性等。 幸运的是,这超出了这个讨论的范围。

底线是这样的, 有时候static final int将被用作enum样式结构

如果你能让自己接受上述陈述是真实的 ,那么我们可以通过讨论风格来跟上这一点。 当声明一个enum ,接受的样式表示我们不执行以下操作:

 public enum Error { SUCCESS(0), TOOLONG(1), ILLEGALCHARACTERS(2); } 

相反,我们执行以下操作:

 public enum Error { Success(0), TooLong(1), IllegalCharacters(2); } 

如果你的static final的整数块作为一个松散的enum ,那么你为什么要使用不同的命名约定呢? 它的背景或意图在两种情况下是相同的。


目的:静态,常量,公共属性

这个用例可能是最阴暗和最有争议的。 静态常量大小的用法示例是最经常遇到的地方。 Java 不需要sizeof() ,但有时候知道数据结构将占用多less字节是很重要的。

例如,假设您正在编写或读取二进制文件的数据结构列表,并且该二进制文件的格式要求在实际数据之前插入数据块的总大小。 这是很常见的,所以读者知道数据在场景中何时停止,并且有更多不相关的数据在后面。 考虑下面组成的文件格式:

 File Format: MyFormat (MYFM) for example purposes only [int filetype: MYFM] [int version: 0] //0 - Version of MyFormat file format [int dataSize: 325] //The data section occupies the next 325 bytes [int checksumSize: 400] //The checksum section occupies 400 bytes after the data section (16 bytes each) [byte[] data] [byte[] checksum] 

这个文件包含一个MyObject对象的列表,该对象序列化成一个字节stream并写入这个文件。 这个文件有325个字节的MyObject对象,但不知道每个MyObject的大小,你无法知道哪些字节属于每个MyObject 。 所以,你在MyObject上定义了MyObject的大小:

 public class MyObject { private final long id; //It has a 64bit identifier (+8 bytes) private final int value; //It has a 32bit integer value (+4 bytes) private final boolean special; //Is it special? (+1 byte) public static final int SIZE = 13; //8 + 4 + 1 = 13 bytes } 

如上所述, MyObject数据结构在写入文件时将占用13个字节。 知道这一点,当阅读我们的二进制文件时,我们可以dynamic地计算出文件中有多less个MyObject对象:

 int dataSize = buffer.getInt(); int totalObjects = dataSize / MyObject.SIZE; 

这似乎是所有大写static final常量的典型用法和参数,我同意在这种情况下,所有的大写都是有意义的。 原因如下:

Java没有像C语言那样的struct类,但是struct只是一个包含所有公共成员而没有构造函数的类。 这只是一个数据struct 。 所以,你可以像struct一样声明一个class

 public class MyFile { public static final int MYFM = 0x4D59464D; //'MYFM' another use of all uppercase! //The struct public static class MyFileHeader { public int fileType = MYFM; public int version = 0; public int dataSize = 0; public int checksumSize = 0; } } 

让我先说这个例子,说我本人不会这样parsing。 我build议一个不可变的类,而不是通过接受ByteBuffer或所有4个variables作为构造函数参数来处理内部parsing。 这就是说,访问(在这种情况下)这个struct的成员会看起来像这样:

 MyFileHeader header = new MyFileHeader(); header.fileType = buffer.getInt(); header.version = buffer.getInt(); header.dataSize = buffer.getInt(); header.checksumSize = buffer.getInt(); 

这些不是staticfinal ,但它们是公开的可以直接设置的成员。 出于这个原因,我认为当一个static final成员公开暴露时,完全用大写是有道理的。 这是一个重要的时候区分它与公共的,非静态的variables。

注意:即使在这种情况下,如果开发人员试图设置finalvariables,他们将遇到IDE或编译器错误。


概要

总而言之,您selectstatic finalvariables的惯例将成为您的偏好,但我坚信使用的上下文应该严重影响您的devise决策。 我个人的build议是遵循以下两种方法之一:

方法论1:评估语境和意图[highly subjective; logical] [highly subjective; logical]

  • 如果它是一个privatevariables,应该与private实例variables不可区分,那么将它们命名为相同。 全部小写
  • 如果它的意图是作为一种static值的松散enumtypes块,那么将其命名为enum帕斯卡案件:首字母大写每个单词
  • 如果意图是定义一些可公开访问的,常量的和静态的属性,那么通过使其全部大写来让它突出

方法二:私人与公共[objective; logical] [objective; logical]

方法论2基本上将其上下文浓缩为可见性,并且没有解释的余地​​。

  • 如果它是privateprotected那么它应该是全部小写
  • 如果是publicpackage那么它应该全部大写

结论

这是我如何查看static finalvariables的命名约定。 我不认为这是可以或应该被装箱成一个单一的东西。 我相信你应该在决定如何命名它之前评估它的意图。

但是,主要目标应该是在整个项目/包装的范围内保持一致。 最后,这是你所有的控制权。

(我希望遇到阻力,但也希望能够从这个方法上得到社会的一些支持,不pipe你的立场如何,在责备,批评或赞扬这种风格的select时,请保持公开。)

语言不关心。 重要的是遵循你正在工作的项目的既定风格和约定,以便其他维护者(或者你现在五个月以后)有最好的机会不要被混淆。

我认为一个可变对象的全大写名称肯定会让我感到困惑,即使对这个对象的引用碰巧存储在一个static finalvariables中。

那么这是一个非常有趣的问题。 我会根据它们的types在你的问题中划分两个常量。 int MAX_COUNT是基本types的常量,而Logger log是非基元types。

当我们使用一个基本types的常量时,我​​们public static final in MAX_COUNT = 10代码public static final in MAX_COUNT = 10只改变一次常量,我们只是在其他地方访问常量的值for(int i = 0; i<MAX_COUNT; i++) 。 这就是我们使用这个惯例的理由。

虽然在非原始types的情况下,虽然我们初始化常量只在一个地方private static final Logger log = Logger.getLogger(MyClass.class); ,我们预计会改变或调用这个常量在其他地方log.debug("Problem") 。 我们不喜欢在大写字母之后加一个点运算符。 毕竟,我们必须把一个函数名称放在点运算符后面,这肯定是一个骆驼案例名称。 这就是为什么LOG.debug("Problem")看起来尴尬。

Stringtypes也是如此。 我们通常不会在代码中对String常量进行变异或调用方法,这就是为什么我们对Stringtypes对象使用大写命名约定的原因。

没有“正确”的方式 – 只有公约。 你已经说明了最常见的约定,我遵循自己的代码: 所有的静态决赛应该全部大写。 我想其他球队遵循其他惯例。

对象的常量引用不是一个常量,它只是一个对象的常量引用。

private static final不是什么定义的东西是一个常数或不。 这只是定义一个常量的Java方法,但并不意味着每个private static final声明都放在那里定义一个常量。

当我写private static final Logger我不是想定义一个常量,我只是想定义一个private对象的引用(即不能从其他类访问), static (它是一个类级别variables,不需要实例)和final (只能分配一次)。 如果这恰好与Java期望你声明一个常数的方式一致,那么运气不好,但它并不是一个常数。 我不在乎编译器,声纳或Java大师说什么。 一个常量,比如MILLISECONDS_IN_A_SECOND = 1000是一回事,一个对象的常量引用是另一回事。

黄金被称为闪耀,但不是所有闪耀的黄金。

在我看来,一个variables是“常量”通常是一个实现细节,并不一定certificate不同的命名约定。 这可能有助于可读性,但在某些情况下也可能会伤害到它。

这些variables是常量,即private static final是否被命名为全部大写。 全能约定简单地说明这些variables是常量,但并不是必需的。 我见过

 private static final Logger log = Logger.getLogger(MyClass.class); 

在小写之前,我很好,因为我知道只使用logging器来logging消息,但它违反了惯例。 你可以争辩说,命名它的log是一个子约定,我想。 但是一般来说,用大写命名常量不是一个正确的方法,而是最好的方法。

不要狂热地对待SUN已经打好的惯例,对你和你的团队做些什么感觉。

例如,这是如何做日食,打破常规。 尝试添加implements Serializable和eclipse将要求为您生成此行。

更新:被排除的特殊情况不知道。 然而,我坚持要做你和你的团队似乎合适。