Typical Mistakes in Java Code

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

这个页面包含了我在与我一起工作的人的Java代码中经常看到的大多数典型错误。静态分析(我们使用qulice)由于明显的原因无法捕捉到所有的错误,这就是为什么我决定在这里列出它们的原因。

如果你想看到其他添加在这里的内容,请告诉我,我会很乐意满足你的要求。

所有列出的错误都与面向对象编程有关,尤其是与Java有关。

你的类应该是一个现实生活实体的抽象,不应包含“验证器”、“控制器”、“管理器”等术语。如果你的类名以“-er”结尾,那么它是一个糟糕的设计。顺便提一下,以下是我对良好对象的七个特点。此外,这篇文章详细解释了这个观点:不要创建以-ER结尾的对象。

当然,工具类是反模式,比如来自Apache的StringUtilsFileUtilsIOUtils。上述示例都是糟糕设计的完美例子。请阅读这篇后续文章:面向对象编程中的替代工具类。

当然,永远不要添加后缀或前缀来区分接口和类。例如,以下所有名称都是错误的:IRecordIfaceEmployeeRecordInterface。通常,接口名是现实生活实体的名称,而类名应该解释其实现细节。如果对于实现没有特别的说明,可以命名为DefaultSimple或类似的名称。例如:

Method Names

方法可以返回某些东西或返回void。如果一个方法返回某些东西,那么它的名称应该解释它返回什么,例如(永远不要使用get前缀):

如果返回void,那么它的名称应该解释它的功能。例如:

你可以在Elegant Objects这本书的第2.4节中了解更多关于这个想法的内容。只有一个例外需要提到—JUnit的测试方法。下面对它们进行了解释。

在JUnit测试中,方法名应以英语句子的形式创建,不包含空格。举个例子来解释会更容易理解:

重要的是在你的Javadoc的第一句话中以你正在测试的类的名称开头,后面跟着can(或cannot)。因此,你的第一句话应该始终类似于“某人可以做某事”。

方法名称将完全相同,但没有主语。如果我在方法名称的开头添加一个主语,我应该得到一个完整的英语句子,就像上面的例子一样:“HttpRequest以Unicode返回其内容”。

请注意,测试方法不以can开头。只有Javadoc注释使用’can’。

将测试方法声明为抛出Exception是一个好的做法。

避免使用复合变量名,如timeOfDayfirstItemhttpRequest。我的意思是包括类变量和方法内部的变量。变量名应该足够长,以避免在其可见范围内产生歧义,但如果可能的话,不应该太长。一个变量名应该是单数或复数形式的名词,或者是一个合适的缩写。关于这个问题,在这篇文章中有更多信息:《复合名称是一种代码异味》。例如:

有时候,如果构造函数将传入的数据保存在实例化对象中,可能会出现构造函数参数和类内属性之间的冲突。在这种情况下,我建议通过删除元音字母来创建缩写(参见美国邮政服务如何缩写街道名称)。

public class Message {
  private String recipient;
  public Message(String rcpt) {
    this.recipient = rcpt;
  }
}

在许多情况下,确定变量名称的最佳提示可以通过阅读其类名来获得。只需用小写字母写出即可,这样你就应该没问题了:

然而,永远不要对原始类型进行相同的操作,比如Integer numberString string

当存在具有不同特征的多个变量时,您还可以使用形容词。例如:

Constructors

没有例外,应该只有一个构造函数用于存储数据到对象变量中。其他所有构造函数都应该以不同的参数调用这个构造函数。例如:

在《只能有一个主要构造函数》中有更多关于此的信息。

尽量避免使用一次性变量。所谓“一次性”是指仅使用一次的变量。就像在这个例子中一样:

以上变量只使用一次,代码应该被重构为:

有时候,在非常罕见的情况下——主要是由于更好的格式——可能会使用一次性变量。然而,尽量避免出现这种情况,不惜一切代价。

毫无疑问,你绝对不应该吞噬异常,而是应该尽可能地将它们向上抛出。私有方法应该总是让已检查异常离开。

绝对不要使用异常来控制流程。例如,下面的代码是错误的:

如果那个 IOException 提示“磁盘已满”,你还会认为文件大小为零然后继续吗?

对于缩进而言,主要规则是括号要么在行尾结束,要么在同一行上关闭(反向规则适用于闭合括号)。例如,以下写法是不正确的,因为第一个括号没有在同一行上关闭,并且在它后面还有符号。第二个括号也有问题,因为在它前面有符号,并且没有在同一行上打开:

正确的缩进应该如下所示:

缩进的第二个重要规则是尽可能将内容放在一行上,但不能超过80个字符的限制。上面的示例是无效的,因为它可以被压缩。

Redundant Constants

类常量应该在你想要在类方法之间共享信息,并且这些信息是类的特征时使用。不要将常量用作字符串或数字字面量的替代品——这是一种非常糟糕的做法,会导致代码污染。常量(与面向对象编程中的任何对象一样)应该在现实世界中具有一定的意义。这些常量在现实世界中有什么意义呢?

另一个典型的错误是在单元测试中使用常量来避免在测试方法中重复使用字符串/数值字面量。不要这样做!每个测试方法应该使用自己的一组输入值。

在每个新的测试方法中使用新的文本和数字。它们是独立的。那么,为什么它们必须共享相同的输入常量呢?

这是一个测试方法中的数据耦合的例子。

在最后一行,我们将"Jeff"与第一行的相同字符串字面值相结合。如果几个月后有人想要更改第三行的值,他/她必须花额外的时间找到在同一个方法中其他地方使用了"Jeff"的地方。

为了避免这种数据耦合,您应该引入一个变量。更多信息请参阅:关于单元测试搭建的一些思考。

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-12-27 at 10:46

sixnines availability badge   GitHub stars