那一年,你定义了一个接口:
public interface WtfService {
public void process(WtfDto dto);
}
为了良好的扩展性,你定义了一个扩展字段,Map<String, String>类型,并且在文档里强调了“key和value都是String类型”:
public class WtfDto implements Serializable {
//other fields
private Map<String, String> extInfo;
public Map<String, String> getExtInfo() {
return extInfo;
}
public void setExtInfo(Map<String, String> extInfo) {
this.extInfo = extInfo;
}
}
然后实现这个接口:
public class WtfServiceImpl implements WtfService {
public void process(WtfDto dto) {
Map<String, String> extInfo = dto.getExtInfo();
for (Entry<String, String> entry : extInfo.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
System.out.println(key + "=" + value);
}
}
}
测试
@Test
public void normal() {
WtfService service = new WtfServiceImpl();
WtfDto dto = new WtfDto();
Map<String, String> extInfo = new HashMap<String, String>();
extInfo.put("name", "Kobe");
dto.setExtInfo(extInfo);
service.process(dto);
}
一切正常。世界看起来是那么完美。
直到某一天,你看到这样的一个报错:
java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.String
at com.sample.WtfServiceImpl.process(WtfServiceImpl.java:40)
你百思不得期解:
明明是Map<String, String>类型,怎么会有Double?
难道调用方还能传一个Double过来?
自己传一个Double看看:
@Test
public void error() {
WtfService service = new WtfServiceImpl();
WtfDto dto = new WtfDto();
Map<String, Object> extInfo = new HashMap<String, Object>();
extInfo.put("name", 10.999);
dto.setExtInfo(extInfo); //编译不通过
service.process(dto);
}
编译不通过。
那Double到底是怎么传过来的?
真相是:
@Test
public void warning() {
WtfService service = new WtfServiceImpl();
WtfDto dto = new WtfDto();
//Map<String, Object> extInfo = new HashMap<String, Object>();
Map extInfo = new HashMap(); //eclipse在这一行会有warning提示
extInfo.put("name", 10.99);
dto.setExtInfo(extInfo);
service.process(dto);
}
}
对于没有代码洁癖直接忽视waring或者压根就不懂得泛型的猪队友,他就那么自然而然的写出了上面的代码。
虽然有warning,但毕竟编译通过了。
于是你的服务就理所当然的报错了。
你体会到这个世界的残酷了。
你应该像王叔叔那样,定义一个key-value的类:
public class MatchVariable implements Serializable {
private String key;
private String value;
//getter/setter
}
然后把接口的参数类改成这样:
public class WtfDto implements Serializable {
//...other fields
// private Map<String, String> extInfo;
//
// public Map<String, String> getExtInfo() {
// return extInfo;
// }
//
// public void setExtInfo(Map<String, String> extInfo) {
// this.extInfo = extInfo;
// }
private List<MatchVariable> extInfoList;
public List<MatchVariable> getExtInfoList() {
return extInfoList;
}
//根据Effective java这本书的建议,你不应该直接提供setExtInfoList这样的方法
// public void setExtInfoList(List<MatchVariable> extInfoList) {
// this.extInfoList = extInfoList;
// }
public void addExtInfo(String key, String value) {
if (extInfoList == null) {
extInfoList = new ArrayList<MatchVariable>();
}
extInfo.add(new MatchVariable(key, value));
}
}
猪队友猫队友再也传不了其他类型的参数给你了。
分享到:
相关推荐
72、当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法? 18 73、线程的基本概念、线程的基本状态以及状态之间的关系 18 74、sleep() 和 wait() 有什么区别? 18 75、socket通信...
2)如果数据文件已经被分析家等软件占用导致无法打开时,将自动复制一份该文件,并从该备份文件中读取数据. 3)程序将自动补充数据,即如果目标表不存在,则建立并添加数据,如果目标表已存在,则判断表中每只证券的最新 ...
但是路由器的物理端口只应该可以分配一个IP地址,那怎样来区分不同网段了?这就可以在这个物理端口下,创建两个子接口---逻辑接口实现。 比如逻辑接口F0/0.1就分配IP地址192.168.1.1/25,用于销售部,而F0/0.2就...
在串行接口模式下,数据通过一个或多个数据线(通常为串行数据线)进行传输,而控制信号则通过另外几条线(如串行时钟、片选等)来实现。这种模式下,数据的发送和接收是分时进行的,即在串行时钟的控制下,数据位逐...
单板机是指将计算机系统的各个组成部分如处理器、内存、I/O接口等集成在一个电路板上的一种微型计算机。与单片机相比,单板机通常具有更强的处理能力和更多的外部接口,适用于更复杂的应用场景。虽然单板机也追求...
比如说,你编写了一个你希望其他人调用的函数。你的函数可能因为这样或那样的原因而运行失败,你必须向函数的调用者说明它已经运行失败。 若要指明函数运行失败,你只需要设定线程的最后的错误代码,然后让你的函数...
一个接口定义一个协定。实现接口的类或结构必须遵守其协定。接口可以从多个基接口继承,而类或结构可以实现多个接口。接口可以包含方法、属性、事件和索引器。接口本身不提供它所定义的成员的实现。接口只指定实现该...
- **描述**:当一个接口太大时,需要将它分割成一些更小的接口,而使用该接口的客户端则仅需知道与之相关的那部分接口。 - **优点**:降低了类之间的耦合度,使得设计更加符合实际、清晰、易懂。 5. **迪米特法则...
在1993年7月发表的Windows NT是第一个支持Intel 386、486和Pentium微处理器32位保护模式的Windows版本。Windows NT提供32位平坦寻址,并使用32位的指令集。(本章后面我会谈到一些寻址空间的问题)。Windows NT还可以...
* 编程接口:USB 2.0 协议提供了一个编程接口,允许开发者编写 USB 设备驱动程序 * 设备类别:USB 2.0 协议定义了多种设备类别,例如_hub、function 和_interface * 传输模式:USB 2.0 协议支持四种传输模式:控制...
这里提到的“DX6+98”可能指的是DirectX 6.0或一个类似的环境,加上Windows 98操作系统,因为这两个技术是90年代末和2000年初常见的软硬件平台。 首先,我们来深入了解摩托罗拉代码。摩托罗拉公司是早期的微处理器...
每一个配置都有一个或者多个 接口,它可以视为一个物理通信渠道 ;每一个接口有零个或者多个端点,它可以是数据提供者或者数据消费者,或者同时具有这两种身份。接口由接口描述符描述,端点由端点描述符描述。并且一...
WSDL,全称为Web Services Description Language(Web服务描述语言),是XML的一个应用,用于定义网络服务的接口。这个“wsdl大合集”显然是一份包含了各种WSDL文档的集合,对于理解、创建和使用Web服务来说,这是一...
JDK8是Java编程语言的一个重要版本,发布于2014年,但随着时间的推移,Oracle会不断对其进行更新和维护,以修复已知问题、增强性能和引入新特性。在2023年,虽然可能已经发布了更高版本的JDK,但标题提到的"2024年...
formatter 该属性定义了 Member.getCaption() 方法返回的动作值,这里需要是一个实现了 mondrian.olap.MemberFormatter 接口的类,用来对 Caption 地值进行格式化。 3.6. Join 对于一个 Hierarchy 来说,有两种...
HTK 是一个广泛使用的语音识别工具包,而 ATK 旨在为开发者提供更加灵活、高效的编程接口。ATK 的最新版本为 1.6,在此版本中引入了多项新特性,包括支持合成以及异步音频输入输出管理等。 #### ATK 的背景与历史 ...
5个目标文件,演示Address EJB的实现 ,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口...
第三章 编写第一个应用程序 .20 3.1 Welcome 程序 .20 3.2 代 码 分 析 .20 3.3 运 行 程 序 .23 .4 添 加 注 释 .25 3.5 小 结 .27 第二部分 C#程序设计基础.28 第四章 数 据 类 型 .28 4.1 值 类 型...