1、转化数组为ArrayList
通常开发者转化数组为ArrayList的方式为
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));
2、检查数组里面是否包含某个元素
部分开发者会这样实现
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;
补充:第一种相比第二种可读性会高一些。
3、数组中循环删除元素
分析一下下列代码:
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异常。
4、hashtable和hashmap
java中有两类,HashTable和HashMap,两者的数据结构是一致的(哈希表),然后两者的区别是:HashTable是同步的。
所以HashTable是线程安全的,HashMap不是线程安全的。
提示:也可以使用ConcurrentHashMap来保证线程安全,ConcurrentHashMap使用分段锁(segment)的原理,效率上会高一些。
5、集合中原生态类型(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 ...
原生态类型会越过泛型的校验,是不安全的。
6、访问级别
有的开发者将类某些属性直接定义为public,这很容易通过外部访问,但绝对是很差的设计。根据拇指规则,最佳做法应该是尽量减少属性的访问级别。
7、LinkList vs ArrayList
很多开发者都习惯使用ArrayList,可能ArrayList相对来说比较熟悉的缘故,其实ArrayList和LinkList还是存在很大的区别。简而言之,LinkList应该在有大量增删操作且无随机访问操作时候使用。
8、可变(mutable) vs 不可变(immutable)
不可变对象有很多优点,比如简单、安全等。但对于多个值则需要多个不同的对象来表示,对象过多时,会消耗很多的GC资源。
通常的,可变对象可用来避免产生过多的对象。如下代码中使用了不可变对象,那么执行过程中将会产生很多的String,消耗很多时间和cpu性能。如果换成可变对象(StringBuilder等),将会好很多。
String result="";
for(String s: arr){
result = result + s;
}
9、父子类的构造函数
class Super {
String s;
public Super(String s) {
super();
this.s = s;
}
}
class Sub extends Super {
public Sub(String s) {
}
public Sub() {
}
}
上述代码会出错,是因为父类默认构造函数没有定义。在java中,如果一个类没有定义构造函数,则编译器会给它构造默认的无参构造函数。如果类中定义了构造函数,那么编译器将不会给它插入默认构造函数。这个正是上述父类的遇到的情况。
在子类中的两个构造函数中,编译器试图插入父类的默认构造函数super();
,然而并未找到,因此编译出错。
10、"" 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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。