6

同じコード行内に複数のメソッド呼び出しやネストされたメソッド呼び出しをパックするとパフォーマンスが向上するかどうかに興味があります。そのため、一部の開発者は、コードを読みにくくするという犠牲を払ってそれを行っています。

例えば

//like
Set<String> jobParamKeySet = jobParams.keySet();
Iterator<String> jobParamItrtr = jobParamKeySet.iterator();

のようにも書ける

//dislike    
Iterator<String> jobParamItrtr = jobParams.keySet().iterator();

個人的には、後者は同じ行で複数の評価を行い、コードを読むのが難しいため嫌いです。そのため、コード行ごとに複数の評価を行うことは絶対に避けようとしています。jobParams.keySet()また、それが a を返し、それが私を悩ませていることも知りSetません。
別の例は次のとおりです。

//dislike
Bar.processParameter(Foo.getParameter());

//like
Parameter param = Foo.getParameter();
Bar.processParameter(param);

前者は、コードのすべての行でシンプルでクリーンな評価を消費するのが好きなので、私は有害でめまいがします。他の人のコードがそのように書かれているのを見ると、ただ嫌いです。

しかし、複数のメソッド呼び出しを同じ行にパックすることには (パフォーマンス) 利点がありますか?

編集: @stemm のおかげで、シングル ライナーのデバッグも難しくなります。

4

7 に答える 7

6

マイクロ最適化はキラーです。表示しているコード参照がインスタンス スコープ (または) メソッド スコープの場合、2 番目のアプローチを使用します。

メソッドのスコープ変数は、メソッドの実行が完了するとすぐに GC の対象になるため、別の変数を宣言しても、スコープが制限され、得られる利点が読みやすくメインテーブル コードになるため、問題ありません。

于 2012-10-09T14:45:09.873 に答える
5

私はこのリストの他のほとんどの人と意見が合わない傾向があります。私は実際、最初の方法がよりクリーンで読みやすいと感じています。

あなたの例では:

//like
Set<String> jobParamKeySet = jobParams.keySet();
Iterator<String> jobParamItrtr = jobParamKeySet.iterator();
Could be also written as

//dislike    
Iterator<String> jobParamItrtr = jobParams.keySet().iterator();

最初の方法(あなたが好きな方法)には、無関係な情報がたくさんあります。たとえば、イテレータインターフェイスの要点は、バッキング実装が存在する場合はそれをループするために使用できる標準インターフェイスを提供することです。したがって、それがキーセットであるという事実は、コード自体には関係ありません。探しているのは、実装されたオブジェクトをループするイテレータだけです。

次に、2番目の実装は実際により多くの情報を提供します。これは、コードがjobParamsの実装を無視し、キーをループするだけであることを示しています。最初のコードでは、最初にjobParamKeySetが(変数として)何であるかをトレースバックして、何を繰り返しているかを把握する必要があります。さらに、jobParamKeySetがスコープ内の他の場所で使用されているかどうか/どこで使用されているかはわかりません。

最後に、最後のコメントとして、2番目の方法では、必要に応じて実装を簡単に切り替えることができます。最初のケースでは、2行を再コーディングする必要があるかもしれません(セットから別のものに変更する場合は最初の変数割り当て)が、2番目のケースでは1行だけを変更する必要があります。

そうは言っても、すべてに限界があります。1行に10個の呼び出しを連鎖させると、読み取りとデバッグが複雑になる可能性があります。ただし、通常は3つまたは4つのレベルが明確です。場合によっては、特に中間変数が数回必要な場合は、明示的に宣言する方が理にかなっています。

2番目の例では:

//dislike
Bar.processParameter(Foo.getParameter());
vs

//like
Parameter param = Foo.getParameter();
Bar.processParameter(param);

実際には、どのパラメーターがによって処理されているかを正確に理解するのは難しいと思いますBar.processParameter(param)param変数のインスタンス化に一致して、それがであることを確認するのに時間がかかりますFoo.getParameter()。最初のケースでは、情報は非常に明確で、非常によく表示されます。つまり、Foo.getParameter()パラメータを処理しています。個人的には、最初のメソッドもエラーが発生しにくいと思いますFoo2.getParamter()。別の行ではなく、同じ呼び出し内にあるときに誤って使用する可能性はほとんどありません。

于 2012-10-09T15:22:16.260 に答える
3

変数の割り当てが 1 つ少なくなりますが、場合によってはコンパイラでさえも最適化できます。私はパフォーマンスのためにそれをしません。それは初期の最適化のようなものです。保守しやすいコードを記述します。

私の場合、次のことがわかります。

Iterator<String> jobParamItrtr = jobParams.keySet().iterator();

以下よりも読みやすい:

Set<String> jobParamKeySet = jobParams.keySet();
Iterator<String> jobParamItrtr = jobParamKeySet.iterator();

しかし、それは個人の好みの問題だと思います。

于 2012-10-09T14:44:58.627 に答える
1

しかし、同じ行に複数のメソッド呼び出しをパックすることには(パフォーマンス上の)利点がありますか?

私はその違いが測定可能であるかどうかを真剣に疑っていますが、たとえあったとしても私は考えます

コードを読むのは難しいです。

非常に重要であるということは、言い過ぎではありません。

速度が半分だったとしても、私は最も単純で、最もクリーンで、最も理解しやすいコードを記述します。アプリケーションのプロファイルを作成し、問題があると特定した場合にのみ、最適化を検討します。

ところで:私はより密度の高い連鎖コードを好みますが、好みのものを使用することをお勧めします。

于 2012-10-09T15:13:48.093 に答える
1

余分なローカル変数を省略すると、パフォーマンス上の利点は無視できる可能性があります(ただし、JITはこれを最適化できる場合があります)。

個人的には、何が行われたかが非常に明確で、中間オブジェクトがnullになる可能性が非常に低い場合(最初の「嫌い」の例のように)、コールチェーンを気にしません。複雑になると(式に複数の。が含まれる)、デバッグが非常に簡単になるため、明示的なローカル変数を使用します。

だから私はケースバイケースで私が好むものを決定します:)

于 2012-10-09T15:14:23.080 に答える
1

コードが同じユーザーによって開発されることはありません。私なら二番目の方法を選びます。また、理解しやすく、維持しやすくなります。

また、これは、2 つの異なるチームが異なる場所でコードに取り組んでいる場合にも役立ちます。

他の開発者が最初のオプションを使用した場合、他の開発者が何をしたかを理解するのに 1 時間以上かかることがよくあります。個人的に、私はこの状況を何度も経験しました。

于 2012-10-09T14:48:18.627 に答える
0

人々があまり気にしていないように見える場所a().b().c().dよりも読みにくい場所はどこにあるのかわかりません。a.b.c.d(私はそれを分割しますが.)すべてが1行にあるのが気に入らない場合は、

a()
 .b()
 .c()
 .d

(私もそれは好きではありません。) 私はいくつかの追加の変数を使用して、分割することを好みます。これにより、デバッグが容易になります。

パフォーマンスが重要な場合 (そうあるべきです)、最初に理解しておくべきことは、細かいことを気にしないことです。追加のローカル変数を追加するのに少しでもコストがかかる場合は、問題が発生する前に残りのコードを完全に削除する必要があります。

于 2012-10-09T19:25:26.920 に答える