《Effective Java》(23~25)阅读笔记

来源:互联网 发布:java去掉括号内容 编辑:程序博客网 时间:2024/06/06 09:21

接着上期继续看本书高质量编码建议23~25条的阅读笔记

23.请不要在新代码中使用原生态类型

       从这条开始涉及泛型相关的点。

  从JDK5开始Java新增了“泛型”新特性,例如:List<String>,在这之前则只有List不会限定类型。

  如今的JDK版本中还是可以写原生类型,但这会带来隐藏的不安全问题。如果在声明一个列表变量时不使用泛型而使用原生类型,如下:

public class Main {    public static void main(String[] args) throws Exception{        List list = new ArrayList();        list.add("hello");        list.add(2);    }}
可以看到可以插入任意类型的数据。如果使用泛型:

public class Main {    public static void main(String[] args) throws Exception{        List<String> list = new ArrayList<String>();        list.add("hello");        //list.add(2);  //编译期就会出错    }}
简而言之,使用泛型相对“安全”,从一开始就能限定数据类型,防止之后不小心插入了错误的类型,而对于原生态类型则不会检查插入的类型,有可能在以后插入了其他类型而只有在运行时才抛出异常,所以鼓励使用泛型。

24.消除非受检警告

在使用泛型时,常常会不可避免的出现一些警告,这些警告可能并不会引起开发人员的注意,例如:

我们应该在代码中尽量消除警告,如果无法消除警告,同时可以证明引起警告的代码是类型安全的,可以使用@SuppreWarnings(“unchecked”)注解,并在注释中加以解释。

25.列表优先于数组

这条建议可引申出列表和数组的区别是什么,列表的内部实现。

  首先数组是协变的,这里的“变”指的是数据类型,而不是说数组的长度,数组的长度当然从一开始就确定不可改变,但对于以下代码确实合法的:

public class Main {    public static void main(String[] args) throws Exception{        Object[] objects = new Long[1];        objects[0] = "hello world";        System.out.println(objects[0]);    }}
但合法仅存在于编译时期,在运行时会抛出以下错误:
 泛型则是不可变的,这个不可变指的也是数据类型例如以下代码:

这段代码在编译期就会报错。综上,利用数组只有在运行时才会报错,利用列表在编译时就会报错,我们当然希望在错误能在编译时尽早发现。

  大家可能都试图写过“泛型数组”:

      List<String>[] lists = new ArrayList<String>[1]; 

但是却发现是错误的,编译时抛出Generic array creation错误,并且一时难以想象为什么不能创建泛型数组,书中举了以下例子来说明:


 List<String>[] lists = new ArrayList<String>[1];    //先假设能创建泛型数组
List<Integer> intList = Arrays.asList(42);  //Integer列表
Object[] objects  = lists;  //根据数组的“协变性”是合法的,例如上面提到的Object[] objects = new Long[1]
objects[0] = intList;   //List<String>和List<Integer>在运行时类型会被擦除为List
String s = lists[0].get(0); //上一步操作过后,实际上取出的是一个initList,即取出是一个Integer 

假设第一步不会报错,那么上面的例子在编译时就不会出错,但一到了运行时最后一句话就会抛出ClassCastException异常,也就是说与其在运行时出错,不如将它提前到编译时即不允许创建泛型数组。这就是为什么创建泛型数组是非法的原因:因为它不是类型安全的。要是它合法,编译器在其他正确的程序中发生的转换就会在运行时失败,并出现一个ClassCastExcetion异常。这就违背了泛型系统提供的基本保证。

  不过有一个例外,以下的创建方式却是合法的:

        List<?>[] lists = new ArrayList<?>[1]; 

泛型在运行时它的类型会被擦除,也就是说泛型是不可具体化的,它在运行时所包含的信息比它在编译时所包含的信息更少。唯一可具体化的参数化类型就是无限制的通配符类型,也就是上面提到的例子如List<?>。

此条目几乎一直在说数组和泛型不能很好的配合使用,如果遇到泛型的情况,应该首先考虑列表。



原创粉丝点击