Java开发者易犯错误Top10

摘要:在Java中,有些事物如果不了解的话,很容易就会用错,如数组转换为数组列表、元素删除、Hashtable和HashMap、ArrayList和LinkedList、Super和Sub构造函数等,如果这些对你来说是陌生的,你可以在本文中了解它们。

本文总结了Java开发者经常会犯的前十种错误列表。

Top1. 数组转换为数组列表

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

[java] view
plain
copy

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

Arrays.asList()将返回一个数组内部是私有静态类的ArrayList,这不是java.util.ArrayList类,java.util.Arrays.ArrayList类有set()、 get()、 contains()方法,但是没有任何加元素的方法,因此它的大小是固定的。你应该这么做来创建一个真正的数组:

[java] view
plain
copy

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

ArrayList的构造函数能够接受一个集合类型,这也是java.util.Arrays.ArrayList的超级类型。

Top2. 检查一个数组包含一个值

开发者经常这么做:

[java] view
plain
copy

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

代码可以工作,但是没有必要首先转换列表到Set,转换一个列表到一个Set需要额外的时间。因此你可以把它简化为:

[java] view
plain
copy

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

[java] view
plain
copy

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

第一个比第二个更具可读性

Top3. 在一个循环中从一个列表里删除一个元素

考虑下面删除元素的代码在迭代中的结果:

[java] view
plain
copy

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

输出是:

[java] view
plain
copy

  1. [b, d]

该方法有一个严重的问题,当一个元素被删除时,列表收缩的大小以及指针改变了。所以想要在循环内利用指针删除多个元素是无法正常进行的。

这种情况下使用迭代器才是正确的方法,foreach循环在Java中的工作像是一个迭代器,但实际上并不是,考虑下面的代码:

[java] view
plain
copy

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

它会报出ConcurrentModificationException异常。

相反下面这个就可以正常工作。

[java] view
plain
copy

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

.next()必须在.remove()之前被调用。在foreach循环中,编译器将在删除元素操作之后调用.next(),这也是导致ConcurrentModificationException异常的原因,你可以点击此处查看ArrayList.iterator()的源代码。

Top4. Hashtable vs HashMap

根据算法的常规,Hashtable是对数据结构的称呼。但是在Java中,数据结构的名称是HashMap。Hashtable和HashMap关键不同之一是Hashtable是同步的。

关于这一点可查看以下两个链接:

HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap

Map问题Top10

Top5. 使用集合的原始类型

在Java中,原始类型和无限制的通配符类型很容易被混淆。以Set为例,Set是原始类型,而Set(?)则是无限制的通配符类型。

考虑下面的代码,以一个原始类型List作为参数:

[java] view
plain
copy

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

该代码会抛出一个异常:

[java] view
plain
copy

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

使用原始类型集合是危险的,因为原始类型集合跳过了泛型类型检查,也不安全。Set、Set<?>和Set<Object>之间有很大的不同。详细可查看

Raw type vs. Unbounded wildcardType
Erasure

Top6. 访问级别

开发者经常对类域使用public,这很容易通过直接引用获得域值,但这是一个非常糟糕的设计。根据经验来说是给予成员的访问级别越低越好。

详细情况可点击查看Java中成员访问级别:public、protected、private

Top7.ArrayList VS LinkedList

如果你不知道ArrayList和LinkedList之间的区别时,你可能会经常的选用ArrayList,因为它看起来看熟悉。然而它们之间有巨大的性能不同。简单的来说,如果有大量的添加/删除操作,并且没有很多的随机存取操作时,LinkedList应该是你的首选。如果您对此不是很了解的话,点此此处查看更多关于它们性能的信息。

Top8. Mutable VS Immutable

Immutable对象有很多优势,比如简单、安全等等。但它要求每一个不同的值都需要有一个不同的对象,而太多的对象可能会导致垃圾收集的高成本。所以对Mutable和Immutable的选择应该有一个平衡点。

一般来说,Mutable对象用于避免产生过多的中间对象,经典的例子是连接大量的字符串数。如果你使用Immutable字符串,那么会产生很多符合垃圾收集条件的对象。这对CPU是浪费时间和精力的,当其可以使用Mutable对象作为正确的解决方案。(如StringBuilder)

[java] view
plain
copy

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

这里还有一些其他Mutable对象可取的情况。例如mutable对象传递到方法中允许你在不跳过太多语法的情况下收集多个结果。另一个例子是排序和过滤,你可以构建一个带有原有集合的方法,并返回一个已排序的,不过这对大的集合来说会造成更大的浪费。

推荐阅读:为什么字符串是Immutable?

Top9. Super和Sub构造函数

这个编译错误是因为默认的Super构造函数是未定义的。在Java中,如果一个类没有定义一个构造函数,编译器会默认的为类插入一个无参数构造函数。如果一个构造函数是在Super类中定义的,这种情况下Super(String s),编译器不会插入默认的无参数构造函数。

另一方面,Sub类的构造函数,无论带不带有参数,都会调用无参数的Super构造函数。

编译器在Sub类中试图将Super()插入到两个构造函数中,但是Super默认的构造函数是没有定义的,编译器才会报错。如何解决这一问题?你只需在Super类中添加一个Super()构造函数,如下所示:

[java] view
plain
copy

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

或移除自定义的Super构造函数,又或者在Sub函数中添加super(value)。

这方面想了解更多的可以点击此处查看。

Top10. ""或构造函数?

字符串可以通过两种方式创建:

[java] view
plain
copy

  1. //1. use double quotes
  2. String x = "abc";
  3. //2. use constructor
  4. String y = new String("abc");

它们之间有何不同?下面的例子可以给出答案:

[java] view
plain
copy

  1. String a = "abcd";
  2. String b = "abcd";
  3. System.out.println(a == b);  // True
  4. System.out.println(a.equals(b)); // True
  5. String c = new String("abcd");
  6. String d = new String("abcd");
  7. System.out.println(c == d);  // False
  8. System.out.println(c.equals(d)); // True

关于它们如何在内存中分布的更多细节可以查看《使用""或构造函数创建Java字符串》。

推荐阅读:

Constructors of Sub and Super Classes in Java?

How Developers Sort in Java?

How to Convert Array to ArrayList in Java?

Java Type Erasure Mechanism

原文来自:programcreek

时间: 2024-08-02 11:03:25

Java开发者易犯错误Top10的相关文章

[golang 易犯错误] golang 局部变量初始化:=的陷阱

我们知道,golang中局部变量初始化方法(使用“:=”创建并赋值),让我们在使用变量时很方便.但是,这也是易犯错误的地方之一.特别是这个初始化符还支持多个变量同时初始化,更特别的是它还支持原有变量赋值和新变量创建并赋值同时进行!也就是说如果有部分变量不存在的而另外一些是已声明好的,用:=来初始化部分变量同样有效.这其实也没什么,更方便了嘛.但是,go的好多语句还支持局部前置语句,比如在if,for,switch等语句的初始化条件语句中.在这些地方,当你以为使用了原有变量的时候,实际上go已经为

样式易犯错误

1,可使字和图标对其 .logo_right img{ margin-right:10px; vertical-align: middle; 如: 2,a标签样式 .nav a:link ,.nav a:visited{ color:rgb(255,255,255); font-size:20px; text-decoration:none; } .nav a:hover ,.nav a:active{ color:#C00; text-decoration:none; font-size:20

初始化赋值时a = b = 常数 的易犯错误

1 #include <stdio.h> 2 #include <stdlib.h> 3 int main() 4 { 5 int a,b; a=b=2; //成功 6 //int a = b = 2;失败 7 printf("%d %d",a,b); 8 system("pause"); 9 return 0; 10 } 新手注意直接初始化变量的 int a = b = 2这样的写法会导致编译失败. 如何能让这个语句正确呢,那就在前面声明好

Python 基础教程 和 易犯错误(文本处理)

一:基础教程 (1)文件I/O  非常类似于 c语言:IO在计算机中指Input/Output,也就是输入和输出.由于程序和运行时数据是在内存中驻留,由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘.网络等,就需要IO接口. spath="D:/download/baa.txt" f=open(spath,"w") # Opens file for writing.Creates this file doesn't exist. f.write(&

编程中易犯错误汇总:一个综合案例.md

# 11编程中易犯错误汇总:一个综合案例 在上一篇文章中,我们学习了如何区分好的代码与坏的代码,如何写好代码.所谓光说不练假把式,在这篇文章中,我们就做一件事——一起来写代码.首先,我会先列出问题,然后要求读者自己写一份答案:然后,我会给出我写的代码:最后,我们还会以这个问题为例,讨论编程中常见的错误. ## 1 问题描述 在[这个](http://wiki.openhatch.org/index.php?title=Scrabble_challenge)页面中,有一道Python相关的练习题,

Java开发者常犯的十个错误

翻译自:Top 10 Mistakes Java Developers Make 文章列出了Java开发者最常犯的是个错误. 1.将数组转换为ArrayList 为了将数组转换为ArrayList,开发者经常会这样做: List<String> list = Arrays.asList(arr); Arrays.asList()会返回一个ArrayList,但这个ArrayList是Arrays的私有静态类,不是java.util.ArrayList.java.util.Arrays.Arra

一个Java增强型for循环的易犯错误,你注意到了吗?

我们知道,在Java语言中有三种循环,分别是while循环,do-while循环和for循环.其实,从JDK1.5开始,又引入了一种增强型for循环,这种新型的for循环主要是用来遍历数组或集合的,它的格式非常简单,下图展示了增强型for循环的基本结构: 增强型for循环被设计出来就是为了遍历数组或者是集合的,所以在循环中都会指定一个数组或者是集合.为了方便程序员编码,增强型for循环不再通过"下标"的形式访问数组或集合中的元素,而是把依次从数组或集合取出元素,并命名为i,这样,程序员

Python初学的易犯错误

当初学 Python 时,想要弄懂 Python 的错误信息的含义可能有点复杂.这里列出了常见的的一些让你程序 crash 的运行时错误. 1)忘记在 if , elif , else , for , while , class ,def 声明末尾添加 :(导致 “SyntaxError :invalid syntax”) 该错误将发生在类似如下代码中: ? 1 2 if spam == 42     print('Hello!') 2)使用 = 而不是 ==(导致“SyntaxError: i

OpenERP新手易犯错误之res.model

接触OpenERP的人都感慨资料之少,尤其是XML中,出点错是相当郁闷的.尤其是新手.什么都别说了,有图有真相. 视图中关联模型name="model" ,而动作中name="res_model", 筒子们,有木有注意到,这可是一个深坑. 会报错,比如:关联性错误,nonetype