Java程序员常犯的10个错误

原文出自:http://www.programcreek.com/2014/05/top-10-mistakes-java-developers-make/java

本文总结了Java程序员常犯的10个错误。程序员

1. 把Array转化成ArrayList

把Array转化成ArrayList,程序员常常用如下方法:算法

List list = Arrays.asList(arr);
Arrays.asList() 实际上返回一个ArrayList,可是这个ArrayList是Arrays的一个内部私有类,而不是java.util.ArrayList类。这个私有类java.util.Arrays.ArrayList有set(), get(), contains()方法,可是不可以添加新的元素。它的大小是固定的。若是你想要一个java.util.ArrayList,正确的方法是:
数组

ArrayList arrayList = new ArrayList (Arrays.asList(arr));
java.util.ArrayList的构造函数能够接受一个集合类型。java.util.Arrays.ArrayList也继承了集合类型,因此能够做用参数使用。
安全

2. 检查数组是否包含一个值

开发人员常常作的是:数据结构

Set set = new HashSet (Arrays.asList(arr));
return set.contains(targetValue);
这个代码是工做的,但没有没有效率。把列表转换成set没有必要,须要额外的时间。正确的方法是:
函数

Arrays.asList(arr).contains(targetValue);
或者,一个简单的loop:oop

for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;
第一种比第二种更具备可读性。性能

3. 在循环中删除一个列表元素

考虑下面的代码,迭代过程当中删除元素:ui

ArrayList list = new ArrayList (Arrays.asList("a", "b", "c", "d"));
for (int i = 0; i < list.size(); i++) {
list.remove(i);
}
System.out.println(list);
这段代码的输出是:

[b, d]
这个方法有一个严重的问题。当元素被移除,该列表的大小缩减,元素索引也随之发生了变化。因此,若是你想经过使用索引来删除一个循环内的多个元素,就会致使错误的结果。

你可能猜到可使用iterator来删除循环中的元素。在Java中的foreach循环的工做原理就像一个iterator。 可是在这里也会发生错误。请看下面的代码:

ArrayList list = new ArrayList (Arrays.asList("a", "b", "c", "d"));

for (String s : list) {
if (s.equals("a"))
list.remove(s);
}
上面的foreach loop代码会抛出一个异常ConcurrentModificationException. 可是下面这段代码不会。

ArrayList list = new ArrayList (Arrays.asList("a", "b", "c", "d"));
Iterator iter = list.iterator();
while (iter.hasNext()) {
String s = iter.next();

if (s.equals("a")) {
    iter.remove();
}

}
经过分析ArrayList.iterator()的原代码,咱们能够发现next()方法必需要在remove()方法前被调用。在foreach loop中,编译器产生的代码会先调用next()方法,从而产生异常ConcurrentModificationException。请查看ArrayList.iterator()的原代码。

4. Hashtable 与 HashMap

按照算法惯例,Hashtable是数据结构的名称。但在Java中,数据结构的名称是HashMap。Hashtable是同步的版本。因此不少时候你并不须要Hashtable,而是HashMap。 这两篇文章详细介绍了各类Map的区别和常见的问题: HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap, Map常见10大问题,

5.使用原始类型Collection

在Java中,原始类型和无界通配符类型很容易混在一块儿。以Set为例,Set是原始类型,而Set>是无界通配符类型。 考虑下面的代码,它使用原始类型的List做为参数: public static void add(List list, Object o){ list.add(o); } public static void main(String[] args){ List list = new ArrayList (); add(list, 10); String s = list.get(0); } 此代码将抛出一个异常: Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at ... 使用原始类型的Collection是危险的,由于原始类型的Collection跳过类型检查。另外值得一提的是Set, Set>, Set<Object>之间存在着巨大的差别。 了解更多,请查看原始类型 vs. 无界通配符类型 和 类型擦除。

6. 访问级别

不少时候,开发者使用public修饰字段。这样作的好处是很容易经过直接引用来获取字段的值,可是这是一个很是糟糕的设计。经验法则是“给成员的访问级别尽量低”。能够查看Java4种不一样的访问级别public, default, protected, and private。

7. ArrayList 与 LinkedList

当开发人员不知道ArrayList和LinkedList的区别的时候,他们常用的是ArrayList,可能由于它看起来面熟。可是ArrayList和LinkedList之间有巨大的性能差别。 简单来讲若是有大量的添加/删除操做,而没有不少随机存取操做,LinkedList的应该是首选。能够查看ArrayList与LinkedList了解它们之间更多的区别。

8.可变性与不变性

不可变对象有不少优势,如简单性,安全性等。可是它须要为每一个不一样的值创造一个单独的对象,对象太多可能会致使垃圾回收的成本高。因此可变和不可变之间进行选择时应该有一个平衡。

通常状况下,使用可变对象,以免产生过多的中间对象。一个经典的例子是串联了大量的字符串。若是使用的是不可变的字符串String,会产生不少能够垃圾回收的对象。这样既浪费时间也浪费CPU的运算能力,使用可变对象是正确的解决方案(如StringBuilder)。

String result="";
for(String s: arr){
result = result + s;
}
另一些状况,可变对象刚更加合适可取。例如排序(Collections.sort())。若是Collection是不可变的,排序方法每次将会返回一个新的Collection,这样会极其浪费资源。 能够看看为何在Java中String被设计成不可变?

9. 父类和子类的构造函数

以上这段代码出现编译错误,由于默认的父类构造函数未定义。在Java中,若是一个类没有定义构造函数,编译器会默认插入一个默认的无参数构造函数。若是程序员定义构造函数,编译器将不插入默认的无参数构造函数。上面的代码因为自定义了有参数的构造函数,编译器再也不插入无参数的构造函数。子类的构造函数,不管是有参数或无参数,都将调用父类无参构造函数。当子类须要父类的无参数构造函数的时候,就发生了错误。

解决这个问题,能够1)增长一个父类构造函数

public Super(){
System.out.println("Super");
}
,或2)删除自定义的父类构造函数,或3)添加super(value)到子类构造函数。更多请查看父类和子类的构造函数。

10. "" 与 Constructor?

字符串能够经过两种方式建立:

//1. use double quotes
String x = "abc";
//2. use constructor
String y = new String("abc");
这二者有什么区别呢? 下面的例子能够提供一个快速的答案:

String a = "abcd";
String b = "abcd";
System.out.println(a == b); // True
System.out.println(a.equals(b)); // True

String c = new String("abcd");
String d = new String("abcd");
System.out.println(c == d); // False
System.out.println(c.equals(d)); // True
关于它们是如何分配内存的更多信息,请查看建立Java字符串使用“”或构造函数?

小结

以上是我根据GitHub上的开源项目,Stack Overflow上的问题,和谷歌热门搜索词所作的总结。虽然它们不是准确的top 10,但很常见的。若是你有不一样的观点或者指出更常见的错误,请留言。我也会更新这个列表。很是感谢。

相关文章
相关标签/搜索