Java开发者易犯错误Top10(java开发中遇到的问题及解决方案)

createh53个月前 (02-01)技术教程38

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

Top1. 数组转换为数组列表

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

List list = Arrays.asList(arr);

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

ArrayList arrayList = new ArrayList(Arrays.asList(arr));

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

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

开发者经常这么做:

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

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

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

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

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

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

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

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

输出是:

[b, d]

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

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

ArrayList list = new ArrayList(Arrays.asList("a", "b", "c", "d"));
 
for (String s : list) {
	if (s.equals("a"))
		list.remove(s);
}

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

ArrayList list = new ArrayList(Arrays.asList("a", "b", "c", "d"));
Iterator iter = list.iterator;
while (iter.hasNext) {
	String s = iter.next;
 
	if (s.equals("a")) {
		iter.remove;
	}
}

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

Top4. Hashtable vs HashMap

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

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

Top5. 使用集合的原始类型

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

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

public static void add(List list, Object o){
	list.add(o);
}
public static void main(String[] args){
	List list = new ArrayList;
	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 ...

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

Top6. 访问级别

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

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

Top7.ArrayList VS LinkedList

相关文章

Java:在Java中使用私有接口方法(java私有的)

  接口是定义一组方法及其签名的契约, 它可以由任何类及其在该类中实现的方法进行扩展。从Java9 开始,你可以在接口中使用私有方法。  由于私有方法只能在定义它的接口内访问,因此你可以利用这些方法编...

思考:Java对象之生(java中对象的概念的理解)

内存、性能是程序永恒的话题,实际开发中关于卡顿、OOM也经常是打不完的两只老虎,关于卡顿、OOM的定位方法和工具比较多,这篇文章也不打算赘述了,本章主要是来整理一下JVM的内存模型以及Java对象的生...

内部类Java(内部类定义)

概念将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。什么时候使用内部类一个事物内部还有一个独立的事物,内部的事物脱离外部的事物无法独立使用比如汽车只有一个发动机,电脑只有一...

Java设计模式-单例模式(java单例模式原理)

单例模式定义:它确保一个类只有一个实例,并提供一个全局访问点来访问该实例。单例模式主要分为两大类:饿汉式和懒汉式,懒汉式又分为 单线程下的普通懒汉式,多线程下的双重校验锁、静态内部类、枚举。单例模式的...

用GitHub创建自己的Maven私有仓库

【Github上创建仓库】首先,在GitHub上创建自己的仓库(mvn-repo):【配置本地setting文件】找到本地的maven settings文件,配置server:有两种选择,可以选择配置...

终于搞懂了 Java 8 的内存结构,再也不纠结方法区和常量池了

java8内存结构图虚拟机内存与本地内存的区别Java虚拟机在执行的时候会把管理的内存分配成不同的区域,这些区域被称为虚拟机内存,同时,对于虚拟机没有直接管理的物理内存,也有一定的利用,这些被利用却不...