文章列出了Java开发者最常犯的是个错误。

1.将数组转换为ArrayList

为了将数组转换为ArrayList,开发者经常会这样做:

1
List<String> list = Arrays.asList(arr);

Arrays.asList()会返回一个ArrayList,但这个ArrayListArrays的私有静态类,不是java.util.ArrayListjava.util.Arrays.ArrayListset(), get(), contains()方法,但没有任何能增加元素的方法,所以它的大小是确定的。 为了创建一个真正的ArrayList,应该这样做:

1
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));

ArrayList的构造函数能够接收一个Collection类型,而它也是java.util.Arrays.ArrayList的一个祖先类。

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

开发者经常这样做:

1
2
Set<String> set = new HashSet<String>(Arrays.asList(arr));
return set.contains(targetValue);

这个的代码可以工作,但没必要首先把数组转换为集合,把数组转换为集合需要额外的时间。可以这样做:

1
Arrays.asList(arr).contains(targetValue);

或者

1
2
3
4
5
for(String s: arr){
    if(s.equals(targetValue))
        return true;
}
return false;

第一个比第二个的可读性更好。

3.在循环里边删除列表的元素

思考下面的代码,该代码在循环里边删除元素

1
2
3
4
5
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
for (int i = 0; i < list.size(); i++) {
    list.remove(i);
}
System.out.println(list);

输出如下:

1
[b, d]

上面的方法有一个严重的问题。当一个元素被移除后,列表的大小减小了,索引也就变了。所以希望利用索引在一个循环里边删除多个元素是做不到的。 你可能知道利用迭代器在一个循环里边删除元素是正确的方法,并且知道Java的foreach循环很像一个迭代器,但事实上不是。思考下面的代码:

1
2
3
4
5
6
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
 
for (String s : list) {
    if (s.equals("a"))
        list.remove(s);
}

它将会抛出异常ConcurrentModificationException。 下面的代码是可以的:

1
2
3
4
5
6
7
8
9
ArrayList<String> list = new ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
    String s = iter.next();
 
    if (s.equals("a")) {
        iter.remove();
    }
}

.next()方法必须在调用.remove()方法之前调用。在foreach循环里边,编译器会先调用.remove(),再调用.next(),从而导致异常ConcurrentModificationException。你可能想知道ArrayList.iterator()的源代码。

4.HashTable vs HashMap

根据算法的约定,HashTable是这个数据结构的名字,但在Java里边,HashMap是这个数据结构的名字。Hashtable和 HashMap的一个关键性的不同是,HashTable是同步的,而HashMap不是。所以通常不需要HashTable,HashMap用的更多。 HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap Top 9 questions about Java Maps

5.使用原始集合类型

在Java里边,原始类型和无界通配符类型很容易混合在一起。以Set为例,Set是一个原始类型,而Set< ? >是一个无界通配符类型。 考虑下面使用原始类型List作为参数的代码:

1
2
3
4
5
6
7
8
public static void add(List list, Object o){
    list.add(o);
}
public static void main(String[] args){
    List<String> list = new ArrayList<String>();
    add(list, 10);
    String s = list.get(0);
}

上面的代码将会抛出异常:

1
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at ...

使用原始集合类型是很危险的,因为原始集合类型跳过了泛型类型检查,是不安全的。SetSet< ? >Set< Object >之间有很大差别。请参考Raw type vs. Unbounded wildcardType Erasure

6.访问级别

开发者经常使用Public作为类的修饰符,这样可以很简单的通过直接引用得到值,但这是一个非常糟糕的设计。根据经验,分配给成员的访问级别应尽可能的低。 public, default, protected, and private

7.ArrayList vs LinkedList

当开发者不知道ArrayList和LinkedList的区别的时候,通常会使用ArrayList,因为它看起来更熟悉。然而,两者之间有很大 的性能差异。简单地说,当有大量的插入/删除操作并且没有太多的随机访问操作的时候,应该使用LinkedList。如果对此不太了解,可参考ArrayList vs. LinkedList

8.可变与不可变

不可变对象有许多的优点,比如简单,安全等等。但是对于每一个不同的值都要有一个独立的对象,过多的对象导致垃圾回收的高消耗。当选择可变与不可变时应该有一个权衡。 通常情况下,可变对象可以用来避免产生过多的中间对象。一个经典的实例就是连接大量的字符串,如果使用不可变的字符串,将会产生大量的需要进行垃圾回收的对象。这会浪费CPU大量的时间,使用可变对象才是正确的方案(比如StringBuilder)。

1
2
3
4
String result="";
for(String s: arr){
    result = result + s;
}

在其它的一些情况下也是需要使用可变对象的,比如将可变对象作为参数传入方法可以使你不需要使用很多语句便可以得到多个结果。另外一个例子是排序和 过滤:当然,你可以写一个方法来接收原始的集合,并且返回一个排好序的集合,但是那样对于大的集合就太浪费了。(来自StackOverFlow的dasblinkenlight的答案)。 Why String is Immutable?

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

因为没有定义父类的默认构造函数,在编译的时候会产生错误。在Java里边,如果一个类没有定义构造函数,编译器将会插入一个无参数的默认构造函数。如果在父类里边定义了一个构造函数,在此例中即Super(String s),编译器将不会插入默认的无参数构造函数。这就是上面示例中父类的情形。 子类的构造函数,不管是没有参数还有有参数,都会调用父类的无参构造函数。因为编译器试图把super()插入到子类的两个构造函数中。但是父类默认的构造函数未定义,编译器就会报出这个错误信息。 要修复这个问题,可以简单的通过1)在父类中添加一个Super()构造方法,就像这样:

1
2
3
public Super(){
    System.out.println("Super");
}

或者2)移除自定义的父类构造函数,或者3)在子类的构造函数中调用父类的super(value)。 Constructor of Super and Sub

10.”“还是构造函数?

有两种方式构造字符串:

1
2
3
4
//1. 利用双引号
String x = "abc";
//2. 利用构造函数
String y = new String("abc");

区别在哪? 下面的例子可以给出一个快速的答案:

1
2
3
4
5
6
7
8
9
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

关于它们内存分配的更多细节,请参考Create Java String Using ”” or Constructor?

将来的工作

这个列表是我根据大量的GitHub上的开源项目、Stack Overflow上的问题和一些常见的Google搜索得到的。没有明显示的评估证明它们是准确的前10,但它们绝对是很常见的问题。如果您不同意任一部 分,请留下您的评论。如果您能提出其它一些常见的错误,我将会非常感激。

翻译自:Top 10 Mistakes Java Developers Make

http://www.cnblogs.com/liushaobo/p/4375493.html

Top 10 Mistakes Java Developers Make(转)的更多相关文章

  1. Top 10 Mistakes Java Developers Make--reference

    This list summarizes the top 10 mistakes that Java developers frequently make. #1. Convert Array to ...

  2. Yet Another 10 Common Mistakes Java Developers Make When Writing SQL (You Won’t BELIEVE the Last One)--reference

    (Sorry for that click-bait heading. Couldn’t resist ;-) ) We’re on a mission. To teach you SQL. But ...

  3. 100 high quality blogs from java developers

    This list collects 100 high quality blogs from Java developers from all over the world. Some of thes ...

  4. 2016年排名Top 100的Java类库——在分析了47,251个依赖之后得出的结论(16年文章)

    本文由HollisChuang 翻译自 The Top 100 Java Libraries in 2016 – After Analyzing 47,251 Dependencies . 原作者:H ...

  5. 2016 年排名 Top 100 的 Java 类库

    我们分析了GitHub中47,251个依赖,从中找出了排名前一百的Java类库,让我们看看谁在前面,谁在后面. 我们在漫长的周末的消遣方式就是浏览GitHub并且搜索流行的Java类库.我们决定把其中 ...

  6. Top 10 Books For Advanced Level Java Developers

    Java is one of the most popular programming language nowadays. There are plenty of books for beginne ...

  7. Watch out for these 10 common pitfalls of experienced Java developers & architects--转

    原文地址:http://zeroturnaround.com/rebellabs/watch-out-for-these-10-common-pitfalls-of-experienced-java- ...

  8. Top 10 Questions about Java Exceptions--reference

    reference from:http://www.programcreek.com/2013/10/top-10-questions-about-java-exceptions/ This arti ...

  9. Top 10 Methods for Java Arrays

    作者:X Wang 出处:http://www.programcreek.com/2013/09/top-10-methods-for-java-arrays/ 转载文章,转载请注明作者和出处 The ...

随机推荐

  1. Win7安装vs2010失败

    提示: ------------------------------------------------------------------------------------------------ ...

  2. Effective C++_笔记_条款02_尽量以const、enum、inline替换#define

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 这个条款或许改为“宁可以编译器替换预处理器”比较好,因为或许#d ...

  3. jquery用div模拟一个下拉列表框

    原文 jquery用div模拟一个下拉列表框 今天分享一个用我自己用jquery写的,用div模拟下拉列表select,这个效果网上有很多,但是写一个有自己思路的代码效果,更有成就感,先看截图: 自我 ...

  4. ASIO攻破!!!----转

    from:http://www.cppblog.com/shanoa/archive/2009/06/26/88606.aspx 花了足足3天时间,外加1天心情休整,终于在第5天编写出了一个能运行的基 ...

  5. 别动我的奶酪:CSV文件数据丢零现象及对策

    CSV文件在读入EXCEL时,对于前面有零的数据项,比如电话号码,会自作聪明地丢掉那个零. 比如,我有一个北京客户,其号码为01059178888,如果这是通过CSV文件来的数据,在EXCEL中打开时 ...

  6. hdu 4090 GemAnd Prince

    题目大意: 别人说是消消看,至于你玩没玩过.反正我是没玩过的. 就是选择一个钻石,可以消除与它相连的所有钻石.并获得 消除数量*消除数量  的分 思路: 直接暴搜,然后用一个cnt数组表示每一种钻石剩 ...

  7. Python 学习入门(23)—— 进程

    本文介绍Python的os包中有查询和修改进程信息的函数,Python的这些工具符合Linux系统的相关概念,所以可以帮助理解Linux体系. 1. 进程信息 os包中相关函数如下: uname()  ...

  8. Codeforces Round #218 (Div. 2)

    500pt, 题目链接:http://codeforces.com/problemset/problem/371/A 分析:k-periodic说明每一段长度为k,整个数组被分成这样长度为k的片段,要 ...

  9. javascript (十三) 函数

    JavaScript 函数语法 函数就是包裹在花括号中的代码块,前面使用了关键词 function: function functionname() { 这里是要执行的代码 } 当调用该函数时,会执行 ...

  10. Guava学习笔记:EventBus(转)

    EventBus是Guava的事件处理机制,是设计模式中的观察者模式(生产/消费者编程模型)的优雅实现.对于事件监听和发布订阅模式,EventBus是一个非常优雅和简单解决方案,我们不用创建复杂的类和 ...