web-dev-qa-db-ja.com

オブジェクトでゲッターを呼び出すか、ローカル変数として保存するか(メモリフットプリント、パフォーマンス)

次のコードでは、listType.getDescription()を2回呼び出します。

_for (ListType listType: this.listTypeManager.getSelectableListTypes())
{
    if (listType.getDescription() != null)
    {
        children.add(new SelectItem( listType.getId() , listType.getDescription()));
    }
}
_

単一の変数を使用するようにコードをリファクタリングする傾向があります。

_for (ListType listType: this.listTypeManager.getSelectableListTypes())
{
    String description = listType.getDescription();

    if (description != null)
    {
        children.add(new SelectItem(listType.getId() ,description));
    }
}
_

私の理解では、JVMは元のコード、特にchildren.add(new SelectItem(listType.getId(), listType.getDescription()));のようなネスト呼び出しに対して何らかの形で最適化されています。

2つのオプションを比較すると、どちらが好ましい方法であり、その理由は何ですか?それは、メモリフットプリント、パフォーマンス、読みやすさ/使いやすさなど、今は頭に浮かばないことです。

後者のコードスニペットが前者よりも有利になるのはいつですか。つまり、listType.getDescription()のように、一時ローカル変数を使用することがより望ましい場合、(おおよその)数のlistType.getDescription()呼び出しがありますか。 thisオブジェクトを格納するには、常にいくつかのスタック操作が必要ですか?

32
Kawu

私はほとんどの場合、ローカル変数ソリューションを好みます。

メモリフットプリント

1つのローカル変数のコストは4バイトまたは8バイトです。これは参照であり、再帰はありませんので、無視しましょう。

パフォーマンス

これが単純なゲッターの場合、JVMはそれ自体をメモ化できるため、違いはありません。最適化できない高価な通話の場合は、手動でメモ化すると高速になります。

読みやすさ

[〜#〜] dry [〜#〜] の原則に従ってください。あなたの場合、ローカル変数名はメソッド呼び出しと同じくらい文字単位であるため、ほとんど問題になりませんが、もっと複雑な場合は、必要がないので読みやすくなります 10の違いを探す 2つの式の間。それらが同じであることがわかっている場合は、ローカル変数を使用して明確にします。

正しさ

SelectItemnullsを受け入れず、プログラムがマルチスレッドであると想像してください。その間にlistType.getDescription()の値が変わる可能性があり、乾杯します。

デバッグ

興味深い値を含むローカル変数を持つことは利点です。


ローカル変数を省略して勝つ唯一のことは、1行を節約することです。だから私はそれが本当に問題ではない場合にのみそれをします:

  • 非常に短い表現
  • 可能な同時変更はありません
  • シンプルなプライベートファイナルゲッター
33
maaartinus

ここで最も重要なことであるコードの可読性保守性が改善されるので、2番目の方法は間違いなく優れていると思います。この種のマイクロ最適化は、ミリ秒ごとに重要なアプリケーションを作成しない限り、実際には何の役にも立ちません。

7
Petr Mensik

どちらが好ましいかわかりません。私がwould好むのは、特にパフォーマンスの向上がごくわずかである場合に、パフォーマンスの高いコードよりも明確に読み取り可能なコードです。この場合、目立った違いはほとんどないと思います(特に、JVMの最適化とコード書き換え機能を考えると)

2
Brian Agnew

命令型言語のコンテキストでは、関数呼び出しによって返される値をメモ化することはできません( http://en.m.wikipedia.org/wiki/Memoization を参照)。これは、関数が副作用はありません。したがって、あなたの戦略は、関数呼び出しによって返される値への参照を格納するために一時変数を割り当てることを犠牲にして、実際に関数呼び出しを回避します。少し効率的であることに加えて(関数がループ内で何度も呼び出されない限り、これは実際には問題ではありません)、コードの可読性が向上するため、私はあなたのスタイルを選びます。

1
Tarik

読みやすさのためのローカル変数アプローチに同意します場合のみローカル変数の名前は自己文書化されています。それを「説明」と呼ぶだけでは十分ではありません(どの説明ですか?)。それを「selectableListTypeDescription」と呼ぶと、それが明確になります。 forループ内のインクリメントされた変数には「selectableListType」という名前を付ける必要があります(特に「listTypeManager」に他のListTypeのアクセサーがある場合)。

もう1つの理由は、これがシングルスレッドであるか、リストが不変であるという保証がない場合です。

0
jaywild