翻译自:Top 10 Mistakes Java Developers Make

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

1.将数组转换为ArrayList

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

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

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

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

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

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

开发者经常这样做:

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

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

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

或者

for(String s: arr){
if(s.equals(targetValue))
return true;
}
return false;

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

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

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

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);

输出如下:

[b, d]

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

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

for (String s : list) {
if (s.equals("a"))
list.remove(s);
}

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

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作为参数的代码:

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);
}

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

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)。

String result="";
for(String s: arr){
result = result + s;
}

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

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


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

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

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

10.”“还是构造函数?

有两种方式构造字符串:

//1. 利用双引号
String x = "abc";
//2. 利用构造函数
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

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

将来的工作

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

翻译自:Top 10 Mistakes Java Developers Make

Java开发者常犯的十个错误的更多相关文章

  1. PHP开发者常犯的MySQL错误

    PHP开发者常犯的MySQL错误   数据库是WEB大多数应用开发的基础.如果你是用PHP,那么大多数据库用的是MYSQL也是LAMP架构的重要部分. PHP看起来很简单,一个初学者也可以几个小时内就 ...

  2. python开发者常犯的10个错误(转)

    常见错误1:错误地将表达式作为函数的默认参数 在Python中,我们可以为函数的某个参数设置默认值,使该参数成为可选参数.虽然这是一个很好的语言特性,但是当默认值是可变类型时,也会导致一些令人困惑的情 ...

  3. SQLSERVER DBA容易犯的十个错误

    SQLSERVER DBA容易犯的十个错误 翻译自:http://sqlsentry.tv/top-10-administrative-mistakes-on-sql-server/ 除了排名前十的错 ...

  4. Verilog与SystemVerilog编程陷阱:怎样避免101个常犯的编码错误

    这篇是计算机类的优质预售推荐>>>><Verilog与SystemVerilog编程陷阱:怎样避免101个常犯的编码错误> 编辑推荐 纠错式学习,从"陷阱 ...

  5. Java开发者易犯错误Top10

    本文总结了Java开发者经常会犯的前十种错误列表. Top1. 数组转换为数组列表 将数组转换为数组列表,开发者经常会这样做: List<String> list = Arrays.asL ...

  6. 【GoLang】50 个 Go 开发者常犯的错误

    1. { 换行:   Opening Brace Can't Be Placed on a Separate Line 2. 定义未使用的变量:  Unused Variables 2. import ...

  7. 由一个Servlet 看java入门常犯的几个错误

    安装完java环境后,cmd-javac 报错           ------------->环境变量配错了,最后全配成系统变量,ok了 能浪费一天的时间 写一个最简单的Servlet ,to ...

  8. PHP开发者常犯的10个MySQL错误

    原文出处: kaiyuanba   欢迎分享原创到伯乐头条 数据库是WEB大多数应用开发的基础.如果你是用PHP,那么大多数据库用的是MYSQL也是LAMP架构的重要部分. PHP看起来很简单,一个初 ...

  9. Java中数组转为List三种情况的优劣对比,常犯的类型转换错误原因解析

    一.最常见方式(未必最佳)通过 Arrays.asList(strArray) 方式,将数组转换List后,不能对List增删,只能查改,否则抛异常. 关键代码:List list = Arrays. ...

随机推荐

  1. Flex-Security权限控制框架

    转自:http://code.google.com/p/flex-security/ flex UI组件权限控制框架 一.快速开始 1) 下载并添加flex_security.swf在你的flex l ...

  2. UNIX/Linux网络编程基础:应用层协议简介

    目录 1.HTTP协议 2.FTP协议 3.TELNET协议 4.NFS协议 1.HTTP协议 应用层协议HTTP协议是Web的核心.HTTP协议在Web的客户程序和服务器程序中得以实现,运行在不同系 ...

  3. 项目源码--JAVA基于LBS地理位置信息应用的服务端

    技术要点: 1. LBS应用框架服务端实现 2. JAVA服务端技术 3. MYSQL数据库技术 4. 源码带详细的中文注释 ......   详细介绍: 1. LBS应用框架服务端实现 此套源码是基 ...

  4. jquery操作cookie {分享}

    web开发过程中如果网站有一部分信息是存储在cookie中并与服务器交互的话,那么前台有时就会遇到需要对cookie中信息进行操作的情况,一个最典型的例子就是在前台判断用户是否登录过当前所访问的网站. ...

  5. A*算法解决八数码问题 Java语言实现

    0X00 定义 首先要明确一下什么是A*算法和八数码问题? A*(A-Star)算法是一种静态路网中求解最短路径最有效的直接搜索方法也是一种启发性的算法,也是解决许多搜索问题的有效算法.算法中的距离估 ...

  6. iOS UIImage DownLoad图片的下载缓存全部在此

    iOS图片的下载缓存全部在此 分类: iOS编程 -- : 2075人阅读 评论() 收藏 举报 注意: 我的文章只写给自己看 ------------------------------------ ...

  7. Unity3D 使用 UI 的 Grid Layout Group 组件。

    1.首先创建一个容器,用于存放列表项的内容. 这里使用 Panel 来做为容器. 这里要注意! “Grid Layout Group”是要增加在容器的游戏对象里. 同时,只有容器对象的子对象才有排列效 ...

  8. Swift - 使用NSNotificationCenter发送通知,接收通知

    转载自:http://www.mamicode.com/info-detail-1069228.html 标签: 1,通知(NSNotification)介绍 这里所说的通知不是指发给用户看的通知消息 ...

  9. struts1标签-<html:radio> 使用注意事项

    struts1标签-<html:radio> 使用注意事项 1.默认选中效果 在后台XxxForm中写入如下代码,可保证默认选中效果实现: @Override public void re ...

  10. linux ----虚拟机无法与本地机通信

    1.以前能正常通信,电脑重启或休眠唤醒后, 虚拟机centos无法与本地主机通信,但能ping通同一局域网的其他主机,也能与外网通信 故障原因: 未找到 解决办法: 1.重启电脑 2.重启xshell ...