每次调用方法传入新对象是否为不良实践?含缓存代码场景
咱们一个个来拆解你提出的这两个问题:
问题1:每次调用方法时都传入新对象,是否属于不良实践?
答案是大概率属于不良实践,核心原因是这会造成不必要的内存浪费和GC压力:
- 如果创建的对象是具有复杂初始化逻辑(比如涉及IO、大量计算)的“重量级”对象,每次创建都会消耗额外的CPU资源,完全是无意义的开销;
- 即使是简单的轻量对象,频繁创建未被使用的实例也会让JVM的垃圾收集器频繁工作,影响应用的性能稳定性;
- 当然也有例外:如果你的对象是极其简单的不可变对象(比如只包含几个基本类型字段的DTO),且JVM的逃逸分析能判定这些对象可以被栈分配而非堆分配,那性能影响会很小,但这种情况属于特殊优化,不能作为常规编码习惯。
总的来说,除非有特别明确的理由,否则尽量复用对象、使用对象池或者延迟创建,避免无意义的实例生成。
问题2:静态Map缓存实例+每次传入new MyCall()的场景是否属于不良实践?
这不仅是不良实践,还存在逻辑错误和性能问题的双重问题,咱们来拆解下:
- 逻辑完全失效的缓存:你看这段代码的逻辑:
每次调用都会把新创建的static <A extends BaseCall> getQuery(String hash, A obj) { BaseCall call = mCalls.get(hash); if (call == null) { call = obj; } mCalls.put(hash, obj); // 这里不管缓存有没有,都会把新传入的obj存进去 }new MyCall()覆盖到Map里,之前缓存的实例直接变成垃圾,缓存完全没起到复用的作用,反而平白多了每次创建新对象的开销。 - 不必要的对象创建:不管缓存里有没有对应hash的实例,你每次调用都要
new MyCall(),哪怕这个实例刚被创建就被覆盖,完全是资源浪费; - 线程安全隐患:静态Map如果用的是普通
HashMap,多线程并发调用时会出现数据不一致甚至死循环的问题。
改进建议:
- 先修复缓存逻辑:只有当缓存不存在时,才把新实例存入Map,把
mCalls.put(hash, obj)移到if (call == null)的代码块里; - 延迟实例化:把方法参数改成
Supplier<A>,这样只有当缓存不存在时才执行实例创建逻辑,避免不必要的对象生成,比如:
调用的时候就改成static <A extends BaseCall> A getQuery(String hash, Supplier<A> supplier) { BaseCall call = mCalls.get(hash); if (call == null) { call = supplier.get(); mCalls.put(hash, call); } return (A) call; }getQuery("xxx", MyCall::new),这样只有缓存没命中时才会创建新实例; - 保证线程安全:把静态Map换成
ConcurrentHashMap,避免多线程下的并发问题。
内容的提问来源于stack exchange,提问作者bycfly
相关产品推荐
相关产品推荐

