`
xfei6868
  • 浏览: 68496 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Set和Map中的类型安全

阅读更多
    原帖地址http://www.javablogging.com/type_safety_in_java_set_and_map/   

    也许你们大家都仍然记得在java1.4中类型检查和集合中元素的强制转型是多么麻烦,根本没法确定代码中有多少潜在的错误。由于在java1.5中通过泛型的说明这种状况确实得到改善,并且现在的语言开始照顾到了经常打错字的程序员。泛型自身给我们带来了一种新的复杂的设置,但是好像我们有理由相信基本情况下通过这种在java的Sets和Maps中使用,并不会带来类似通配符的并发症,转换应该是安全可靠的。真的是这样吗?

    最近我遇到了一个生产代码中的bug发生在一个简单的(真的很简单的)Map的应用中,令人尴尬的是我用很多方法去调试它,结果确实......唉......一个小问题。下面的代码演示了一个bug产生前代码的一个轮廓,在真实的生活中class中代码部分是很好的而且会经常修改的,肯定要比下面的代码多的多:

import java.util.HashMap;
import java.util.Map;

public class EmployeeDataLookup {
    // A map storing relation between employee ID and name.
    private Map<Integer, String> employeeIdToName;

    public EmployeeDataLookup() {
        // Create a new EmployeeDataLookup and initialize
        // it with employee names and IDs.
        employeeIdToName = new HashMap<Integer, String>();
        addEmployee(301, "John Doe");
        addEmployee(302, "Mary Poppins");
        addEmployee(303, "Andy Stevens");
    }

    public void addEmployee(int employeeId, String employeeName) {
        employeeIdToName.put(employeeId, employeeName);
    }

    // This class is very complicated and has many other methods...

    // Lookup method for finding employee name for given employee ID.
    public String findEmployeeName(int employeeId) {
        return employeeIdToName.get(employeeId);
    }

    public static void main(String[] args) {
        // Create a EmployeeDataLookup instance
        EmployeeDataLookup employeeLookup = new EmployeeDataLookup();
        // Find the name of an employee with ID = 301
        String employeeName = employeeLookup.findEmployeeName(301);
        System.out.print("Employee 301 : " + employeeName);
    }
}


    这有什么问题呢?哦,在一个项目中功能要求发生了变化(有点惊讶,是吧?)和Map中Key的内部数据必须发生了变化。例如公司是合并的供应商之一,因此系统存储employee数据必须做出跟供应商ID兼容的例子。由于供应商用的是13位的IDs,所以我们必须java代码中Integer替换成Long。简单吧?着看起来很简单,我们用类似于eclipse的ide的重构--只要改变第7行的Map key的定义Integer变为Long,让编辑器显示所有的错误,然后修复他们!五分钟搞定:

import java.util.HashMap;
import java.util.Map;

public class EmployeeDataLookup2 {
    // A map storing relation between employee ID and name.
    private Map<Long, String> employeeIdToName;

    public EmployeeDataLookup2() {
        // Create a new EmployeeDataLookup and initialize
        // it with employee names and IDs.
        employeeIdToName = new HashMap<Long, String>();
        addEmployee(301, "John Doe");
        addEmployee(302, "Mary Poppins");
        addEmployee(303, "Andy Stevens");
    }

    public void addEmployee(long employeeId, String employeeName) {
        employeeIdToName.put(employeeId, employeeName);
    }

    // This class is very complicated and has many other methods...

    // Lookup method for finding employee name for given employee ID.
    public String findEmployeeName(int employeeId) {
        return employeeIdToName.get(employeeId);
    }

    public static void main(String[] args) {
        // Create a EmployeeDataLookup instance
        EmployeeDataLookup employeeLookup = new EmployeeDataLookup();
        // Find the name of an employee with ID = 301
        String employeeName = employeeLookup.findEmployeeName(301);
        System.out.print("Employee 301 : " + employeeName);
    }
}


    这段改变导致了一个错误,你能发现吗?当您运行main方法的时候你会发现,该员工的ID=301的值是“null”,哈!

    如果没有发现个问题(或者懒得去尝试)我给你一个提示是去检查25行和26行,如果你能发现它,我们尝试想一下现实生活中的class有1000+的代码和不确定的要改变的Map,由于我们没有编译错误,我们就像大海捞针一样找它,这为什么产生这个bug。

    这个问题是在引入了泛型,可能为了向后兼容,一些方法在Collection and Map interface 并没有修改和仍然没有进行类型检查。其中一个我们发现的方法就是Map.get(Object)导致我们上面的错误。经过“简单修改”后我们仍然用Interger keys去访问包含了Long类型的Map,所以我们即使是有301的employee仍然get返回null,而且由于缺乏类型检查并没有警告......

    那么我们能得到上面教训?要谨慎关于基本情况,甚至类型检查。记住那些访问方法在Sets,Lists和Maps可能伤害你,最大的痛苦是通过这种方式产生的bug很被人识别,有时候甚至十几人对着代码都难找出它。有一个办法可以找到他们——如果你正在使用静态代码分析工具,大部分这样的bug都可以很容易被识别(如:findBUGs)。
   
分享到:
评论

相关推荐

    java集合知识-map、set等

    Set接口中的方法和Collection一致。 |--HashSet: 内部数据结构是哈希表 ,是不同步的。 如何保证该集合的元素唯一性呢? 是通过对象的hashCode和equals方法来完成对象唯一性的。 如果对象的hashCode值不同,...

    java面试宝典

    68、java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类? 17 69、文件读写的基本类 17 70、多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么? 17 71、启动一个...

    java笔记.docx

    Java中的泛型可以让代码更加通用和类型安全。 Java中的注解可以让开发人员添加元数据和标记代码。 Java中的集合类是用于处理数据的集合的框架,包括List、Set和Map等。 Java中的文件处理可以使用File类和IO流进行...

    Java面试八股文.zip

    1. 准备篇 1.1 Java面试概述 1.2 面试流程和注意事项 1.3 自我介绍及项目介绍 1.4常见面试问题 2....2.1 Redis简介和特点 ...2.2 Redis数据类型及其应用 ...2.4 Redis高级特性和集群 ...7.2 List、Set和Map

    Kotlin 语言文档

    类型安全的构建器 113 参考 119 关键字与操作符 119 Grammar 123 Notation 123 Semicolons 123 Syntax 123 Lexical structure 130 兼容性 132 Java 互操作 135 在 Kotlin 中调用 Java 代码 135 Java 中调用 Kotlin ...

    Java 基础面试题

    24. 手写单例模式中的懒汉式和饿汉 25. transient 这个关键字是干啥的 26. 什么是一致性hash算法 27. 构造方法链 28. 谈谈你对线程调度的理解 29. JDK动态代理和CGLIB动态代理 30. 反射机制以及反射的方式 31...

    超级有影响力霸气的Java面试题大全文档

    引用类型和原始类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null,而原始...

    Java基础语法面试题.docx

    集合框架:涵盖Java中的List、Set、Map等集合类型,以及它们的特性和用法。 线程和并发:涵盖多线程编程、线程同步、线程安全等相关概念。 IO操作:解释如何进行文件读写、输入输出流、序列化等操作。 Java虚拟机...

    Java面试技术面知识扩展包第一弹

    3. 集合框架:面试官可能会考察您对Java集合框架的理解和使用,包括List、Set、Map等不同类型的集合接口和对应的实现类,以及它们的特点和适用场景。 4. 多线程:面试官可能会提问关于多线程编程的问题,如线程的...

    2023Java高频面试题

    Java集合框架:常用的List、Set、Map等集合类及其实现方式、使用场景、遍历方法等。 异常处理:Java中的异常类型、异常处理机制、如何自定义异常等。 IO流:Java中常用的文件读写、序列化和反序列化等操作。 多线程...

    typedpy:类型安全,严格的Python。 与标准Python搭配良好

    Typedpy-适用于Python的严格类型系统typedpy是用于类型安全,严格的Python结构的库。 它支持Python 3.6+。特征全功能,复杂的,基于类的类型系统支持JSON模式draft4功能,包括将模式映射到代码和将代码映射到模式...

    STL 标准模板库简介

    从根本上说,STL是一些“容器”的集合,这些“容器”有list, vector,set,map等,STL也是算法和其它一些组件的集合。 这里的“容器”和算法的集合指的是世界上很多聪明人很多年的杰作。是C++标准库的一个重要组成...

    STL学习总结

    从根本上说,STL是一些“容器”的集合,这些“容器”有list, vector,set,map等,STL也是算法和其它一些组件的集合。这里的“容器”和算法的集合指的是世界上很多聪明人很多年的杰作。是C++标准库的一个重要组成...

    java 面试题 总结

    引用类型和原始类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null,而原始...

    Java开发常见问题总结.docx

    根据需求选择合适的集合类型(List, Set, Map等)。 对于并发环境,使用线程安全的集合类如ConcurrentHashMap、CopyOnWriteArrayList等。 避免在循环中修改集合,可能导致ConcurrentModificationException。 异常...

    JAVA的教程.txt

    JAVA的教程涵盖多个方面,从基础知识到高级编程都有详细的讲解。以下是一些主要的学习内容: ... JAVA集合框架与泛型:JAVA的集合框架提供了丰富的数据结构,如List、Set、Map等。你需要学习如何使用这些数据

    C++大学教程,一本适合初学者的入门教材(part2)

    11.4.4 类型安全的I/0 11.5 成员函数read、gcount和write的无格式输人/输出 11.6 流操纵算子 11.6.1 整数流的基数:流操纵算子dec、oct、hex和setbase 11.6.2 设置浮点数精度(Precision、setprecision) ...

    JAVA面试题最全集

    9.Jsp和Servlet中的请求转发分别如何实现。 三、J2EE相关知识 1.介绍J2EE、J2SE、J2SE的区别。 2.J2EE是一种技术还是一种平台,他提供了那些技术。 3.什么是Application Server,它有什么功能和优点。 4.简单...

    写给大忙人看的JAVA SE 8

    2.3 filter、map和flatMap方法 25 2.4 提取子流和组合流 26 2.5 有状态的转换 27 2.6 简单的聚合方法 28 2.7 Optional类型 29 2.7.1 使用Optional值 29 2.7.2 创建可选值 30 2.7.3 使用flatMap来组合可选值函数 31 ...

    springmybatis

    其实还有更简单的方法,而且是更好的方法,使用合理描述参数和SQL语句返回值的接口(比如IUserOperation.class),这样现在就可以至此那个更简单,更安全的代码,没有容易发生的字符串文字和转换的错误.下面是详细...

Global site tag (gtag.js) - Google Analytics