5

特にクラスのメソッド/関数内で、無数の(まあ、数え切れないほど多くの)機会に、void-return関数内で一連の操作を実行したい状況にありましたが、if(condition met). ほとんどの場合、(コードが機能すると仮定して)ブロックelseに戻るだけでステートメントを完全に削除できることがわかります。if

意味をなさない場合に備えて、具体的な例を次に示します。

else ステートメントを使用する (教師がどのように表示するか)

    private void ifThisDoThat(params){
        if(dependenciesNotMet) return;
        else{
            ////DO STUFF HERE...
        }
    }

なし(より倹約的)

    private void ifThisDoThat(params){
        if(dependenciesNotMet) return;
        //Assuming the above does not execute, DO STUFF HERE...
    }

ステートメントを削除することはelse、最適化が行われたとしても、マイクロ最適化として分類されると考えていますが、それでも私は自分自身の啓蒙を求めるだろうと考えました.

最後に:

を使用してブロックreturnを削除する利点はありますか?else

elseステートメントを使用すると、コンパイラは余分な作業を行いますか?

else(エラーの場合、またはその他の理由で)を常に使用する理由はありますか?

4

5 に答える 5

5

それは誤った最適化です。コンパイラは実際にはコンパイルに時間がかかり、途中から戻ってくる可能性があり、最適化コンパイラは両方の形式に対して本質的に同じ実行可能コードを生成します。

スタイルに関しては、あるスタイルが良い場合もあれば、別のスタイルが良い場合もあります。return-immediately スタイルの危険性は次のとおりです。

  1. メソッドの最後に一般的な終了/クリーンアップ ロジックがある場合、それは見逃されます。大規模なメソッドでは、ロジックがそこにあることを忘れがちです。大規模なメソッドでは、そのようなロジックを編集して、以前はロジックがなかったメソッドにするのはかなり簡単です。この種のバグは見つけるのが難しい場合があります。
  2. メソッドの下部に「クリーンアップ」ロジックを含めるオプションが本質的に排除されるため、個々のifレグでロジックが急増し、標準の if/then/else よりも混乱が生じる可能性があります。
  3. これは、優れた「構造化プログラミング」の実践に反します。

そうは言っても、途中から戻るスタイルがより良い選択である場合があります。

  1. 複数の順次ifステートメントがあり、それぞれが単純な本体を持ち、それぞれが return で終了できる場合。
  2. 「速い出口」が自然でかなり明白な非常に簡単な方法の場合。
  3. 「高速終了」の場合 (たとえば、一部のデータ項目が nil であるため) は、長いメソッドの最上部のすぐ近くにあります。
于 2013-04-01T17:50:21.100 に答える
2

1 つの簡単なテストで、その答えを得ることができます。あなたが持っていると想像してください:

public void x(int i){
    if(i == 0){
        System.out.println("zero");
        return;
    }
    System.out.println("not zero");
}

public void y(int i){
    if(i == 0){
        System.out.println("zero");
        return;
    }
    else {
        System.out.println("not zero");
    }
}

コンパイルされたコードを見てみると ( を使用javap -v <class>):

xのコード:

  public void x(int);
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: iload_1       
         1: ifne          13
         4: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
         7: ldc           #22                 // String zero
         9: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        12: return        
        13: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
        16: ldc           #30                 // String not zero
        18: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        21: return        
      LineNumberTable:
        line 6: 0
        line 7: 4
        line 8: 12
        line 10: 13
        line 11: 21
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      22     0  this   Lpt/kash/Test;
               0      22     1     i   I
      StackMapTable: number_of_entries = 1
           frame_type = 13 /* same */

yのコード:

  public void y(int);
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
         0: iload_1       
         1: ifne          13
         4: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
         7: ldc           #22                 // String zero
         9: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        12: return        
        13: getstatic     #16                 // Field java/lang/System.out:Ljava/io/PrintStream;
        16: ldc           #30                 // String not zero
        18: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        21: return        
      LineNumberTable:
        line 14: 0
        line 15: 4
        line 16: 12
        line 19: 13
        line 21: 21
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      22     0  this   Lpt/kash/Test;
               0      22     1     i   I
      StackMapTable: number_of_entries = 1
           frame_type = 13 /* same */

違いは... ありません。コンパイラは、コードを最適化するのに十分スマートです。

つまり、結論は (前述のとおり): 読みやすさとシンプルさを最適化することです。

于 2013-04-01T17:47:21.947 に答える
1

スタイルの問題です。生成されたコードには影響しません。最適化ではありません。

個人的には、コードが読みやすくなると思うので、可能な場合は常に return を使用します。else ステートメントの末尾を検索する必要はありません。

于 2013-04-01T17:35:26.247 に答える
0

14: goto 25プログラムを javap でテストすると、2番目のケースの JUMP 命令を除いてほとんど違いが見られません。

else ステートメントで実行するものが何もない場合、else を追加する理由がわかりません。ただし、ログなどを行うために使用したい場合があります。

public class Test {
    public static void main(String[] s){
        if(testMethod()){
            System.out.println("in if");
        }
        System.out.println("in else");      
    }   
    static boolean testMethod(){
        return false;
    }
}

結果として

    public static void main(java.lang.String[]);
      Code:
       Stack=2, Locals=1, Args_size=1
       0:   invokestatic    #16; //Method testMethod:()Z
       3:   ifeq    14
       6:   getstatic       #20; //Field java/lang/System.out:Ljava/io/PrintStream;
       9:   ldc     #26; //String in if
       11:  invokevirtual   #28; //Method java/io/PrintStream.println:
                            (Ljava/lang/String;)V
       14:  getstatic       #20; //Field java/lang/System.out:Ljava/io/PrintStream;
       17:  ldc     #34; //String in else
       19:  invokevirtual   #28; 
      //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   22:  return

public class Test {
    public static void main(String[] s){
        if(testMethod()){
            System.out.println("in if");
        }else{
            System.out.println("in else");
        }
    }   
    static boolean testMethod(){
        return false;
    }
}

public static void main(java.lang.String[]);
  Code:
   Stack=2, Locals=1, Args_size=1
   0:   invokestatic    #16; //Method testMethod:()Z
   3:   ifeq    17
   6:   getstatic       #20; //Field java/lang/System.out:Ljava/io/PrintStream;
   9:   ldc     #26; //String in if
   11:  invokevirtual   #28; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   14:  goto    25
   17:  getstatic       #20; //Field java/lang/System.out:Ljava/io/PrintStream;
   20:  ldc     #34; //String in else
   22:  invokevirtual   #28; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   25:  return
于 2013-04-01T17:55:18.680 に答える
0

実行に違いはありません。とにかく同じものに最適化されますが、読みやすさのためにこれをお勧めします(1つの戻り原則を使用):

private void ifThisDoThat(params){
    if(!dependenciesNotMet) { // would be nicer to change this to if(dependenciesNotMet)
        ////DO STUFF HERE...
    }
}
于 2013-04-01T17:49:22.403 に答える