169it科技资讯


当前位置:  编程技术>java/j2ee

Java编程中的一些常见问题汇总

    来源: 互联网  发布时间:2014-11-08

本文列举了我在周围同事的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”。

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


    
相关技术文章:
    ▪java之super关键字用法实例解析

     本文实例讲述了java中super关键字的用法。分享给大家供大家参考。具体方法分析如下: super关键字:在java中使用super来引用基类的成分。 程序代码如下: class FatherClass{ public int value; public void f(){ value = 100; System.out.println("FatherClass.value:"+value); } } class ChildClass extends FatherClass{ private int value; public void f(){ super.f(); value=200; System.out.println("ChildClass.value:"+value); System.out.println(value); System.out.println(super.value); } } public class TestInHerit{ public static void main(String args[]){ ChildClass cc = new Chil......


    ▪java生成jar包的方法

     本文实例讲述了java生成jar包的方法,是非常实用的技巧。分享给大家供大家参考。具体分析如下: 很多Java初学者都会有这样的疑问:Java编写的application程序是否能够最终形成一个类似于exe一样的可执行文件,难道就只能用命令行运行? 通常来说有两种方法,一种是制作一个可执行的JAR文件包,然后就可以像.chm文档一样双击运行了;而另一种是使用JET来进行编译。但是JET是要用钱买的,而且据说JET也不是能把所有的Java程序都编译成执行文件,性能也要打些折扣。所以,使用制作可执行JAR 文件包的方法就是最佳选择了,何况它还能保持Java的跨平台特......


    ▪java之static关键字用法实例解析

     本文实例讲述了java中static关键字用法,分享给大家供大家参考。具体分析如下: 一、介绍: 1、在类中,用static声明的成员变量为静态成员变量,它为该类的公用变量,在第一次使用时被初始化,对于该类的所有对象来说,static成员变量只有一份。 2、用static声明的方法为静态方法,在调用该方法时,不会将对象的引用传递给它,所以在static方法中不可访问非static成员。(静态方法不再是针对于某个对象调用,所以不能访问非静态成员) 3、可以通过对象引用或类名(不需要实例化)访问静态成员。 注:静态变量多用于计数......


 
最新技术文章:
    ▪Java中使用开源库JSoup解析HTML文件实例

     HTML是WEB的核心,互联网中你看到的所有页面都是HTML,不管它们是由JavaScript,JSP,PHP,ASP或者是别的什么WEB技术动态生成的。你的浏览器会去解析HTML并替你去渲染它们。不过如果你需要自己在Java程序中解析HTML文档并查找某些元素,标签,属性或者检查某个特定的元素是否存在的话,那又该如何呢?如果你已经使用Java编程多年了,我相信你肯定试过去解析XML,也使用过类似DOM或者SAX这样的解析器,不过很有可能你从未进行过任何的HTML解析的工作。更讽刺的是,在Java应用中,很少会有需要你去解析HTML文档的时候,这里并不包括Servlet或者其它的Java WEB技术。更糟糕......


    ▪Java函数式编程(一):你好,Lambda表达式

     第一章 你好,lambda表达式! 第一节 Java的编码风格正面临着翻天覆地的变化。 我们每天的工作将会变成更简单方便,更富表现力。Java这种新的编程方式早在数十年前就已经出现在别的编程语言里面了。这些新特性引入Java后,我们可以写出更简洁,优雅,表达性更强,错误更少的代码。我们可以用更少的代码来实现各种策略和设计模式。 在本书中我们将通过日常编程中的一些例子来探索函数式风格的编程。在使用这种全新的优雅的方式进行设计编码之前,我们先来看下它到底好在哪里。 改变了你的思......


    ▪Java函数式编程(二):集合的使用

     第二章:集合的使用 我们经常会用到各种集合,数字的,字符串的还有对象的。它们无处不在,哪怕操作集合的代码要能稍微优化一点,都能让代码清晰很多。在这章中,我们探索下如何使用lambda表达式来操作集合。我们用它来遍历集合,把集合转化成新的集合,从集合中删除元素,把集合进行合并。 遍历列表 遍历列表是最基本的一个集合操作,这么多年来,它的操作也发生了一些变化。我们使用一个遍历名字的小例子,从最古老的版本介绍到现在最优雅的版本。 用下面的代码我们很容易创建一个不可变的名字的......


 


站内导航:


特别声明:169IT网站部分信息来自互联网,如果侵犯您的权利,请及时告知,本站将立即删除!

©2012-2017,169IT.COM,E-mail:www_169it_com#163.com(请将#改为@)

浙ICP备11055608号