
getWorkingMonth() 方法在首次调用时返回正确结果,但第二次调用(如断言中)返回 0,根本原因是该方法直接修改了类的实例字段 currentSaving,破坏了对象状态的一致性;应改用局部变量模拟计算过程。
如何修复因状态修改导致的断言失败问题:`getworkingmonth()` 方法在首次调用时返回正确结果,但第二次调用(如断言中)返回 0,根本原因是该方法直接修改了类的实例字段 `currentsaving`,破坏了对象状态的一致性;应改用局部变量模拟计算过程。
在编写金融计算类(如养老金规划器 PensionPlanner)时,查询类行为的方法(如 getWorkingMonth())应当是纯函数式的——即不改变对象内部状态,仅基于当前输入和只读字段进行计算。而原实现中:
public int getWorkingMonth() {
double Saving = monthlySaving * (annualSalary / 12);
int months = 0;
while (currentSaving <p>每次调用都会持续累加 currentSaving,导致:</p>
- 第一次调用(System.out.println(...))从初始值 0 开始模拟,最终返回 368;
- 第二次调用(assert 中)时,currentSaving 已被更新为 ≥ 240000,循环条件立即不成立,months 保持 0,断言失败。
✅ 正确做法是隔离计算逻辑与状态变更:使用局部变量 curr 复制初始 currentSaving 值,并在循环中仅操作该副本:
public int getWorkingMonth() {
double monthlyContribution = monthlySaving * (annualSalary / 12);
double curr = currentSaving; // ✅ 局部副本,保护原始状态
int months = 0;
while (curr <blockquote>
<p>? <strong>额外建议</strong>: </p>
<ul>
<li>将 monthlyContribution 提前计算并命名,提升可读性与复用性; </li>
<li>考虑边界情况:若 pensionTarget ≤ currentSaving,应直接返回 0(当前逻辑已自然支持); </li>
<li>若需持久化计算结果(如缓存),应显式提供 simulate() 或 calculateMonths() 等非 getter 命名方法,避免语义混淆; </li>
<li>启用 JVM 断言(-ea 参数)时,确保测试逻辑不依赖副作用,否则结果不可预测。</li>
</ul>
</blockquote><p>遵循“getter 不应有副作用”的设计原则,不仅能解决当前断言失败问题,更能提升代码可测试性、线程安全性与长期可维护性。</p>










