`
deepinmind
  • 浏览: 456152 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
1dc14e59-7bdf-33ab-841a-02d087aed982
Java函数式编程
浏览量:42011
社区版块
存档分类
最新评论

Java代码中的常见问题

 
阅读更多
本文列举了我在周围同事的Java代码中看到的一些比较典型的错误。显然,静态代码分析(我们团队用的是qulice)不可能发现所有的问题,这也是为什么我要在这里列出它们的原因。

如果你觉得少了什么,请不吝赐教,我会很乐意把它们加上。

下面列出的所有这些错误基本都与面向对象编程有关,尤其是Java的OOP。

类名

读下这篇短文“什么是对象”。类应该是真实生活中的一个抽象实体,而不是什么“validators”,“controller”, “managers”这些东西。如果你的类名以”er”结尾的话——那它就是个糟糕的设计。

当然了,工具类也是反模式,比如说Apache的StringUtils, FileUtils, 以及IOUtils。上面这些都是糟糕设计的代表。延伸阅读:OOP中工具类的替代方案

当然,不要使用前缀或者后缀来区分类和接口。比方说,这些名字就是错误的:IRecord, IfaceEmployee, 或者RecordInterface。通常来说,接口名应该是真实生活中的实体的名字,类名应该可以说明它的实现细节。如果这个实现没有什么特别可说明的,可以把它叫作Default, Simple或者类似的什么。比如说:



class SimpleUser implements User {};
class DefaultRecord implements Record {};
class Suffixed implements Name {};
class Validated implements Content {};






方法名


方法可以返回值也可以返回void。如果方法返回值的话,它的名字应该能说明它返回了什么,比如说(永远也不要使用get前缀):





boolean isValid(String name);
String content();
int ageOf(File file);






如果它返回void,那么它的名字应该要说明它做了什么。比如:





void save(File file);
void process(Work work);
void append(File file, String line);






刚才提到的这些规则只有一个例外——JUnit的test方法不算。下面将会说到这个。


test方法的名字


在JUnit的测试用例中,方法名应该是没有空格的英文语句。用一个例子来说明会更清楚一些:




/**
 * HttpRequest can return its content in Unicode.
 * @throws Exception If test fails
 */
public void returnsItsContentInUnicode() throws Exception {
}




你的JavaDoc里的第一句话的开头应该是你要测试的那个类的名字,然后是一个can。因此,你的第一句话应该是类似于“somebody can do something”。


方法名也是一样的,只是没有主题而已。如果我在方法名中间加一个主题的话,我就能得到一个完整的句子,正如上面那个例子中那样:“HttpRequest returns its content in unicode”。


请注意test方法的名字是不以can开头的。只有JavaDoc里的的注释会以can开头。除此之外,方法名不应该以动词开头。


实践中最好将测试方法声明为抛出Exception的。


变量名


避免组合的变量名,比如说timeOfDay, firstItem,或者httpRequest。类变量及方法内的变量都是如此。变量名应该足够长,避免在它的可见作用域内产生歧义,但是如果可以的话也不要太长。名字应该是单数或复数形式的名词,或者是一个适当的缩写。比如:





List<String> names;
void sendThroughProxy(File file, Protocol proto);
private File content;
public HttpRequest request;






有的时候,如果构造方法要将入参保存到一个新初始化的对象中的时候,它的参数和类属性的名字可能会冲突。这种情况,我建议是去掉元音,使用缩写。


示例:





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






很多时候,看一下变量的类名就知道变量该取什么名字了。就用它的小写形式就好了,像这样就很靠谱:





File file;
User user;
Branch branch;






然而,基础类型的话,永远不要这么做,比如Integer number或者String string。


如果存在多个不同性质的变量的话,可以考虑下使用形容词。比如:





String contact(String left, String right);






构造方法


不考虑异常的话,应该只有一个构造方法用来将数据存储到对象变量中。其它构造方法则使用不同的参数来调用这个构造方法。比如说:





public class Server {
  private String address;
  public Server(String uri) {
    this.address = uri;
  }
  public Server(URI uri) {
    this(uri.toString());
  }
}






一次性变量


无论如何都应该避免使用一次性变量。这里我所说的“一次性“指的是只使用一次的变量。比如下面这个:







String name = "data.txt";
return new File(name);








上述的变量只会使用一次,因此这段代码可以重构成这样:





return new File("data.txt");






有的时候,比较罕见的情况中——主要是为了格式更好看些——可能会用到一次性变量。然而,还是应当尽量避免这种情况。


异常


毋庸赘言,永远不要自己吞掉异常,而是应该当它尽量往上传递。私有方法应该始终把受检查异常往外面抛。


不要使用异常来进行流程控制。比方说下面这段代码就是错误的:





int size;
try {
  size = this.fileSize();
} catch (IOException ex) {
  size = 0;
}




那如果IOException提示“磁盘已满”的话该怎么办?你还会认为这个文件大小为0,然后继续往下处理?


缩进


关于缩进,主要的规则就是左括号要么在该行的末尾,要么就在同一行上闭合(对于右括号来说则相反)。比如说,下面这个就不正确,因为第一个左括号没有在同一行上闭合,而它后面还有别的字符。第二个括号也有问题,因为它前面有字符,但对应的开括号又没在同一行上:





final File file = new File(directory,
  "file.txt");




正确的缩进应该是这样的:




StringUtils.join(
  Arrays.asList(
    "first line",
    "second line",
    StringUtils.join(
      Arrays.asList("a", "b")
    )
  ),
  "separator"
);






关于缩进,第二条重要的规则就是同时一行中应该尽量多写一些——上限是80个字符。上面的那个例子并不满足这点,它还可以收缩一下:





StringUtils.join(
  Arrays.asList(
    "first line", "second line",
    StringUtils.join(Arrays.asList("a", "b"))
  ),
  "separator"
);






多余的常量

当你希望在类的方法中共享信息的时候,应当使用类常量,这些信息应该是你这个类所特有的。不要把常量当作字符串或数值字面量的替代品来使用——这是非常糟糕的实践方式,它会对代码造成污染。常量(正如OOP中的任何对象一样)应当在真实世界中有它自己的含义。看下这些常量在真实生活中的意思是什么:






class Document {
  private static final String D_LETTER = "D"; // bad practice
  private static final String EXTENSION = ".doc"; // good practice
}






另一个常见的错误就是在单元测试中使用常量来避免测试方法中出现冗余的字符串或者数值的字面量。不要这么做!每个测试方法都应该有自己专属的输入值。


在每个新的测试方法中使用新的文本或者数值。它们是相互独立的。那么为什么它们还要共享同样的输入常量呢?


测试数据耦合


下面是测试方法中数据耦合的一个例子:






User user = new User("Jeff");
// maybe some other code here
MatcherAssert.assertThat(user.name(), Matchers.equalTo("Jeff"));








最后一行中,”Jeff”和第一行中的同一个字符串字面值发生了耦合。如果过了几个月,有人想把第三行这个值换一下,那么他还得花时间找出同一个方法中哪里也使用了这个”Jeff”。


为了避免这种情况,你最好还是引入一个变量。





原创文章转载请注明出处:http://it.deepinmind.com



英文原文链接
2
1
分享到:
评论

相关推荐

    java代码启动tomcat

    在 Java 中,使用 Tomcat 服务器来发布 Web 应用程序是一种常见的做法。下面,我们将详细介绍如何使用 Java 代码来启动 Tomcat 服务器,并实现远程控制 Tomcat。 标题: Java 代码启动 Tomcat 描述: Java 实现 ...

    Java项目开发代码Review常见问题实例.doc

    在进行Java项目开发的Code Review时,关注这些常见问题并采取相应措施,可以显著提升代码质量,减少潜在的运行时错误,提高系统的稳定性和性能。通过持续学习和实践,开发者可以更好地遵循最佳实践,为项目贡献更高...

    四种常用的java代码扫描工具介绍

    本文主要介绍了四种常用的 Java 代码扫描工具,并对它们的功能、特性等方面进行了分析和比较。这些工具分别是 Checkstyle、FindBugs、PMD 和 Jtest。静态代码分析是指无需运行被测代码,仅通过分析或检查源程序的...

    Java代码审计案例及修复

    在 Java 编程中,安全编码规范是非常重要的,它可以帮助开发者编写更加安全的代码,避免常见的安全漏洞。华为 Java 安全编码规范是业界广泛认可的安全编码规范之一,该规范提供了详细的编码指南,涵盖了输入验证、...

    审查Java代码的十一种常见错误

    ### 审查Java代码的十一种常见错误 在软件开发过程中,代码审查是确保软件质量的重要环节之一。本文将详细介绍审查Java代码时常见的十一种错误,并提供相应的解决方案,帮助开发者提高代码质量和程序稳定性。 ####...

    JAVA常用代码块

    JAVA常用代码块 JAVA常用代码块 JAVA常用代码块 JAVA常用代码块 JAVA常用代码块

    java代码自动生成工具

    Java代码自动生成工具是一种高效开发辅助软件,它能够根据预设的...总的来说,Java代码自动生成工具是现代软件开发中的重要辅助手段,通过合理利用,能够显著提升开发效率,降低出错概率,并且有利于项目的维护和扩展。

    将java代码生成html并且高亮显示的类

    在IT行业中,有时候我们需要将源...总的来说,将Java代码转换为HTML并高亮显示是一项常见的需求,涉及到代码解析、HTML生成和前端美化等多个技术环节。理解这个过程可以帮助开发者更好地在Web环境中分享和展示代码。

    Java代码审计(入门篇).pdf

    作者通过浅入深出的方式,从Java代码审计的基础知识讲起,逐步引导读者了解审计流程、掌握常用工具,并通过经典案例分析,让读者能够将理论与实践相结合,快速上手代码安全审计。 全书共分为多个章节,每个章节都有...

    JAVA代码审计常用漏洞总结

    主要代码审计方法是跟踪用户输入数据和敏感函数参数回溯: 跟踪用户的输入数据,判断...这个方法是最高效,最常用 的方法。大多数漏洞的产生是因为函数的使用不当导致的,只要找到这些函数,就能够快速挖掘想要的漏洞。

    java代码评审检查表.xls

    java代码评审检查表:包含java常用代码审查内容

    java 格式代码模板

    在编程世界中,保持代码的一致性和可读性至关重要,这就是`Java`代码格式化和模板工具的作用。本文将深入探讨`Java`代码格式代码模板(code templates)和代码格式化器(code formatter),以及如何利用它们提升开发...

    Java基础练习代码

    练习中可能会涉及到单例模式、工厂模式等常见设计模式的实现,这些模式可以提升代码的可维护性和复用性。 总之,"Java基础练习代码"旨在通过实际的编程练习,帮助初学者掌握Java语言的基础知识和编程技巧。通过反复...

    Java常用代码整理

    在"Java常用代码整理"这个主题中,我们可以探讨多个Java编程中的关键知识点,包括基础语法、面向对象特性、异常处理、集合框架、IO流、多线程、网络编程以及实用工具类等。 1. **基础语法**:Java的基础语法包括...

    把wsdl文件或地址转化成java代码工具

    在MyEclipse中,有一个内置的功能,可以将WSDL文件转换为Java代码,这个过程通常被称为“代码生成”或“代码反编译”。这样,开发者无需手动编写调用Web服务的Java代码,只需导入WSDL文件,MyEclipse就能自动生成...

    Java经典代码 Java经典代码

    "Java经典代码"通常指的是在Java编程中常见的、实用的、经过时间检验的代码片段,这些代码可以解决常见问题,或者展示了一些核心概念和技术。在这个Java项目案例导航源代码的压缩包中,我们可以期待找到各种各样的...

    加密典型代码(java)

    例如,使用AES加密的Java代码通常会涉及到`javax.crypto.Cipher`类,以及`SecretKey`的生成。开发者需要先创建一个密钥,然后利用`Cipher`类的`init()`方法初始化加密或解密模式,最后调用`doFinal()`方法执行加密或...

    VB代码转java代码,亲测可用

    在实际操作中,为了确保转换后的Java代码质量和可读性,需要对转换结果进行审查和调整。此外,理解两种语言的异同以及熟悉Java编程的最佳实践是至关重要的。在进行大型项目转换时,还应考虑测试策略,确保转换后的...

    java代码反编译器

    总的来说,Java代码反编译器是Java开发和调试工具箱中的重要组成部分,它们帮助开发者在缺乏源代码的情况下理解二进制代码,或者用于研究和学习已编译的库和框架。尽管反编译的代码可能无法完全恢复到原始的编写形式...

    Java代码审查工具

    2. **PMD**:PMD是一个开源的静态代码分析工具,用于检测Java代码中的常见问题,如未使用的变量、空的catch块、无效的if语句等。开发者可以自定义规则,以适应特定的项目需求。 3. **Checkstyle**:这个工具专注于...

Global site tag (gtag.js) - Google Analytics