新手都容易犯这个错误,先看代码:
List<String> list = new ArrayList<String>();
for(int i=0;i<list.size();i++){
System.err.println(list.get(i).toString());
}
if(list!=null){
System.out.println("不为空");
}else{
System.out.println("为空,需进行赋值判断");
}
改代码如下:
if(!list.isEmpty()){
System.out.println("不为空");
}else{
System.out.println("为空,需进行赋值判断");
}
改成以上代码,ok了!这个错误就是对集合判断是否为Null出错,需要加上list.size()>0或者使用才可以list.isEmpty()才行。
List list=new ArrayList();
这样的list其实不为null,但是判断size的时候,实则是为0,所以判断集合的时候,一定记得要双重判断。即list!=null && list.size()>0才好。
PS:list.isEmpty()和list.size()==0 没有区别, isEmpty()判断有没有元素,而size()返回有几个元素,如果判断一个集合有无元素,建议用isEmpty()方法,该方法简单、清晰明了!
public class ListGu {
private static List<String> list;
public static void main(String[] args) {
setList();
}
//对集合重新赋值
private static void setList() {
for(int i=0;i<10;i++){
list.add(String.valueOf(i));
}
for(int i=0;i<list.size();i++){
System.err.println(list.get(i).toString());
}
}
}
上面的代码乍一看,没毛病,可是一运行:
按住ctrl键,点List进去看底层源码:
擦,竟然是个接口,竟然没new对象就直接赋值。发现问题,及时改正:
public class ListGu {
private static List<String> list;
public static void main(String[] args) {
setList();
}
//对集合重新赋值
private static void setList() {
for(int i=0;i<10;i++){
list = new ArrayList<String>(); //new对象
list.add(String.valueOf(i));
}
for(int i=0;i<list.size();i++){
System.err.println(list.get(i).toString());
}
}
}
运行代码,竟然不是预想中的结果:
这是为什么呢?现在我们知道,使用List时,需要new对象,仔细一看,擦,竟然在循环里new对象,这种错误,特别容易犯!!
public static void main(String[] args) {
List<List<String>> list=new ArrayList<>();
List<String> list2=new ArrayList<>();
for(int i=0;i<10;i++){
list2.add(""+i);
list.add(list2);
list2.clear();
}
// 遍历List
for(int i=0;i<list.size();i++){
System.err.println(list.get(i).toString());
}
}
乍一看以上代码,没毛病,很简单的逻辑,少new一个对象,可以达到节省优化代码,节省虚拟机内存,可是一运行,擦,竟然是这样的结果:
这个错误引起就是因为list中存储的是对象的引用,而不是对象本身。如果不清楚这一点,会常踩这个坑。该代码虽然可以达到一个对象重复使用的效果,但是因为list存储的是对象的引用,所以当list2.clear()的时候,list中的list2也会clear,这样最后得到的就只能是一堆空的集合。
Array转ArrayList(常见错误补充)
当需要把Array转成ArrayList的时候,我们经常这样做:List<String> list = Arrays.asList(arr);
假若这个时候我们需要在list
上添加删除一些东西:
public static void main(String[] args) {
String[] array = { "java", "c" };
List<String> list = Arrays.asList(array);
for (String list2 : list) {
System.err.println(list2.toString());
}
list.add("我是李逍遥");
list.add("我是林月如");
list.remove("c");
for (String list2 : list) {
System.err.println(list2.toString());
}
}
竟然执行失败??
需要注意的是:
Arrays.asList()的确会返回一个ArrayList,但是要特别注意,这个ArrayList是Arrays类的静态内部类,并不是java.util.ArrayList类。
java.util.Arrays.ArrayList类实现了set(), get(),contains()方法,但是并没有实现增加元素的方法(事实上是可以调用add方法,但是没有具体实现,仅仅抛出UnsupportedOperationException异常),因此它的大小也是固定不变的。为了创建一个真正的java.util.ArrayList,你应该这样做:
ArrayList<String> arrayList = new ArrayList<String>(Arrays.asList(arr));
ArrayList的构造方法可以接收一个Collection类型,而java.util.Arrays.ArrayList已经实现了该接口。
public static void main(String[] args) {
String[] array = { "java", "c" };
// List<String> list = Arrays.asList(array);
// for (String list2 : list) {
// System.err.println(list2.toString());
// }
// list.add("我是李逍遥");
// list.add("我是林月如");
// list.remove("c");
// for (String list2 : list) {
// System.err.println(list2.toString());
// }
ArrayList<String> list = new ArrayList<String>(Arrays.asList(array));
for (String list2 : list) {
System.err.println(list2.toString());
}
list.add("我是李逍遥");
list.add("我是林月如");
list.remove("c");
System.out.println("----------------");
for (String list2 : list) {
System.err.println(list2.toString());
}
}
add成功,remove成功!!
删除List中的一个元素
删除list中的元素,肯定要循环,先看这段代码:
public static void main(String[] args) {
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]
这个时候,肯定想到需要用迭代器,为什么循环删除list元素会导致这种错误呢?这是因为:当一个元素被删除的时候,list大小减小,然后原先索引指向了其它元素,所以如果你想在循环里通过索引来删除多个元素,将不会正确工作,如果你用foreach循环代替迭代器,代码还是执行失败,如下代码:
public static void main(String[] args) {
// ArrayList<String> list = new
//
// ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
// System.err.println(list);
//
// for (int i = 0; i < list.size(); i++) {
// list.remove(i);
// }
// System.out.println(list);
ArrayList<String> list = new
ArrayList<String>(Arrays.asList("a", "b", "c", "d"));
for (String s : list) {
if (s.equals("a"))
list.remove(s);
}
}
执行结果:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at com.kai.Array.main(Array.java:22)
所以,移除list
元素,我们一定要用迭代器:
public static void main(String[] args) {
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();
}
}
System.err.println(list);
}
执行打印:[b, c, d]
next()方法需要在remove()方法之前被调用,在foreach循环里,编译器会在删除元素操作化调用next方法,这导致了ConcurrentModificationException异常。更多详细信息,可以查看ArrayList.iterator()的源码。