java常见十大误区

一、转化数组为ArrayList

一般开发者转化数组为ArrayList的方式为java

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

Arrays.asList()会返回一个ArrayList,而这个ArrayList是Arrays类的静态内部类,不是java.util.ArrayList。数组

这个类有get()、set()和contains()方法,但却没有任何能够添加元素的方法。正确的作法能够这样作安全

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

二、检查数组里面是否包含某个元素

部分开发者会这样实现数据结构

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

结果是对的,可是没有必要转化为Set,这反而会花费更多时间,能够简单这样实现函数

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

或者性能

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

补充:第一种相比第二种可读性会高一些。ui

三、数组中循环删除元素

分析一下下列代码:this

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]设计

由于当数组删除一个元素后,它的长会缩小,index至关于向后移动一位,这是个严重的问题。当你想经过index来删除多个元素时候,这种方法是不可取的。

你也许知道用迭代器来删除是没问题的,而且java中有一类for语句原理就是使用迭代器。但实际你想用这类for语句来代替迭代器进行删除也是不行的,以下代码

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()以前被调用。而在for循环中,编译器会在元素被remove以后调用next(),所以就会抛出ConcurrentModificationException异常。

四、hashtable和hashmap

java中有两类,HashTable和HashMap,二者的数据结构是一致的(哈希表),而后二者的区别是:HashTable是同步的。

因此HashTable是线程安全的,HashMap不是线程安全的。

提示:也可使用ConcurrentHashMap来保证线程安全,ConcurrentHashMap使用分段锁(segment)的原理,效率上会高一些。

五、集合中原生态类型(raw type)的使用

在java中,开发者一般把原生态类型(raw type)一般和无界通配符类型(unbounded wildcard type)弄混。拿Set来举例子,Set是原生态类型,而Set<?>是无界通配符类型。

以下代码使用了原生态类型

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

原生态类型会越过泛型的校验,是不安全的。

六、访问级别

有的开发者将类某些属性直接定义为public,这很容易经过外部访问,但绝对是不好的设计。根据拇指规则,最佳作法应该是尽可能减小属性的访问级别。

七、LinkList vs ArrayList

不少开发者都习惯使用ArrayList,可能ArrayList相对来讲比较熟悉的缘故,其实ArrayList和LinkList仍是存在很大的区别。简而言之,LinkList应该在有大量增删操做且无随机访问操做时候使用。

八、可变(mutable) vs 不可变(immutable)

不可变对象有不少优势,好比简单、安全等。但对于多个值则须要多个不一样的对象来表示,对象过多时,会消耗不少的GC资源。

一般的,可变对象可用来避免产生过多的对象。以下代码中使用了不可变对象,那么执行过程当中将会产生不少的String,消耗不少时间和cpu性能。若是换成可变对象(StringBuilder等),将会好不少。

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

九、父子类的构造函数

class Super {
        String s;

        public Super(String s) {
            super();
            this.s = s;
        }

    }

    class Sub extends Super {

        public Sub(String s) {
        }

        public Sub() {

        }
    }

上述代码会出错,是由于父类默认构造函数没有定义。在java中,若是一个类没有定义构造函数,则编译器会给它构造默认的无参构造函数。若是类中定义了构造函数,那么编译器将不会给它插入默认构造函数。这个正是上述父类的遇到的状况。

在子类中的两个构造函数中,编译器试图插入父类的默认构造函数super(); ,然而并未找到,所以编译出错。

十、"" or Constructor

字符串能够经过两种方式创建

//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
相关文章
相关标签/搜索