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专家。

posted @ 2016-03-21 15:32  JintaoXIAO  阅读(281)  评论(0编辑  收藏  举报