文章列出了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. PreTranslateMessage和TranslateMessage区别

    PreTranslateMessage是消息在送给TranslateMessage函数之前被调用的,绝大多数本窗口的消息都要通过这里,比较常用,当需要在MFC之前处理某些消息时,常常要在这里添加代码. ...

  2. MFC自绘控件学习总结第二贴

    首先感谢大家对第一帖的支持,应一些网友烈要求下面我在关于上一贴的一些补充和说明(老鸟可以无视)这一贴是实战+理论不知道第一帖的先看第一帖:http://topic.csdn.net/u/2011071 ...

  3. DELPHI XE7 新的并行库

    DELPHI XE7 的新功能列表里面增加了并行库System.Threading, System.SyncObjs. 为什么要增加新的并行库? 还是为了跨平台.以前要并行编程只能从TThread类继 ...

  4. 14.9 InnoDB Row Storage and Row Formats InnoDB 行存储和行格式:

    14.9 InnoDB Row Storage and Row Formats InnoDB 行存储和行格式: 14.9.1 Overview of InnoDB Row Storage 14.9.2 ...

  5. Java设计模式之适配器模式(Adapter Pattern)

    Adapter Pattern的作用是在不改变功能的前提下转换接口.Adapter分为两类,一类是Object Adapter, 还有一类是Class Adapter.因为Class Adapter的 ...

  6. Unable to instantiate activity ComponentInfo或java.lang.ClassNotFoundException: com.ibright.herolegen

    不知道怎么回事,在libs中添加了jar包后,无法给jar包附加上源码,于是采取以下措施: 删除自动生成的依赖: 在Android Dependences目录上右击->Build Path -& ...

  7. STM32建立project库函数方法

    (1)打开keilMDK主界面能够看到project中有一个默认的project,点击这个project名字,然后选择菜单Project->Close Project,就关闭掉这个project ...

  8. Swift - 判断设备类型开发兼容的iOS应用(iPad使用分隔视图控制器)

    1,分割视图控制器(UISplitViewController) 在iPhone应用中,使用导航控制器由上一层界面进入下一层界面. 但iPad屏幕较大,通常使用SplitViewController来 ...

  9. HDU 1142 A Walk Through the Forest(dijkstra+记忆化DFS)

    题意: 给你一个图,找最短路.但是有个非一般的的条件:如果a,b之间有路,且你选择要走这条路,那么必须保证a到终点的所有路都小于b到终点的一条路.问满足这样的路径条数 有多少,噶呜~~题意是搜了解题报 ...

  10. 一个网友写的栈,问为啥不能迭代。具有__iter__ 和next方法的对象叫迭代器-七七巴巴黄页网

    一个网友写的栈,问为啥不能迭代.具有__iter__ 和next方法的对象叫迭代器-七七巴巴黄页网 一个网友写的栈,问为啥不能迭代.具有__iter__ 和next方法的对象叫迭代器 python视频 ...