Java Generics and Collections-8.1
8.1 Take Care when Calling Legacy Code
通常,泛型都是在编译时检查的,而不是运行时。便意识检查可以提早通知错误,而不至于到运行时才出问题。
但有时后编译时检查不一定就坚不可摧,因为有时我们在运行时才能之道具体类型。
(唉,翻译水平有限,还是看代码吧)
package java_generics_collections.chap08;
import java.util.ArrayList;
import java.util.List;
/**
* Created by jintaox on 2016/3/21.
*/
public class LegacyLibrary {
public static void addItems(List list) {
list.add(new Integer(1));
list.add("two");
}
public static List getItems() {
List list = new ArrayList();
list.add(new Integer(3));
list.add("four");
return list;
}
}
使用这段代码的客户端被告知item永远是整数。
package java_generics_collections.chap08;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
/**
* Created by jintaox on 2016/3/21.
*/
public class NaiveClient {
public static void processItems() {
List<Integer> list = new ArrayList<>();
LegacyLibrary.addItems(list);
List<Integer> list2 = LegacyLibrary.getItems();//unchecked warnings
//sometime later可能过了很久才打算使用list中的数据
int s = 0;
for (int i : list) {
s += i;//class cast exception
}
for (int i : list2) {
s += i;//class cast exception
}
}
@Test
public void test_processItems() throws Exception {
processItems();
}
}
当我们对这段代码跑测试的时候,异常如下:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at java_generics_collections.chap08.NaiveClient.processItems(NaiveClient.java:18)
at java_generics_collections.chap08.NaiveClient.test_processItems(NaiveClient.java:28)
...
也就是说我们从集合中拿出数据并把它当作`Integer`来用的时候,它抛出了异常,也就是说错误定位我们只能快速到达这里,但究其原因是因为我们在插入的时候,插入了一个`String`类型,
而我们很难定位到这里,只能从头开始读代码。
来看另一个客户端(以下代码是可以通过编译检查)
package java_generics_collections.chap08;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Created by jintaox on 2016/3/21.
*/
public class WaryClient {
public static void processItems() {
List<Integer> list = new ArrayList<>();
List<Integer> view = Collections.checkedList(list, Integer.class);
LegacyLibrary.addItems(view);
List<Integer> list2 = LegacyLibrary.getItems();//unchecked
for (int i : list2) {
//class case exception
System.out.println(i);
}
}
@Test
public void test_processItems() throws Exception {
processItems();
}
}
在这个客户端里面,我们使用了工具类`Collections`中的`checkedList`方法,还是先看运行结果吧
java.lang.ClassCastException: Attempt to insert class java.lang.String element into collection with element type class java.lang.Integer
at java.util.Collections$CheckedCollection.typeCheck(Collections.java:3037)
at java.util.Collections$CheckedCollection.add(Collections.java:3080)
at java_generics_collections.chap08.LegacyLibrary.addItems(LegacyLibrary.java:12)
at java_generics_collections.chap08.WaryClient.processItems(WaryClient.java:16)
at java_generics_collections.chap08.WaryClient.test_processItems(WaryClient.java:27)
看,我们一下就定位到了插入的地方,这样就大大加快我们定位错误的速度。
`checkedList`方法的api介绍: Returns a dynamically typesafe view of the specified collection.
checkedList
源码分析待定
加油,我要做Java专家。