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

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

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

Top1. 数组转换为数组列表

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

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

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

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

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

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

开发者经常这么做:

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

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

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

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

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

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

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

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

输出是:

  1. [b, d]

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

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

  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异常。

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

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

  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. }

该代码会抛出一个异常:

  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)

  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()构造函数,如下所示:

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

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

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

Top10. ""或构造函数?

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

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

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

  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

最新文章

  1. ZeroMQ接口函数之 :zmq_proxy – 开始ZMQ内置代理
  2. python编程(一)汉诺塔
  3. 7.5 [bx+idata] 书中错误
  4. Java Web项目里开发获取上个页面连接地址的问题
  5. which命令
  6. QSplashScreen类实现Qt程序启动画面
  7. python -i filename
  8. Sparse Filtering
  9. final、finally、finalize
  10. &lt;经验杂谈&gt;介绍Js简单的递归排列组合
  11. 使用SecureCRTP 连接生产环境的web服务器和数据库服务器
  12. ROS_Kinetic_13 ROS数据录制与回放
  13. U68364 _GC滑迷宫
  14. Xamarin 学习笔记 - Layout(布局)
  15. Java 获取当前日期的四种方法
  16. Error: Invalid or corrupt jarfile
  17. 【Java集合系列】目录
  18. ipone 5s上,字体rem遇到的问题
  19. html dom之iframe对象
  20. Windows下 VS2015编译boost1.62

热门文章

  1. HDU 1207 汉诺塔II (简单DP)
  2. LIS LCS LCIS (主要过一遍,重在做题)
  3. Cg(C for Graphic)语言语义绑定方法(转)
  4. ErrorObject OpenAsync(Action&lt;ErrorObject&gt;arg_fnRet)
  5. Django学习:url路由系统
  6. 黑客攻防技术宝典web实战篇:Web 应用程序技术习题
  7. PHP函数技巧篇
  8. 7.2 Collection和Iterator接口
  9. 微信环境支付宝服务窗环境app手机浏览器pc端混合判断
  10. Xml文档数据提取到Excel表中