public static void main(String[] args)
{
LazyValue<Integer> ultimateQuestionOfLife = new LazyValue<Integer>()
{
@Override
protected Integer update()
{
return findNewUltimateAnswer();
}
};
//
ultimateQuestionOfLife.invalidate();
// update()
System. out .println( "Answer is: " + ultimateQuestionOfLife.get());
// update() ,
System. out .println( "Answer is: " + ultimateQuestionOfLife.get());
//
ultimateQuestionOfLife.invalidate();
// update()
System. out .println( "Answer is: " + ultimateQuestionOfLife.get());
}
小さなエチュードプログラムでのテストは成功しましたが、このクラスを使用する大規模な作業プロジェクトでは、スタックオーバーフローエラーが発生し始めました。他の情報源なしで値が互いに更新されました。 最後の瞬間ではなく、毎回再計算が行われた場合、このエラーは発生しません。
private static LazyValue<Integer> lv1 = new LazyValue<Integer>()
{
@Override
protected Integer update()
{
return lv2.get(); //
}
};
private static LazyValue<Integer> lv2 = new LazyValue<Integer>()
{
@Override
protected Integer update()
{
return lv1.get() + 1;
}
};
public static void main(String[] args)
{
// StackOverflowException
System. out .println(lv2.get());
}
非常に迅速に、再帰を防ぐためにコードに松葉杖を挿入するのにうんざりしていたので、キャッシュクラスに再帰検出器を埋め込み、動作し、スタックを再帰の「インスティゲーター」に戻し、デフォルト値を生成することを決定しました。 StackOverflowException。 実装は次のとおりです。
private static LazyValue<Integer> lv1 = new RSLazyValue<Integer>()
{
@Override
protected Integer update()
{
return lv2.get();
}
@Override
protected Integer getDefault()
{
return 0;
}
};
private static LazyValue<Integer> lv2 = new RSLazyValue<Integer>()
{
@Override
protected Integer update()
{
return lv1.get() + 1;
}
@Override
protected Integer getDefault()
{
return 10;
}
};
public static void main(String[] args)
{
// 10
System. out .println(lv2.get());
}
すべての魔法はRSLazyValueクラスにあります(RSは再帰セーフです)。 更新が開始されると、特別なフラグが設定され、更新の最後に削除されます。 同じ関数に入って、更新が進行中の場合、再帰を末尾でキャッチし、それを使って何かをする必要があります。 額の解決策は、すぐにデフォルト値を返すことです。 ただし、処理された値は最初の関数呼び出しに戻り、外部からのみ処理された独自の値に基づいて値を返すため、これは最良の方法ではありません。 最も適切なオプションは、同じ関数の以前の「hypostasis」に呼び出しスタックを巻き戻す例外をスローし、そこからデフォルト値を返すことです。 仕組みは次のとおりです。
public ValueType get()
{
// update() ,
// , get()
// update()
if (updateInProgress)
throw new RecursionDetectedException( this );
// update()
if (isInvalid)
{
// update()
updateInProgress = true ;
try
{
//
value = update();
// isInvalid false update()
//
isInvalid = false ;
}
catch (RecursionDetectedException e)
{
if (e.getRecursionStarter() != this )
throw e; // ,
else
return getDefault(); // -
}
finally
{
// , get()
updateInProgress = false ;
}
}
return value;
}
このソリューションにより、大規模なプロジェクトで多くの時間を節約できました。 プログラマーとプロセッサーの両方の時間。 パフォーマンスの節約は、データがオンデマンドでのみ計算され、リクエストが発生しなかった場合、誰でもこのデータが必要であり、ユーザーがそれを読み取る必要がないことです。 これらの2つの小さなクラスがあなたの時間を節約することを願っています。 私は建設的な批判と「何も機能しない」場合に喜んでいるでしょう。
完全なクラスコード:
LazyValue.java
RSLazyValue.java