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)); } }
猪队友猫队友再也传不了其他类型的参数给你了。