在一个java语言群里面,有人抛了这么一段代码出来,问题是出现了下下图中的warning,问有什么好的方法消除java
这种强转都是由于类型链条断掉了,写入的时候擦除了类型,读出来的时候也就只能强转了,那个instanceof 其实并无帮到什么忙,无外乎把A异常变成了B异常。编程
最简单的解决方法也很是直观,就是加上 @SuppressWarnings("unchecked")。segmentfault
这里先不谈用其余的方法相对优雅的除掉这个warning,而是看看这段代码自己的问题。编码
这是一个context,这种模式就是一个数据容器,啥都能装,经过编码的人来保证类型匹配,进去擦除类型,出来补上类型,能不能弄对,全看人。spa
这种模式相似于在其余的语言里面就拿个容器类型就开始编程,忽略一切的type信息。设计
1. context装进去的是有类型化的对象,出来就没有了,设计上讲究封装性,封装基本的就要保证对称,那么context抹除掉的东西,就应该由他来补上。3d
2. 因为他没有补上,因此全部使用的地方本身来补充,代码其实会产生不少冗余,考虑到他是一个context,那么实际上其余地方必定还有不少处有相似的代码日志
3. 这里模拟的实际上是一个computeIfAbsent的逻辑,若是没有对象就补一个默认值,而后set进去,借用了isEmpty来婉转的表达容器里面没有这个元素。这里做者应当对java容器上的computeIfAbsent一类的方法不熟悉,由于兜兜转转作的就是这个事情。code
4. 因为没有用computeIfAbsent,本身的实现中,不管对象是否存在于context中,都会new一个HashMap出来,这在多数状况下,都是一个浪费。对象
5. 更不要说,当他发现类型不匹配的时候,仅仅打了一行日志。 元素没有推动去,程序也不知道,只有日志知道了。
1. context作对称设计,出来的时候就把类型转换好,不要让调用者本身来作。 这样抑制告警就在一处便可。
2. 实现computeIfAbsent的逻辑封装,有就返回,没有就插入一个对象,而后返回对象。 对象的建立是按需的。
context的包装类样子以下
public static class SomeClass { Map<String, Object> context = new HashMap<>(); @SuppressWarnings("unchecked") public <T> T computeIfAbsent(String key, Supplier<T> defaultGen) { return (T) context.computeIfAbsent(key, k -> defaultGen.get()); } }
使用者样子以下
public static class Usage { public void test() { SomeClass workingClass = new SomeClass(); Supplier<Integer> wantToAppendItem = () -> 2; Map<String, Supplier<Integer>> element = workingClass.computeIfAbsent("my-key", HashMap::new); element.put("level2-key", wantToAppendItem); Supplier<String> wantToAppendStringItem = () -> "good"; workingClass.computeIfAbsent("my-str-key", HashMap::new).put("level2-str-key", wantToAppendStringItem); } }
是否是会好一点,业务也更聚焦一点,从鸡毛蒜皮的重复中解脱出来了?